Code

Updated image
[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             if(isset($attr['FAIstate'])){
79               $buffer['FAIstate'] = $attr['FAIstate'][0];
80             }else{
81               $buffer['FAIstate'] = "branch"; 
82             }
83           }
85           /* In detailed mode are some additonal informations visible */
86           if($detailed){
88             /* Create list of parents */
89             if(isset($res[$name])){
90               $buffer = $res[$name];
91               $buffer['parents'][] = $res[$name]['dn'];
92             }else{
93               $buffer['parents'] = array();
94             }
96             /* Append objectClass to resulsts */
97             foreach($attributes as $val){
98               if(isset($attr[$val])){
99                 $buffer[$val] = $attr[$val];
100               }
101             }
102             unset($buffer['objectClass']['count']);
103           }
105           /* Add this object to our list */
106           $buffer['dn']           = $attr['dn'];
107           $res[$name] = $buffer;
108         }
109       }
110     }
111     return($res);
112   }
115   /* Return all relevant FAI departments */
116   static function get_FAI_departments($suffix = "")
117   {
118     $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
119     $tmp = array();
120     if(preg_match("/^,/",$suffix)){
121       $suffix = preg_replace("/^,/","",$suffix);
122     }
123     foreach($arr as $name){
124       if(empty($suffix)){
125         $tmp[$name] = "ou=".$name;
126       }else{
127         $tmp[$name] = "ou=".$name.",".$suffix;
128       }
129     }
130     return($tmp);
131   }
134   /* Return all releases within the given base */
135   static function get_all_releases_from_base($dn,$appendedName=false)
136   {
137     global $config;
139     if(!preg_match("/".normalizePreg(get_ou('faiou'))."/",$dn)){
140       $base = get_ou('faiou').$dn;
141     }else{
142       $base = $dn;
143     }
144     $res = array();  
146     $ldap = $config->get_ldap_link();
147     $ldap->cd($base);
148     $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
149     while($attrs = $ldap->fetch()){
150       if($appendedName){
151         $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".normalizePreg(get_ou('faiou')).".*$/","",$attrs['dn']));
152       }else{
153         $res[$attrs['dn']] = $attrs['ou'][0];
154       }
155     }
156     return($res);
157   }
160   /* Add this object to list of objects, that must be checked for release saving */
161   static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
162   {
163     /* Get ldap object */  
164     global $config;
165     $addObj['Current_DN'] = $Current_DN;
166     $addObj['objectAttrs']= $objectAttrs;
167     $addObj['removed']    = $removed;
168     $addObj['diff']       = TRUE;
170     if(!$removed){
171       $ldap = $config->get_ldap_link();
172       $ldap->cd($config->current['BASE']);
174       /* Get some basic informations */
175       $parent_obj   = FAI::get_parent_release_object($Current_DN);
176       if(!empty($parent_obj)){
177         $ldap->cat($parent_obj,array("*"));
178         $attrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
180         if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
181           $addObj['diff'] = FALSE;
182         }
183       } 
184     }else{
186       /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
187           we have to remove this name from all profiles in this release.
188       */
189       $ldap = $config->get_ldap_link();
190       $ldap->cd($config->current['BASE']);
191       $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
193       /* Dont't try to modify non FAIclasses  
194        */
195       if(!preg_match("/[^,]+,".normalizePreg(get_ou("faiou"))."/",$obj_dn)){
196         trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);        
197         echo "<br>-->".$Current_DN."<br>";
198         echo "<br>-->".$obj_dn."<br>";
199       }else{
201         /* Get source object and check if it is a base FAIclass
202          */
203         $ldap->cat($obj_dn);
204         $attrs = $ldap->fetch();
205         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
206         if(count(array_intersect($classes,$attrs['objectClass']))){
207           $cn    = $attrs['cn'][0];
209           /* Check if this is the last with this name in the current release.
210               In this case we have to remove the package name 
211               from all profiles in this release.
212            */
213           $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
214               "(&(objectClass=FAIclass)(cn=".$cn."))"); 
216           /* Check if this is the last class with this name.
217            */
218           if(count($classes) == 1){
220             /* Get all FAI Profiles 
221              */
222             $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
223                 "(&(objectClass=FAIprofile)(FAIclass=*))"); 
225             /* Walk though all profiles and remove the source class name
226              */
227             foreach($profiles as $dn){
228               $ldap->cat($dn['dn']);
229               $attrs = $ldap->fetch();
231               $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
233               /* Check if this Profile uses the source class ($cn)
234                */
235               if(preg_match("/".normalizePreg($cn)."/",$attrs['FAIclass'])){
236                 $attrs['FAIclass'] = preg_replace("/[ ]*".normalizePreg($cn)."[ ]*/i"," ",$attrs['FAIclass']);
237                 if(empty($attrs['FAIclass'])){
238                   $attrs['FAIclass'] = array();
239                 }
240                 $ldap->cd($dn['dn']);
241                 $ldap->modify($attrs);
243                 if (!$ldap->success()){
244                   msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
245                 }
246               }
247             }
248           }
249         }
250       }
251     }
255     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
256     $FAI_objects_to_save[$Current_DN] =  $addObj;
257     session::set('FAI_objects_to_save',$FAI_objects_to_save);
258   }
261   /* Detect differences in attribute arrays  */
262   static function array_diff_FAI($ar1,$ar2)
263   {
265     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
266       $ar1['description'] = "";
267     }
268     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
269       $ar2['description'] = "";
270     }
272     if(count($ar1) != count($ar2)) {
273       return (true);
274     }
276     foreach($ar1 as $key1 => $val1){
278       if((is_array($val1)) && (count($val1)==1)){
279         $ar1[$key1] = $val1[0];
280       }
282       if(isset($ar2[$key1])&&  (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
283         $val1 = $val1[0];
284         $ar2[$key1] = $ar2[$key1][0];
285       }
286     }
287     ksort($ar1);
288     ksort($ar2);
289     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
290       return(true);
291     }else{
292       return(false);
293     }
294   }
297   static function arr_diff($ar1,$ar2)
298   {
299     foreach($ar1 as $ak1 => $av1){
300       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
301         return(TRUE);    
302       }elseif(is_array($av1)){
303         $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
304         if($ret) {
305           return(TRUE);
306         }
307       }
308     }
309     return(FALSE);
310   }
315   /* check which objects must be saved, and save them */
316   static function save_release_changes_now()
317   {
318     global $config;
319     /* Variable init*/
320     $to_save = array();
321     
322     $reload_fai_classes = FALSE;
324     /* check which objects must be saved */
325     if(!session::is_set('FAI_objects_to_save')){
326       return;
327     }
328     $FAI_objects_to_save = session::get('FAI_objects_to_save');
329     if(!is_array($FAI_objects_to_save)) {
330       print_a(array(session::get('FAI_objects_to_save')));
331       trigger_error("Can't save FAI objects, no array given.");
332       return;
333     }
334   
335     foreach($FAI_objects_to_save as $Current_DN => $object){
336       if($object['diff']){
337         $sub_name = $Current_DN;
338         while(isset($FAI_objects_to_save[$sub_name])){
339           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
340           unset($FAI_objects_to_save[$sub_name]);
341           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
342         }
343       }
344     }
345     session::set('FAI_objects_to_save',$FAI_objects_to_save);
347     /* Sort list of objects that must be saved, and ensure that 
348        container   objects are safed, before their childs are saved */
349     ksort($to_save);
350     $tmp = array();
351     foreach($to_save as $SubObjects){
352       foreach($SubObjects as $object){
353         $tmp[] = $object;
354       }
355     }
356     $to_save = $tmp;
359     /* Save objects and manage the correct release behavior*/
360     foreach($to_save as $save){
362       $Current_DN = $save['Current_DN'];
363       $removed    = $save['removed'];
364       $objectAttrs= $save['objectAttrs'];
366       /* Get ldap object */ 
367       $ldap = $config->get_ldap_link();
368       $ldap->cd($config->current['BASE']);
370       /* Get some basic informations */
371       $base_release       = FAI::get_release_dn($Current_DN);
372       $sub_releases       = FAI::get_sub_releases_of_this_release($base_release,true);
373       $parent_obj         = FAI::get_parent_release_object($Current_DN);
374       $following_releases = $sub_releases;
376       /* Check if given dn exists or if is a new entry */
377       $ldap->cat($Current_DN);
378       if(!$ldap->count()){
379         $is_new = true;
380       }else{
381         $is_new = false;
382       }
384       /* if parameter removed is true, we have to add FAIstate to the current attrs 
385          FAIstate should end with ...|removed after this operation */  
386       if($removed ){
387         $ldap->cat($Current_DN);
389         /* Get current object, because we must add the FAIstate ...|removed */
390         if((!$ldap->count()) && !empty($parent_obj)){
391           $ldap->cat($parent_obj);
392         }
394         /* Check if we have found a suiteable object */ 
395         if(!$ldap->count()){
396           echo "Error can't remove this object ".$Current_DN;
397           return;
398         }else{
400           /* Set FAIstate to current objectAttrs */
401           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
402           if(isset($objectAttrs['FAIstate'][0])){
403             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
404               $objectAttrs['FAIstate'][0] .= "|removed";
405             }
406           }else{
407             $objectAttrs['FAIstate'][0] = "|removed";
408           }
410           /* Force reload of FAI classes */
411           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
412           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
413             $reload_fai_classes = TRUE;
414           }
415         }
416       }
418       /* Check if this a leaf release or not */ 
419       if(count($following_releases) == 0 ){
421         /* This is a leaf object. It isn't inherited by any other object */    
422         if(DEBUG_FAI_FUNC) { 
423           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
424           print_a($objectAttrs);
425         }
426         FAI::save_FAI_object($Current_DN,$objectAttrs);
428         /* Force reload of FAI classes */
429         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
430         if(count(array_intersect($classes,$objectAttrs['objectClass']))){
431           $reload_fai_classes = TRUE;
432         }
434       }else{
436         /* This object is inherited by some sub releases */  
438         /* Get all releases, that inherit this object */ 
439         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
441         /* Get parent object */
442         $ldap->cat($parent_obj);
443         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
445         /* New objects require special handling */
446         if($is_new){
448           /* Force reload of FAI classes */
449           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
450           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
451             $reload_fai_classes = TRUE;
452           }
454           /* check if there is already an entry named like this,
455              in one of our parent releases */
456           if(!empty($parent_obj)){
457             if(DEBUG_FAI_FUNC) { 
458               echo "There is already an entry named like this.</b><br>";
460               echo "<b>Saving main object</b>".$Current_DN;
461               print_a($objectAttrs);
462             }    
463             FAI::save_FAI_object($Current_DN,$objectAttrs);
465             foreach($r as $key){
466               if(DEBUG_FAI_FUNC) { 
467                 echo "<b>Saving parent to following release</b> ".$key;
468                 print_a($parent_attrs);
469               }
470               FAI::save_FAI_object($key,$parent_attrs);
471             }
472           }else{
474             if(DEBUG_FAI_FUNC) { 
475               echo "<b>Saving main object</b>".$Current_DN;
476               print_a($objectAttrs);
477             }
478             FAI::save_FAI_object($Current_DN,$objectAttrs);
480             if(isset($objectAttrs['FAIstate'])){
481               $objectAttrs['FAIstate'] .= "|removed"; 
482             }else{
483               $objectAttrs['FAIstate'] = "|removed";
484             }
486             foreach($r as $key ){
487               if(DEBUG_FAI_FUNC) { 
488                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
489                 print_a($objectAttrs);
490               }
491               FAI::save_FAI_object($key,$objectAttrs);
492             }
493           }
494         }else{
496           /* check if we must patch the follwing release */
497           if(!empty($r)){
499             foreach($r as $key ){
500               if(DEBUG_FAI_FUNC) { 
501                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
502                 print_a($parent_attrs);
503               }
504              
505               /* Append FAIstate tag to ensure that freezed objects stay freezed
506                */ 
507               $rTag = FAI::get_release_tag(FAI::get_release_dn($key));
508               $parent_attrs['FAIstate'] = $rTag;
509               FAI::save_FAI_object($key,$parent_attrs);
510             }
511           }
513           if(DEBUG_FAI_FUNC) { 
514             echo "<b>Saving current object</b>".$parent_obj;
515             print_a($objectAttrs);
516           }
517           FAI::save_FAI_object($parent_obj,$objectAttrs);
519           if(($parent_obj != $Current_DN)){
520             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
521           }
522         }
523       }
524     }
526     /* Reload GOsa si FAI DB/cache
527      */
528     if($reload_fai_classes){
529       if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
530         $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);        
531         if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
532           $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db']; 
533           $tmp = new $evt['CLASS_NAME']($config);
534           $tmp->set_type(TRIGGERED_EVENT);
535           $tmp->add_targets(array("GOsa"));
536           $o_queue = new gosaSupportDaemon();
537           if(!$o_queue->append($tmp)){
538             msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
539           }
540         }
541       }
542     }
544     session::set('FAI_objects_to_save',array());
545   }
548   /* this function will remove all unused (deleted) objects,
549      that have no parent object */
550   static function clean_up_releases($Current_DN)
551   {
552     global $config;
553     $ldap = $config->get_ldap_link();
554     $ldap->cd($config->current['BASE']);
556     /* Collect some basic informations and initialize some variables */ 
557     $base_release       = FAI::get_release_dn($Current_DN);
558     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
559     $Kill = array();
560     $Skip = array();
562     /* We must also include the given release dn */
563     $previous_releases[] = $base_release;
565     /* Walk through all releases */
566     foreach($previous_releases as $release){
568       /* Get fai departments */
569       $deps_to_search = FAI::get_FAI_departments($release); 
571       /* For every single department  (ou=hoos,ou ..) */
572       foreach($deps_to_search as $fai_base){
574         /* Ldap search for fai classes specified in this release */
575         $ldap->cd($fai_base);
576         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
578         /* check the returned objects, and add/replace them in our return variable */
579         while($attr = $ldap->fetch()){
581           $buffer = array();
582 #        $name = str_ireplace($release,"",$attr['dn']);
583           $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
585           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
587             /* Check if this object is required somehow */    
588             if(!isset($Skip[$name])){
589               $Kill[$attr['dn']] = $attr['dn'];
590             }
591           }else{
593             /* This object is required (not removed), so do not 
594                delete any following sub releases of this object */
595             $Skip[$name] = $attr['dn'];
596           }
597         }
598       }
599     }
600     return($Kill);
601   }
604   /* Remove numeric index and 'count' from ldap->fetch result */
605   static function prepare_ldap_fetch_to_be_saved($attrs)
606   {
607     foreach($attrs as $key => $value){
608       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
609         unset($attrs[$key]);
610       }
611       if(is_array($value) && isset($value['count'])){
612         unset($attrs[$key]['count']);
613       }
614     }
615     return($attrs);
616   }
619   /* Save given attrs to specified dn*/
620   static function save_FAI_object($dn,$attrs)
621   {
622     global $config;
623     $ldap = $config->get_ldap_link();
624     $ldap->cd($config->current['BASE']);
625     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
626     $ldap->cd($dn);
628     $ldap->cat($dn,array("dn"));
629     if($ldap->count()){
631       /* Remove FAIstate*/
632       if(!isset($attrs['FAIstate'])){
633         $attrs['FAIstate'] = array();
634       }
636       $ldap->modify($attrs);
637     }else{
639       /* Unset description if empty  */
640       if(empty($attrs['description'])){
641         unset($attrs['description']);
642       }    
644       $ldap->add($attrs);
645     }
646     if (!$ldap->success()){
647       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
648     }
649   }
652   /* Return FAIstate freeze branch or "" for specified release department */
653   static function get_release_tag($dn)
654   {
655     global $config;
656     $ldap = $config->get_ldap_link();
657     $ldap->cd($dn);
658     $ldap->cat($dn,array("FAIstate"));
660     if($ldap->count()){
662       $attr = $ldap->fetch();
663       if(isset($attr['FAIstate'][0])){
664         if(preg_match("/freeze/",$attr['FAIstate'][0])){
665           return("freeze");
666         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
667           return("branch");
668         }
669       }
670     }
671     return("");
672   }
675   static function get_following_releases_that_inherit_this_object($dn)
676   {
677     global $config;
678     $ldap = $config->get_ldap_link();
679     $ldap->cd($config->current['BASE']);
681     $ret = array();
683     /* Get base release */
684     $base_release = FAI::get_release_dn($dn);
686     /* Get previous release dns */
687     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
689     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
690 #  $dn_suffix = str_ireplace($base_release,"",$dn);
691     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
693     /* Check if given object also exists whitin one of these releases */
694     foreach($sub_releases as $p_release => $name){
696       $check_dn = $dn_suffix.$p_release;
698       $ldap->cat($check_dn,array("dn","objectClass"));
700       if($ldap->count()){
701         //return($ret);
702       }else{
703         $ret[$check_dn]=$check_dn;
704       }
705     }
706     return($ret);
707   }
710   /* Get previous version of the object dn */
711   static function get_parent_release_object($dn,$include_myself=true)
712   {
713     global $config;
714     $ldap = $config->get_ldap_link();
715     $ldap->cd($config->current['BASE']);
716     $previous_releases= array();
718     /* Get base release */
719     $base_release = FAI::get_release_dn($dn);
720     if($include_myself){
721       $previous_releases[] = $base_release;  
722     }
724     /* Get previous release dns */
725     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
726     foreach($tmp as $release){
727       $previous_releases[] = $release;
728     }
730     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
731 #  $dn_suffix = str_ireplace($base_release,"",$dn);
732     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
734     /* Check if given object also exists whitin one of these releases */
735     foreach($previous_releases as $p_release){
736       $check_dn = $dn_suffix.$p_release;
737       $ldap->cat($check_dn,array("dn","objectClass"));
739       if($ldap->count()){
740         return($check_dn);
741       }
742     }
743     return("");
744   }
747   /* return release names of all parent releases */
748   static function get_previous_releases_of_this_release($dn,$flat)
749   {
750     global $config;
751     $ldap = $config->get_ldap_link();
752     $ldap->cd($config->current['BASE']);
753     $ret = array();
755     /* Explode dns into pieces, to be able to build parent dns */
756     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
758     if(!is_array($dns_to_check)){
759       return;  
760     }
762     /* Unset first entry which represents the given dn */
763     unset($dns_to_check['count']); 
764     unset($dns_to_check[key($dns_to_check)]);
766     /* Create dns addresses and check if this dn is a release dn */
767     $id = 0;
768     while(count($dns_to_check)){
770       /* build parent dn */
771       $new_dn = "";
772       foreach($dns_to_check as $part){
773         $new_dn .= $part.",";
774       }
775       $new_dn .= $config->current['BASE'];
777       /* check if this dn is a release */
778       if(FAI::is_release_department($new_dn)){
779         if($flat){
780           $ret[$id] = $new_dn; 
781         }else{
782           $ret = array($new_dn=>$ret); 
783         }
784         $id ++;
785       }else{
786         return($ret);
787       }
788       reset($dns_to_check);
789       unset($dns_to_check[key($dns_to_check)]);
790     }
791     return($ret);
792   } 
795   /* This function returns all sub release names, recursivly  */
796   static function get_sub_releases_of_this_release($dn,$flat = false)
797   {
798     global $config;
799     $res  = array();
800     $ldap = $config->get_ldap_link();
801     $ldap->cd($config->current['BASE']);
802     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
803     while($attr = $ldap->fetch()){
805       /* Append department name */
806       if($flat){
807         $res[$attr['dn']] = $attr['ou'][0];
808       }else{
809         $res[$attr['dn']] = array();
810       }
812       /* Get sub release departments of this department */
813       if(in_array("FAIbranch",$attr['objectClass'])) {
814         if($flat){
815           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
816           foreach($tmp as $dn => $value){
817             $res[$dn]=$value;
818           }
819         }else{
820           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
821         }
822       }
823     }
824     return($res);
825   }
828   /* Check if the given department is a release department */
829   static function is_release_department($dn)
830   {
831     global $config;
832     $ldap = $config->get_ldap_link();
833     $ldap->cd($config->current['BASE']);
834     $ldap->cat($dn,array("objectClass","ou"));
836     /* Check objectClasses and name to check if this is a release department */
837     if($ldap->count()){
838       $attrs = $ldap->fetch();
840       $ou = "";
841       if(isset($attrs['ou'][0])){
842         $ou = $attrs['ou'][0];  
843       }
845       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
846         return($attrs['dn']);
847       }
848     }
849     return(false);
850   }
853   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
854   {
855     global $config;
856     $start = microtime(TRUE);
857     $source_release = trim($source_release,"/");
859     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
861     $sub_releases = array();
862     $source_dn = "";
863     
864     $tmp = split("\/",$source_release);
865     foreach($tmp as $part){
866       if(empty($part)){
867         continue;
868       }
869       $source_dn            = "ou=".$part.",".$source_dn;
870       $sub_releases[$part]  = $source_dn;
871     }
873     /* Get all groups */
874     $ldap =$config->get_ldap_link();
875     $ldap->cd($config->current['BASE']);
876     $ldap->search("(objectClass=posixGroup)",array("dn"));
877     $groups = array();
878     while($attrs = $ldap->fetch()){
879       $groups[$attrs['dn']] = $attrs;
880     }
882     /* Get all FAI releases, to be able to create missing group application releases 
883         with the correct type of release (FAIstate=freeze/branch).
884      */
885     $f_releases = array();
886     $ldap->cd ($config->current['BASE']);
887     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
888     while($attrs = $ldap->fetch()){
889       foreach($sub_releases as $sub_rel){
890         if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
891           $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
892         }
893       }
894     }
896     /* Get all group releases */
897     $g_releases = array();
898     foreach($groups as $dn => $data){
899       $ldap->cd($dn);
900       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
901       while($attrs = $ldap->fetch()){
902         $g_releases[$attrs['dn']] = $attrs;
903       }
904     }
906     /* Check if base releases exists.
907        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
908      */
909     foreach($sub_releases as $name => $sub_rel){
911       $FAIstate = "";
912       if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
913         $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
914       }
916       foreach($groups as $dn => $data){
917         if(!isset($g_releases[$sub_rel.$dn])){
918           $ldap->cd($dn);
919           $r_data = array();
920           $r_data['ou'] = $name;
921           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
922           if(!empty($FAIstate)) {
923             $r_data['FAIstate'] = $FAIstate;
924           }
925  
926           $ldap->cd($sub_rel.$dn) ;
927           $ldap->add($r_data);
928           echo "&nbsp;<b>"._("Object").":</b> ";
929           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
930           flush();
931         }
932       }
933     } 
934  
935     /* Create new release container in each group.
936      */
937     $n_data = array();
938     $n_data = array();
939     $n_data['ou'] = $destination_name;
940     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
941     if(!empty($type)){
942       $n_data['FAIstate'] = $type."/cow";
943     }
945     foreach($groups as $dn => $att){
946       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
947       if(!isset($g_releases[$n_dn])){
948         $ldap->cd ($n_dn);
949         $ldap->add($n_data);
950         echo "&nbsp;<b>"._("Object").":</b> ";
951         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
952         flush();
953       }
954     }
956     /* If the source release is empty, then create a new release by copying 
957         all group application menus into a new ou=$destination_name release container.
958       
959        If the source release is not empty. 
960          We detect all releases which match the source release dn and copy the contents.
961      */
962     if(empty($source_release)){
963       $source_dns = $groups;
964     }else{
965       $source_dns = array();
966       foreach($g_releases as $dn => $data){
967         if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
968           $source_dns[$dn] = $data; 
969         }
970       }
971     }
973     /* Detect all menu object we have to copy 
974      */
975     $to_copy = array();
976     foreach($source_dns as $dn => $attrs){
977       $ldap->cd($dn);
978       $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
979       while($attrs = $ldap->fetch()){
980         $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
981         $to_copy[$attrs['dn']] = $destination;
982       }
983     }
984    
985     /* At least create the menu objects object */
986     $plug = new plugin($config);
987     foreach($to_copy as $source => $destination){
988       $ldap->cat($destination);
989       if($ldap->count()){
990         echo "&nbsp;<b>"._("Object").":</b> ";
991         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
992         flush();
993       }else{
994         $plug->copy($source,$destination);
995         echo "&nbsp;<b>"._("Object").":</b> ";
996         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
997         flush();
998       }
999     }
1000   }
1003   /*! \brief Create a new FAI branch.
1004    *  @param $sourcedn          String  The source release dn
1005    *  @param $destinationdn     String  The destination dn
1006    *  @param $destinationName   String  The name of the new release
1007    *  @param $type              String  The release type (freeze/branch)
1008    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
1009    *  @param $depth             Integer Current depth of recursion.
1010    */
1011   static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1012   {
1013     global $config;
1014     error_reporting(E_ALL | E_STRICT);
1015     $ldap     = $config->get_ldap_link();
1016     $basedn   = $config->current['BASE'];
1017     $delarray = array();
1019     /* The following code will output a status string
1020      *  for each handled object, in a seperate iframe.
1021      */
1024     /* Display current action information.
1025      */
1026     if($is_first){
1027       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1028     }else{
1029       if(preg_match("/^ou=/",$sourcedn)){
1030         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1031       }else{
1032         $tmp = split(",",$sourcedn);
1033         echo "&nbsp;<b>"._("Object").":</b> ";
1034         $deststr = LDAP::fix($destinationdn);
1035         if(strlen($deststr) > 96){
1036           $deststr = substr($deststr,0,96)."...";
1037         }
1038         echo $deststr."<br>";
1039       }
1040     }
1041     /* .. immediately display infos */
1042     flush();
1044     /* Check if destination entry already exists
1045      */
1046     $ldap->cat($destinationdn);
1047     if($ldap->count()){
1048       echo _("Could not create new release, the destination dn is already in use.");
1049       return;
1050     }else{
1052       $ldap->clearResult();
1054       /* Get source entry
1055        *  if it does not exist, abort here.
1056        */
1057       $ldap->cd($basedn);
1058       $ldap->cat($sourcedn);
1059       $attr = $ldap->fetch();
1060       if((!$attr) || (count($attr)) ==0) {
1061         echo _("Error while fetching source dn - aborted!");
1062         return;
1063       }
1065       /* The current object we want to create is an department.
1066        * Create the department and add the FAIbranch tag.
1067        */
1068       if(in_array("organizationalUnit",$attr['objectClass'])){
1069         $attr['dn'] = LDAP::convert($destinationdn);
1070         $ldap->cd($basedn);
1071         $ldap->create_missing_trees($destinationdn);
1072         $ldap->cd($destinationdn);
1074         /* If is first entry, append FAIbranch to department entry */
1075         if($is_first){
1076           $ldap->cat($destinationdn);
1077           $attr= $ldap->fetch();
1078           /* Filter unneeded informations */
1079           foreach($attr as $key => $value){
1080             if(is_numeric($key)) unset($attr[$key]);
1081             if(isset($attr[$key]['count'])){
1082               if(is_array($attr[$key])){
1083                 unset($attr[$key]['count']);
1084               }
1085             }
1086           }
1088           unset($attr['count']);
1089           unset($attr['dn']);
1091           /* Add marking attribute */
1092           $attr['objectClass'][] = "FAIbranch";
1093           $attr['FAIstate'] = $type;
1095           /* Add this entry */
1096           $ldap->modify($attr);
1097         }
1098       }else{
1100         /* Replicate all relevant FAI objects here.
1101          * FAI objects, Apps and Mimetypes.
1102          * Get all attributes as binary value, to ensure that Icon, File template aso
1103          *  are created correctly.
1104          */
1105         foreach($attr as $key => $value){
1107           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1108             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1109             $ei= ldap_first_entry($ldap->cid, $sr);
1110             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1111               $attr[$key] = $tmp;
1112             }
1113           }
1115           if(is_numeric($key)) unset($attr[$key]);
1116           if(isset($attr[$key]['count'])){
1117             if(is_array($attr[$key])){
1118               unset($attr[$key]['count']);
1119             }
1120           }
1121         }
1122         unset($attr['count']);
1123         unset($attr['dn']);
1124         if(!in_array("FAIclass",$attr['objectClass'])){
1125           $attr['objectClass'][] = "FAIobject";
1126         }
1127         $attr['FAIstate'] = $type;
1129         /* Add entry
1130          */
1131         $ldap->cd($destinationdn);
1132         $ldap->cat($destinationdn);
1134         $a = $ldap->fetch();
1135         if(!count($a)){
1136           $ldap->add($attr);
1137         }
1139         if(!$ldap->success()){
1141           /* Some error occurred */
1142           print "---------------------------------------------";
1143           print $ldap->get_error()."<br>";
1144           print $sourcedn."<br>";
1145           print $destinationdn."<br>";
1146           print_a( $attr);
1147           exit();
1148         }
1149       }
1150     }
1152     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1154     /* Prepare for recursive copy.
1155      * Get all object within the source dn and
1156      *  call the recursive copy for each.
1157      */
1158     $ldap->ls ("(objectClass=*)",$sourcedn);
1159     while ($ldap->fetch()){
1160       $deldn= $ldap->getDN();
1161       $delarray[$deldn]= strlen($deldn);
1162     }
1163     asort ($delarray);
1164     reset ($delarray);
1165     $depth ++;
1166     foreach($delarray as $dn => $bla){
1167       if($dn != $destinationdn){
1168         $ldap->cd($basedn);
1169         $item = $ldap->fetch($ldap->cat($dn));
1170         if(!in_array("FAIbranch",$item['objectClass'])){
1171           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1172         }
1173       }
1174     }
1175     if($is_first){
1176       echo "<p class='seperator'>&nbsp;</p>";
1177     }
1178   }
1182   /* This function returns the dn of the object release */
1183   static function get_release_dn($Current_DN)
1184   {
1185     global $config;
1186     $ldap = $config->get_ldap_link();
1187     $ldap->cd($config->current['BASE']);
1189     /* Split dn into pices */ 
1190     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1192     if(!is_array($dns_to_check)){
1193       return;  
1194     }
1196     /* Use dn pieces, to create sub dns like 
1197        ou=test,ou=1,ou=0...
1198        ou=1,ou=0...
1199        ou=0... 
1200        To check which dn is our release container.
1201      */
1202     unset($dns_to_check['count']); 
1203     while(count($dns_to_check)){
1205       /* Create dn */
1206       $new_dn = "";
1207       foreach($dns_to_check as $part){
1208         $new_dn .= $part.",";
1209       }
1210       $new_dn .= $config->current['BASE'];
1212       /* Check if this dn is a release dn */
1213       if(FAI::is_release_department($new_dn)){
1214         return($new_dn);
1215       }
1217       /* Remove first element of dn pieces */
1218       reset($dns_to_check);
1219       unset($dns_to_check[key($dns_to_check)]);
1220     }
1221     return("");
1222   }
1228 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1229 ?>