Code

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