Code

Updated get_ou it receives values from the config registry now.
[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     $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
149     $tmp = array();
150     if(preg_match("/^,/",$suffix)){
151       $suffix = preg_replace("/^,/","",$suffix);
152     }
153     foreach($arr as $name){
154       if(empty($suffix)){
155         $tmp[$name] = "ou=".$name;
156       }else{
157         $tmp[$name] = "ou=".$name.",".$suffix;
158       }
159     }
160     return($tmp);
161   }
164   /* Return all releases within the given base */
165   static function get_all_releases_from_base($dn,$appendedName=false)
166   {
167     global $config;
169     if(!preg_match("/".preg_quote(get_ou('faiBaseRDN'), '/')."/i",$dn)){
170       $base = get_ou('faiBaseRDN').$dn;
171     }else{
172       $base = $dn;
173     }
174     $res = array();  
176     $ldap = $config->get_ldap_link();
177     $ldap->cd($base);
178     $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
179     while($attrs = $ldap->fetch()){
180       if($appendedName){
181         $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".preg_quote(get_ou('faiBaseRDN'), '/').".*$/i","",$attrs['dn']));
182       }else{
183         $res[$attrs['dn']] = $attrs['ou'][0];
184       }
185     }
186     return($res);
187   }
190   /* Add this object to list of objects, that must be checked for release saving */
191   static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
192   {
193     /* Get ldap object */  
194     global $config;
195     $addObj['Current_DN'] = $Current_DN;
196     $addObj['objectAttrs']= $objectAttrs;
197     $addObj['removed']    = $removed;
198     $addObj['diff']       = TRUE;
200     if(!$removed){
201       $ldap = $config->get_ldap_link();
202       $ldap->cd($config->current['BASE']);
204       /* Get some basic informations */
205       $parent_obj   = FAI::get_parent_release_object($Current_DN);
206       if(!empty($parent_obj)){
207         $ldap->cat($parent_obj,array("*"));
208         $attrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
210         if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
211           $addObj['diff'] = FALSE;
212         }
213       } 
214     }else{
216       /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
217           we have to remove this name from all profiles in this release.
218       */
219       $ldap = $config->get_ldap_link();
220       $ldap->cd($config->current['BASE']);
221       $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
223       /* Dont't try to modify non FAIclasses  
224        */
225       if(!preg_match("/[^,]+,".preg_quote(get_ou("faiBaseRDN"), '/')."/i",$obj_dn)){
226         trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);        
227         echo "<br>-->".$Current_DN."<br>";
228         echo "<br>-->".$obj_dn."<br>";
229       }else{
231         /* Get source object and check if it is a base FAIclass
232          */
233         $ldap->cat($obj_dn);
234         $attrs = $ldap->fetch();
235         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
236         if(count(array_intersect($classes,$attrs['objectClass']))){
237           $cn    = $attrs['cn'][0];
239           /* Check if this is the last with this name in the current release.
240               In this case we have to remove the package name 
241               from all profiles in this release.
242            */
243           $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
244               "(&(objectClass=FAIclass)(cn=".$cn."))"); 
246           /* Check if this is the last class with this name */
247           if(count($classes) == 1){
249             /* Get all FAI Profiles 
250              */
251             $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
252                 "(&(objectClass=FAIprofile)(FAIclass=*))"); 
254             /* Walk though all profiles and remove the source class name
255              */
256             foreach($profiles as $dn){
257               $ldap->cat($dn['dn']);
258               $attrs = $ldap->fetch();
260               $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
262               /* Check if this Profile uses the source class ($cn)
263                */
264               if(preg_match("/".preg_quote($cn, '/')."/",$attrs['FAIclass'])){
265                 $attrs['FAIclass'] = preg_replace("/[ ]*".preg_quote($cn, '/')."[ ]*/i"," ",$attrs['FAIclass']);
266                 if(empty($attrs['FAIclass'])){
267                   $attrs['FAIclass'] = array();
268                 }
269                 $ldap->cd($dn['dn']);
270                 $ldap->modify($attrs);
272                 if (!$ldap->success()){
273                   msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
274                 }
275               }
276             }
277           }
278         }
279       }
280     }
284     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
285     $FAI_objects_to_save[$Current_DN] =  $addObj;
286     session::set('FAI_objects_to_save',$FAI_objects_to_save);
287   }
290   /* Detect differences in attribute arrays  */
291   static function array_diff_FAI($ar1,$ar2)
292   {
294     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
295       $ar1['description'] = "";
296     }
297     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
298       $ar2['description'] = "";
299     }
301     if(count($ar1) != count($ar2)) {
302       return (true);
303     }
305     foreach($ar1 as $key1 => $val1){
307       if((is_array($val1)) && (count($val1)==1)){
308         $ar1[$key1] = $val1[0];
309       }
311       if(isset($ar2[$key1])&&  (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
312         $val1 = $val1[0];
313         $ar2[$key1] = $ar2[$key1][0];
314       }
315     }
316     ksort($ar1);
317     ksort($ar2);
318     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
319       return(true);
320     }else{
321       return(false);
322     }
323   }
326   static function arr_diff($ar1,$ar2)
327   {
328     foreach($ar1 as $ak1 => $av1){
329       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
330         return(TRUE);    
331       }elseif(is_array($av1)){
332         $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
333         if($ret) {
334           return(TRUE);
335         }
336       }
337     }
338     return(FALSE);
339   }
344   /* check which objects must be saved, and save them */
345   static function save_release_changes_now()
346   {
347     global $config;
348     /* Variable init*/
349     $to_save = array();
350     
351     $reload_fai_classes = FALSE;
353     /* check which objects must be saved */
354     if(!session::is_set('FAI_objects_to_save')){
355       return;
356     }
357     $FAI_objects_to_save = session::get('FAI_objects_to_save');
358     if(!is_array($FAI_objects_to_save)) {
359       print_a(array(session::get('FAI_objects_to_save')));
360       trigger_error("Can't save FAI objects, no array given.");
361       return;
362     }
363   
364     foreach($FAI_objects_to_save as $Current_DN => $object){
365       if($object['diff']){
366         $sub_name = $Current_DN;
367         while(isset($FAI_objects_to_save[$sub_name])){
368           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
369           unset($FAI_objects_to_save[$sub_name]);
370           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
371         }
372       }
373     }
374     session::set('FAI_objects_to_save',$FAI_objects_to_save);
376     /* Sort list of objects that must be saved, and ensure that 
377        container   objects are safed, before their childs are saved */
378     ksort($to_save);
379     $tmp = array();
380     foreach($to_save as $SubObjects){
381       foreach($SubObjects as $object){
382         $tmp[] = $object;
383       }
384     }
385     $to_save = $tmp;
388     /* Save objects and manage the correct release behavior*/
389     foreach($to_save as $save){
391       $Current_DN = $save['Current_DN'];
392       $removed    = $save['removed'];
393       $objectAttrs= $save['objectAttrs'];
395       /* Get ldap object */ 
396       $ldap = $config->get_ldap_link();
397       $ldap->cd($config->current['BASE']);
399       /* Get some basic informations */
400       $base_release       = FAI::get_release_dn($Current_DN);
401       $sub_releases       = FAI::get_sub_releases_of_this_release($base_release,true);
402       $parent_obj         = FAI::get_parent_release_object($Current_DN);
403       $following_releases = $sub_releases;
405       /* Check if given dn exists or if is a new entry */
406       $ldap->cat($Current_DN);
407       if(!$ldap->count()){
408         $is_new = true;
409       }else{
410         $is_new = false;
411       }
413       /* if parameter removed is true, we have to add FAIstate to the current attrs 
414          FAIstate should end with ...|removed after this operation */  
415       if($removed ){
416         $ldap->cat($Current_DN);
418         /* Get current object, because we must add the FAIstate ...|removed */
419         if((!$ldap->count()) && !empty($parent_obj)){
420           $ldap->cat($parent_obj);
421         }
423         /* Check if we have found a suiteable object */ 
424         if(!$ldap->count()){
425           echo "Error can't remove this object ".$Current_DN;
426           return;
427         }else{
429           /* Set FAIstate to current objectAttrs */
430           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
431           if(isset($objectAttrs['FAIstate'][0])){
432             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
433               $objectAttrs['FAIstate'][0] .= "|removed";
434             }
435           }else{
436             $objectAttrs['FAIstate'][0] = "|removed";
437           }
439           /* Force reload of FAI classes */
440           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
441           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
442             $reload_fai_classes = TRUE;
443           }
444         }
445       }
447       /* Check if this a leaf release or not */ 
448       if(count($following_releases) == 0 ){
450         /* This is a leaf object. It isn't inherited by any other object */    
451         if(DEBUG_FAI_FUNC) { 
452           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
453           print_a($objectAttrs);
454         }
455         FAI::save_FAI_object($Current_DN,$objectAttrs);
457         /* Force reload of FAI classes */
458         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
459         if(count(array_intersect($classes,$objectAttrs['objectClass']))){
460           $reload_fai_classes = TRUE;
461         }
463       }else{
465         /* This object is inherited by some sub releases */  
467         /* Get all releases, that inherit this object */ 
468         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
470         /* Get parent object */
471         $ldap->cat($parent_obj);
472         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
474         /* New objects require special handling */
475         if($is_new){
477           /* Force reload of FAI classes */
478           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
479           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
480             $reload_fai_classes = TRUE;
481           }
483           /* check if there is already an entry named like this,
484              in one of our parent releases */
485           if(!empty($parent_obj)){
486             if(DEBUG_FAI_FUNC) { 
487               echo "There is already an entry named like this.</b><br>";
489               echo "<b>Saving main object</b>".$Current_DN;
490               print_a($objectAttrs);
491             }    
492             FAI::save_FAI_object($Current_DN,$objectAttrs);
494             foreach($r as $key){
495               if(DEBUG_FAI_FUNC) { 
496                 echo "<b>Saving parent to following release</b> ".$key;
497                 print_a($parent_attrs);
498               }
499               FAI::save_FAI_object($key,$parent_attrs);
500             }
501           }else{
503             if(DEBUG_FAI_FUNC) { 
504               echo "<b>Saving main object</b>".$Current_DN;
505               print_a($objectAttrs);
506             }
507             FAI::save_FAI_object($Current_DN,$objectAttrs);
509             if(isset($objectAttrs['FAIstate'])){
510               $objectAttrs['FAIstate'] .= "|removed"; 
511             }else{
512               $objectAttrs['FAIstate'] = "|removed";
513             }
515             foreach($r as $key ){
516               if(DEBUG_FAI_FUNC) { 
517                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
518                 print_a($objectAttrs);
519               }
520               FAI::save_FAI_object($key,$objectAttrs);
521             }
522           }
523         }else{
525           /* check if we must patch the follwing release */
526           if(!empty($r)){
528             foreach($r as $key ){
529               if(DEBUG_FAI_FUNC) { 
530                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
531                 print_a($parent_attrs);
532               }
533              
534               /* Append FAIstate tag to ensure that freezed objects stay freezed
535                */ 
536               $rTag = FAI::get_release_tag(FAI::get_release_dn($key));
537               $parent_attrs['FAIstate'] = $rTag;
539               /* FAItemplateFile can be binary, therefore it needs to be fetched with
540                * $ldap->get_attribute */
541               if (isset($parent_attrs['FAItemplateFile'])) {
542                 $parent_attrs['FAItemplateFile'] = $ldap->get_attribute($parent_obj, 'FAItemplateFile');
543               }
545               FAI::save_FAI_object($key,$parent_attrs);
546             }
547           }
549           if(DEBUG_FAI_FUNC) { 
550             echo "<b>Saving current object</b>".$parent_obj;
551             print_a($objectAttrs);
552           }
553           FAI::save_FAI_object($parent_obj,$objectAttrs);
555           if(($parent_obj != $Current_DN)){
556             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
557           }
558         }
559       }
560     }
562     /* Reload GOsa si FAI DB/cache
563      */
564     if($reload_fai_classes){
565       if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
566         $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);        
567         if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
568           $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db']; 
569           $tmp = new $evt['CLASS_NAME']($config);
570           $tmp->set_type(TRIGGERED_EVENT);
571           $tmp->add_targets(array("GOSA"));
572           $o_queue = new gosaSupportDaemon();
573           if(!$o_queue->append($tmp)){
574             msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
575           }
576         }
577       }
578     }
580     session::set('FAI_objects_to_save',array());
581   }
584   /* this function will remove all unused (deleted) objects,
585      that have no parent object */
586   static function clean_up_releases($Current_DN)
587   {
588     global $config;
589     $ldap = $config->get_ldap_link();
590     $ldap->cd($config->current['BASE']);
592     /* Collect some basic informations and initialize some variables */ 
593     $base_release       = FAI::get_release_dn($Current_DN);
594     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
595     $Kill = array();
596     $Skip = array();
598     /* We must also include the given release dn */
599     $previous_releases[] = $base_release;
601     /* Walk through all releases */
602     foreach($previous_releases as $release){
604       /* Get fai departments */
605       $deps_to_search = FAI::get_FAI_departments($release); 
607       /* For every single department  (ou=hoos,ou ..) */
608       foreach($deps_to_search as $fai_base){
610         /* Ldap search for fai classes specified in this release */
611         $ldap->cd($fai_base);
612         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
614         /* check the returned objects, and add/replace them in our return variable */
615         while($attr = $ldap->fetch()){
617           $buffer = array();
618 #        $name = str_ireplace($release,"",$attr['dn']);
619           $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
621           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
623             /* Check if this object is required somehow */    
624             if(!isset($Skip[$name])){
625               $Kill[$attr['dn']] = $attr['dn'];
626             }
627           }else{
629             /* This object is required (not removed), so do not 
630                delete any following sub releases of this object */
631             $Skip[$name] = $attr['dn'];
632           }
633         }
634       }
635     }
636     return($Kill);
637   }
640   /* Remove numeric index and 'count' from ldap->fetch result */
641   static function prepare_ldap_fetch_to_be_saved($attrs)
642   {
643     foreach($attrs as $key => $value){
644       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
645         unset($attrs[$key]);
646       }
647       if(is_array($value) && isset($value['count'])){
648         unset($attrs[$key]['count']);
649       }
650     }
651     return($attrs);
652   }
655   /* Save given attrs to specified dn*/
656   static function save_FAI_object($dn,$attrs)
657   {
658     global $config;
659     $ldap = $config->get_ldap_link();
660     $ldap->cd($config->current['BASE']);
661     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
662     $ldap->cd($dn);
664     $ldap->cat($dn,array("dn"));
665     if($ldap->count()){
667       /* Remove FAIstate*/
668       if(!isset($attrs['FAIstate'])){
669         $attrs['FAIstate'] = array();
670       }
672       $ldap->modify($attrs);
673     }else{
675       /* Unset description if empty  */
676       if(empty($attrs['description'])){
677         unset($attrs['description']);
678       }    
680       $ldap->add($attrs);
681     }
682     if (!$ldap->success()){
683       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
684     }
685   }
688   /* Return FAIstate freeze branch or "" for specified release department */
689   static function get_release_tag($dn)
690   {
691     global $config;
692     $ldap = $config->get_ldap_link();
693     $ldap->cd($dn);
694     $ldap->cat($dn,array("FAIstate"));
696     if($ldap->count()){
698       $attr = $ldap->fetch();
699       if(isset($attr['FAIstate'][0])){
700         if(preg_match("/freeze/",$attr['FAIstate'][0])){
701           return("freeze");
702         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
703           return("branch");
704         }
705       }
706     }
707     return("");
708   }
711   static function get_following_releases_that_inherit_this_object($dn)
712   {
713     global $config;
714     $ldap = $config->get_ldap_link();
715     $ldap->cd($config->current['BASE']);
717     $ret = array();
719     /* Get base release */
720     $base_release = FAI::get_release_dn($dn);
722     /* Get previous release dns */
723     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
725     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
726 #  $dn_suffix = str_ireplace($base_release,"",$dn);
727     $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
729     /* Check if given object also exists whitin one of these releases */
730     foreach($sub_releases as $p_release => $name){
732       $check_dn = $dn_suffix.$p_release;
734       $ldap->cat($check_dn,array("dn","objectClass"));
736       if($ldap->count()){
737         //return($ret);
738       }else{
739         $ret[$check_dn]=$check_dn;
740       }
741     }
742     return($ret);
743   }
746   /* Get previous version of the object dn */
747   static function get_parent_release_object($dn,$include_myself=true)
748   {
749     global $config;
750     $ldap = $config->get_ldap_link();
751     $ldap->cd($config->current['BASE']);
752     $previous_releases= array();
754     /* Get base release */
755     $base_release = FAI::get_release_dn($dn);
756     if($include_myself){
757       $previous_releases[] = $base_release;  
758     }
760     /* Get previous release dns */
761     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
762     foreach($tmp as $release){
763       $previous_releases[] = $release;
764     }
766     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
767 #  $dn_suffix = str_ireplace($base_release,"",$dn);
768     $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
770     /* Check if given object also exists whitin one of these releases */
771     foreach($previous_releases as $p_release){
772       $check_dn = $dn_suffix.$p_release;
773       $ldap->cat($check_dn,array("dn","objectClass"));
775       if($ldap->count()){
776         return($check_dn);
777       }
778     }
779     return("");
780   }
783   /* return release names of all parent releases */
784   static function get_previous_releases_of_this_release($dn,$flat)
785   {
786     global $config;
787     $ldap = $config->get_ldap_link();
788     $ldap->cd($config->current['BASE']);
789     $ret = array();
791     /* Explode dns into pieces, to be able to build parent dns */
792     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$dn));
794     if(!is_array($dns_to_check)){
795       return;  
796     }
798     /* Unset first entry which represents the given dn */
799     unset($dns_to_check['count']); 
800     unset($dns_to_check[key($dns_to_check)]);
802     /* Create dns addresses and check if this dn is a release dn */
803     $id = 0;
804     while(count($dns_to_check)){
806       /* build parent dn */
807       $new_dn = "";
808       foreach($dns_to_check as $part){
809         $new_dn .= $part.",";
810       }
811       $new_dn .= $config->current['BASE'];
813       /* check if this dn is a release */
814       if(FAI::is_release_department($new_dn)){
815         if($flat){
816           $ret[$id] = $new_dn; 
817         }else{
818           $ret = array($new_dn=>$ret); 
819         }
820         $id ++;
821       }else{
822         return($ret);
823       }
824       reset($dns_to_check);
825       unset($dns_to_check[key($dns_to_check)]);
826     }
827     return($ret);
828   } 
831   /* This function returns all sub release names, recursivly  */
832   static function get_sub_releases_of_this_release($dn,$flat = false)
833   {
834     global $config;
835     $res  = array();
836     $ldap = $config->get_ldap_link();
837     $ldap->cd($config->current['BASE']);
838     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
839     while($attr = $ldap->fetch()){
841       /* Append department name */
842       if($flat){
843         $res[$attr['dn']] = $attr['ou'][0];
844       }else{
845         $res[$attr['dn']] = array();
846       }
848       /* Get sub release departments of this department */
849       if(in_array("FAIbranch",$attr['objectClass'])) {
850         if($flat){
851           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
852           foreach($tmp as $dn => $value){
853             $res[$dn]=$value;
854           }
855         }else{
856           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
857         }
858       }
859     }
860     return($res);
861   }
864   /* Check if the given department is a release department */
865   static function is_release_department($dn)
866   {
867     global $config;
868     $ldap = $config->get_ldap_link();
869     $ldap->cd($config->current['BASE']);
870     $ldap->cat($dn,array("objectClass","ou"));
872     /* Check objectClasses and name to check if this is a release department */
873     if($ldap->count()){
874       $attrs = $ldap->fetch();
876       $ou = "";
877       if(isset($attrs['ou'][0])){
878         $ou = $attrs['ou'][0];  
879       }
881       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
882         return($attrs['dn']);
883       }
884     }
885     return(false);
886   }
889   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
890   {
891     global $config;
892     $start = microtime(TRUE);
893     $source_release = trim($source_release,"/");
895     echo "<h3>".sprintf(_("Creating group application release for %s"),$destination_name)."</h3>";
897     $sub_releases = array();
898     $source_dn = "";
899     
900     $tmp = explode("/",$source_release);
901     foreach($tmp as $part){
902       if(empty($part)){
903         continue;
904       }
905       $source_dn            = "ou=".$part.",".$source_dn;
906       $sub_releases[$part]  = $source_dn;
907     }
909     /* Get all groups */
910     $ldap =$config->get_ldap_link();
911     $ldap->cd($config->current['BASE']);
912     $ldap->search("(objectClass=posixGroup)",array("dn"));
913     $groups = array();
914     while($attrs = $ldap->fetch()){
915       $groups[$attrs['dn']] = $attrs;
916     }
918     /* Get all FAI releases, to be able to create missing group application releases 
919         with the correct type of release (FAIstate=freeze/branch).
920      */
921     $f_releases = array();
922     $ldap->cd ($config->current['BASE']);
923     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
924     while($attrs = $ldap->fetch()){
925       foreach($sub_releases as $sub_rel){
926         if(preg_match("/^".preg_quote($sub_rel.get_ou('faiBaseRDN'), '/')."/i",$attrs['dn'])){
927           $f_releases[$sub_rel.get_ou('faiBaseRDN')] = $attrs;
928         }
929       }
930     }
932     /* Get all group releases */
933     $g_releases = array();
934     foreach($groups as $dn => $data){
935       $ldap->cd($dn);
936       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
937       while($attrs = $ldap->fetch()){
938         $g_releases[$attrs['dn']] = $attrs;
939       }
940     }
942     /* Check if base releases exists.
943        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
944      */
945     foreach($sub_releases as $name => $sub_rel){
947       $FAIstate = "";
948       if(isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]) && isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'])){
949         $FAIstate = $f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'][0];
950       }
952       foreach($groups as $dn => $data){
953         if(!isset($g_releases[$sub_rel.$dn])){
954           $ldap->cd($dn);
955           $r_data = array();
956           $r_data['ou'] = $name;
957           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
958           if(!empty($FAIstate)) {
959             $r_data['FAIstate'] = $FAIstate;
960           }
961  
962           $ldap->cd($sub_rel.$dn) ;
963           $ldap->add($r_data);
964           echo "&nbsp;<b>"._("Object").":</b> ";
965           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
966           flush();
967         }
968       }
969     } 
970  
971     /* Create new release container in each group.
972      */
973     $n_data = array();
974     $n_data = array();
975     $n_data['ou'] = $destination_name;
976     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
977     if(!empty($type)){
978       $n_data['FAIstate'] = $type."/cow";
979     }
981     foreach($groups as $dn => $att){
982       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
983       if(!isset($g_releases[$n_dn])){
984         $ldap->cd ($n_dn);
985         $ldap->add($n_data);
986         echo "&nbsp;<b>"._("Object").":</b> ";
987         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
988         flush();
989       }
990     }
992     /* If the source release is empty, then create a new release by copying 
993         all group application menus into a new ou=$destination_name release container.
994       
995        If the source release is not empty. 
996          We detect all releases which match the source release dn and copy the contents.
997      */
998     if(empty($source_release)){
999       $source_dns = $groups;
1000     }else{
1001       $source_dns = array();
1002       foreach($g_releases as $dn => $data){
1003         if(preg_match("/^".preg_quote($source_dn, '/')."/",$dn)){
1004           $source_dns[$dn] = $data; 
1005         }
1006       }
1007     }
1009     /* Detect all menu object we have to copy 
1010      */
1011     $to_copy = array();
1012     foreach($source_dns as $dn => $attrs){
1013       $ldap->cd($dn);
1014       $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
1015       while($attrs = $ldap->fetch()){
1016         $destination = preg_replace("/".preg_quote($dn, '/')."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
1017         $to_copy[$attrs['dn']] = $destination;
1018       }
1019     }
1020    
1021     /* At least create the menu objects object */
1022     $plug = new plugin($config);
1023     foreach($to_copy as $source => $destination){
1024       $ldap->cat($destination);
1025       if($ldap->count()){
1026         echo "&nbsp;<b>"._("Object").":</b> ";
1027         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
1028         flush();
1029       }else{
1030         $plug->copy($source,$destination);
1031         echo "&nbsp;<b>"._("Object").":</b> ";
1032         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
1033         flush();
1034       }
1035     }
1036   }
1039   /*! \brief Create a new FAI branch.
1040    *  @param $sourcedn          String  The source release dn
1041    *  @param $destinationdn     String  The destination dn
1042    *  @param $destinationName   String  The name of the new release
1043    *  @param $type              String  The release type (freeze/branch)
1044    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
1045    *  @param $depth             Integer Current depth of recursion.
1046    */
1047   static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1048   {
1049     global $config;
1050     error_reporting(E_ALL | E_STRICT);
1051     $ldap     = $config->get_ldap_link();
1052     $basedn   = $config->current['BASE'];
1053     $delarray = array();
1055     /* The following code will output a status string
1056      *  for each handled object, in a seperate iframe.
1057      */
1060     /* Display current action information.
1061      */
1062     if($is_first){
1063       echo "<h3>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h3>";
1064     }else{
1065       if(preg_match("/^ou=/",$sourcedn)){
1066         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1067       }else{
1068         $tmp = explode(",",$sourcedn);
1069         echo "&nbsp;<b>"._("Object").":</b> ";
1070         $deststr = LDAP::fix($destinationdn);
1071         if(strlen($deststr) > 96){
1072           $deststr = substr($deststr,0,96)."...";
1073         }
1074         echo $deststr."<br>";
1075       }
1076     }
1077     /* .. immediately display infos */
1078     flush();
1080     /* Check if destination entry already exists
1081      */
1082     $ldap->cat($destinationdn);
1083     if($ldap->count()){
1084       echo _("Could not create new release, the destination dn is already in use.");
1085       return;
1086     }else{
1088       $ldap->clearResult();
1090       /* Get source entry
1091        *  if it does not exist, abort here.
1092        */
1093       $ldap->cd($basedn);
1094       $ldap->cat($sourcedn);
1095       $attr = $ldap->fetch();
1096       if((!$attr) || (count($attr)) ==0) {
1097         echo _("Error while fetching source dn - aborted!");
1098         return;
1099       }
1101       /* The current object we want to create is an department.
1102        * Create the department and add the FAIbranch tag.
1103        */
1104       if(in_array("organizationalUnit",$attr['objectClass'])){
1105         $attr['dn'] = LDAP::convert($destinationdn);
1106         $ldap->cd($basedn);
1107         $ldap->create_missing_trees($destinationdn);
1108         $ldap->cd($destinationdn);
1110         /* If is first entry, append FAIbranch to department entry */
1111         if($is_first){
1112           $ldap->cat($destinationdn);
1113           $attr= $ldap->fetch();
1114           /* Filter unneeded informations */
1115           foreach($attr as $key => $value){
1116             if(is_numeric($key)) unset($attr[$key]);
1117             if(isset($attr[$key]['count'])){
1118               if(is_array($attr[$key])){
1119                 unset($attr[$key]['count']);
1120               }
1121             }
1122           }
1124           unset($attr['count']);
1125           unset($attr['dn']);
1127           /* Add marking attribute */
1128           $attr['objectClass'][] = "FAIbranch";
1129           $attr['FAIstate'] = $type;
1131           /* Add this entry */
1132           $ldap->modify($attr);
1133         }
1134       }else{
1136         /* Replicate all relevant FAI objects here.
1137          * FAI objects, Apps and Mimetypes.
1138          * Get all attributes as binary value, to ensure that Icon, File template aso
1139          *  are created correctly.
1140          */
1141         foreach($attr as $key => $value){
1143           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1144             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1145             $ei= ldap_first_entry($ldap->cid, $sr);
1146             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1147               $attr[$key] = $tmp;
1148             }
1149           }
1151           if(is_numeric($key)) unset($attr[$key]);
1152           if(isset($attr[$key]['count'])){
1153             if(is_array($attr[$key])){
1154               unset($attr[$key]['count']);
1155             }
1156           }
1157         }
1158         unset($attr['count']);
1159         unset($attr['dn']);
1160         if(!in_array("FAIobject",$attr['objectClass'])){
1161           $attr['objectClass'][] = "FAIobject";
1162         }
1163         $attr['FAIstate'] = $type;
1165         /* Add entry
1166          */
1167         $ldap->cd($destinationdn);
1168         $ldap->cat($destinationdn);
1170         $a = $ldap->fetch();
1171         if(!count($a)){
1172           $ldap->add($attr);
1173         }
1175         if(!$ldap->success()){
1177           /* Some error occurred */
1178           msg_dialog::display(_("Fatal error"),
1179               sprintf(_("Release creation failed due to ldap errors. Additional informations '%s'."),
1180                 $ldap->get_error()."<br>".$sourcedn."<br>".$destinationdn."<br>"),FATAL_ERROR_DIALOG);
1181           exit();
1182         }
1183       }
1184     }
1186     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1188     /* Prepare for recursive copy.
1189      * Get all object within the source dn and
1190      *  call the recursive copy for each.
1191      */
1192     $ldap->ls ("(objectClass=*)",$sourcedn);
1193     while ($ldap->fetch()){
1194       $deldn= $ldap->getDN();
1195       $delarray[$deldn]= strlen($deldn);
1196     }
1197     asort ($delarray);
1198     reset ($delarray);
1199     $depth ++;
1200     foreach($delarray as $dn => $bla){
1201       if($dn != $destinationdn){
1202         $ldap->cd($basedn);
1203         $item = $ldap->fetch($ldap->cat($dn));
1204         if(!in_array("FAIbranch",$item['objectClass'])){
1205           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1206         }
1207       }
1208     }
1209     if($is_first){
1210       echo "<hr>";
1211     }
1212   }
1216   /* This function returns the dn of the object release */
1217   static function get_release_dn($Current_DN)
1218   {
1219     global $config;
1220     $ldap = $config->get_ldap_link();
1221     $ldap->cd($config->current['BASE']);
1223     /* Split dn into pices */ 
1224     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$Current_DN));
1226     if(!is_array($dns_to_check)){
1227       return;  
1228     }
1230     /* Use dn pieces, to create sub dns like 
1231        ou=test,ou=1,ou=0...
1232        ou=1,ou=0...
1233        ou=0... 
1234        To check which dn is our release container.
1235      */
1236     unset($dns_to_check['count']); 
1237     while(count($dns_to_check)){
1239       /* Create dn */
1240       $new_dn = "";
1241       foreach($dns_to_check as $part){
1242         $new_dn .= $part.",";
1243       }
1244       $new_dn .= $config->current['BASE'];
1246       /* Check if this dn is a release dn */
1247       if(FAI::is_release_department($new_dn)){
1248         return($new_dn);
1249       }
1251       /* Remove first element of dn pieces */
1252       reset($dns_to_check);
1253       unset($dns_to_check[key($dns_to_check)]);
1254     }
1255     return("");
1256   }
1262 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1263 ?>