Code

Fix revision 13752 (for Trac #2697)
[gosa.git] / trunk / 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");
67         $res_tmp = get_list($filter,"fai",$fai_base,$attributes,GL_SUBSEARCH | GL_SIZELIMIT);
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           /* In detailed mode are some additonal informations visible */
101           if($detailed){
103             /* Create list of parents */
104             if(isset($res[$name])){
105               $buffer = $res[$name];
106               $buffer['parents'][] = $res[$name]['dn'];
107             }else{
108               $buffer['parents'] = array();
109             }
111             /* Append objectClass to resulsts */
112             foreach($attributes as $val){
113               if(isset($attr[$val])){
114                 $buffer[$val] = $attr[$val];
115               }
116             }
117             unset($buffer['objectClass']['count']);
118           }
120           /* Add this object to our list */
121           $buffer['dn']           = $attr['dn'];
122           $res[$name] = $buffer;
123         }
124       }
125     }
126     return($res);
127   }
130   /* Return all relevant FAI departments */
131   static function get_FAI_departments($suffix = "")
132   {
133     $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
134     $tmp = array();
135     if(preg_match("/^,/",$suffix)){
136       $suffix = preg_replace("/^,/","",$suffix);
137     }
138     foreach($arr as $name){
139       if(empty($suffix)){
140         $tmp[$name] = "ou=".$name;
141       }else{
142         $tmp[$name] = "ou=".$name.",".$suffix;
143       }
144     }
145     return($tmp);
146   }
149   /* Return all releases within the given base */
150   static function get_all_releases_from_base($dn,$appendedName=false)
151   {
152     global $config;
154     if(!preg_match("/".preg_quote(get_ou('faiBaseRDN'), '/')."/",$dn)){
155       $base = get_ou('faiBaseRDN').$dn;
156     }else{
157       $base = $dn;
158     }
159     $res = array();  
161     $ldap = $config->get_ldap_link();
162     $ldap->cd($base);
163     $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
164     while($attrs = $ldap->fetch()){
165       if($appendedName){
166         $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".preg_quote(get_ou('faiBaseRDN'), '/').".*$/","",$attrs['dn']));
167       }else{
168         $res[$attrs['dn']] = $attrs['ou'][0];
169       }
170     }
171     return($res);
172   }
175   /* Add this object to list of objects, that must be checked for release saving */
176   static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
177   {
178     /* Get ldap object */  
179     global $config;
180     $addObj['Current_DN'] = $Current_DN;
181     $addObj['objectAttrs']= $objectAttrs;
182     $addObj['removed']    = $removed;
183     $addObj['diff']       = TRUE;
185     if(!$removed){
186       $ldap = $config->get_ldap_link();
187       $ldap->cd($config->current['BASE']);
188       $parent_dn = FAI::get_parent_object($Current_DN);
190       /* Get some basic informations */
191       $parent_obj   = FAI::get_parent_release_object($Current_DN);
192       /* Check whether parent object is removed, do not create object in this case */
193       if(!empty($parent_obj) && !FAI::parent_is_removed($Current_DN)){
194         $ldap->cat($parent_obj,array("*"));
195         $attrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
197         if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
198           $addObj['diff'] = FALSE;
199         }
200       } 
201     }else{
203       /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
204           we have to remove this name from all profiles in this release.
205       */
206       $ldap = $config->get_ldap_link();
207       $ldap->cd($config->current['BASE']);
208       $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
210       /* Dont't try to modify non FAIclasses  
211        */
212       if(!preg_match("/[^,]+,".preg_quote(get_ou("faiBaseRDN"), '/')."/",$obj_dn)){
213         trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);        
214         echo "<br>-->".$Current_DN."<br>";
215         echo "<br>-->".$obj_dn."<br>";
216       }else{
218         /* Get source object and check if it is a base FAIclass
219          */
220         $ldap->cat($obj_dn);
221         $attrs = $ldap->fetch();
222         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
223         if(count(array_intersect($classes,$attrs['objectClass']))){
224           $cn    = $attrs['cn'][0];
226           /* Check if this is the last with this name in the current release.
227               In this case we have to remove the package name 
228               from all profiles in this release.
229            */
230           $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
231               "(&(objectClass=FAIclass)(cn=".$cn."))"); 
233           /* Check if this is the last class with this name.
234            */
235           if(count($classes) == 1){
237             /* Get all FAI Profiles 
238              */
239             $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
240                 "(&(objectClass=FAIprofile)(FAIclass=*))"); 
242             /* Walk though all profiles and remove the source class name
243              */
244             foreach($profiles as $dn){
245               $ldap->cat($dn['dn']);
246               $attrs = $ldap->fetch();
248               $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
250               /* Check if this Profile uses the source class ($cn)
251                */
252               if(preg_match("/".preg_quote($cn, '/')."/",$attrs['FAIclass'])){
253                 $attrs['FAIclass'] = preg_replace("/[ ]*".preg_quote($cn, '/')."[ ]*/i"," ",$attrs['FAIclass']);
254                 if(empty($attrs['FAIclass'])){
255                   $attrs['FAIclass'] = array();
256                 }
257                 $ldap->cd($dn['dn']);
258                 $ldap->modify($attrs);
260                 if (!$ldap->success()){
261                   msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
262                 }
263               }
264             }
265           }
266         }
267       }
268     }
272     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
273     $FAI_objects_to_save[$Current_DN] =  $addObj;
274     session::set('FAI_objects_to_save',$FAI_objects_to_save);
275   }
278   /* Detect differences in attribute arrays  */
279   static function array_diff_FAI($ar1,$ar2)
280   {
282     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
283       $ar1['description'] = "";
284     }
285     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
286       $ar2['description'] = "";
287     }
289     if(count($ar1) != count($ar2)) {
290       return (true);
291     }
293     foreach($ar1 as $key1 => $val1){
295       if((is_array($val1)) && (count($val1)==1)){
296         $ar1[$key1] = $val1[0];
297       }
299       if(isset($ar2[$key1])&&  (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
300         $val1 = $val1[0];
301         $ar2[$key1] = $ar2[$key1][0];
302       }
303     }
304     ksort($ar1);
305     ksort($ar2);
306     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
307       return(true);
308     }else{
309       return(false);
310     }
311   }
314   static function arr_diff($ar1,$ar2)
315   {
316     foreach($ar1 as $ak1 => $av1){
317       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
318         return(TRUE);    
319       }elseif(is_array($av1)){
320         $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
321         if($ret) {
322           return(TRUE);
323         }
324       }
325     }
326     return(FALSE);
327   }
332   /* check which objects must be saved, and save them */
333   static function save_release_changes_now()
334   {
335     global $config;
336     /* Variable init*/
337     $to_save = array();
338     
339     $reload_fai_classes = FALSE;
341     /* check which objects must be saved */
342     if(!session::is_set('FAI_objects_to_save')){
343       return;
344     }
345     $FAI_objects_to_save = session::get('FAI_objects_to_save');
346     if(!is_array($FAI_objects_to_save)) {
347       print_a(array(session::get('FAI_objects_to_save')));
348       trigger_error("Can't save FAI objects, no array given.");
349       return;
350     }
351   
352     foreach($FAI_objects_to_save as $Current_DN => $object){
353       if($object['diff']){
354         $sub_name = $Current_DN;
355         while(isset($FAI_objects_to_save[$sub_name])){
356           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
357           unset($FAI_objects_to_save[$sub_name]);
358           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
359         }
360       }
361     }
362     session::set('FAI_objects_to_save',$FAI_objects_to_save);
364     /* Sort list of objects that must be saved, and ensure that 
365        container   objects are safed, before their childs are saved */
366     ksort($to_save);
367     $tmp = array();
368     foreach($to_save as $SubObjects){
369       foreach($SubObjects as $object){
370         $tmp[] = $object;
371       }
372     }
373     $to_save = $tmp;
376     /* Save objects and manage the correct release behavior*/
377     foreach($to_save as $save){
379       $Current_DN = $save['Current_DN'];
380       $removed    = $save['removed'];
381       $objectAttrs= $save['objectAttrs'];
383       /* Get ldap object */ 
384       $ldap = $config->get_ldap_link();
385       $ldap->cd($config->current['BASE']);
387       /* Get some basic informations */
388       $base_release       = FAI::get_release_dn($Current_DN);
389       $sub_releases       = FAI::get_sub_releases_of_this_release($base_release,true);
390       $parent_obj         = FAI::get_parent_release_object($Current_DN);
391       $following_releases = $sub_releases;
393       /* Check if given dn exists or if is a new entry */
394       $ldap->cat($Current_DN);
395       if(!$ldap->count()){
396         $is_new = true;
397       }else{
398         $is_new = false;
399       }
401       /* if parameter removed is true, we have to add FAIstate to the current attrs 
402          FAIstate should end with ...|removed after this operation */  
403       if($removed ){
404         $ldap->cat($Current_DN);
406         /* Get current object, because we must add the FAIstate ...|removed */
407         if((!$ldap->count()) && !empty($parent_obj)){
408           $ldap->cat($parent_obj);
409         }
411         /* Check if we have found a suiteable object */ 
412         if(!$ldap->count()){
413           echo "Error can't remove this object ".$Current_DN;
414           return;
415         }else{
417           /* Set FAIstate to current objectAttrs */
418           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
419           if(isset($objectAttrs['FAIstate'][0])){
420             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
421               $objectAttrs['FAIstate'][0] .= "|removed";
422             }
423           }else{
424             $objectAttrs['FAIstate'][0] = "|removed";
425           }
427           /* Force reload of FAI classes */
428           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
429           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
430             $reload_fai_classes = TRUE;
431           }
432         }
433       }
435       /* Check if this a leaf release or not */ 
436       if(count($following_releases) == 0 ){
438         /* This is a leaf object. It isn't inherited by any other object */    
439         if(DEBUG_FAI_FUNC) { 
440           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
441           print_a($objectAttrs);
442         }
443         FAI::save_FAI_object($Current_DN,$objectAttrs);
445         /* Force reload of FAI classes */
446         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
447         if(count(array_intersect($classes,$objectAttrs['objectClass']))){
448           $reload_fai_classes = TRUE;
449         }
451       }else{
453         /* This object is inherited by some sub releases */  
455         /* Get all releases, that inherit this object */ 
456         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
458         /* Get parent object */
459         $ldap->cat($parent_obj);
460         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
462         /* New objects require special handling */
463         if($is_new){
465           /* Force reload of FAI classes */
466           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
467           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
468             $reload_fai_classes = TRUE;
469           }
471           /* check if there is already an entry named like this,
472              in one of our parent releases */
473           if(!empty($parent_obj)){
474             if(DEBUG_FAI_FUNC) { 
475               echo "There is already an entry named like this.</b><br>";
477               echo "<b>Saving main object</b>".$Current_DN;
478               print_a($objectAttrs);
479             }    
480             FAI::save_FAI_object($Current_DN,$objectAttrs);
482             foreach($r as $key){
483               if(DEBUG_FAI_FUNC) { 
484                 echo "<b>Saving parent to following release</b> ".$key;
485                 print_a($parent_attrs);
486               }
487               FAI::save_FAI_object($key,$parent_attrs);
488             }
489           }else{
491             if(DEBUG_FAI_FUNC) { 
492               echo "<b>Saving main object</b>".$Current_DN;
493               print_a($objectAttrs);
494             }
495             FAI::save_FAI_object($Current_DN,$objectAttrs);
497             if(isset($objectAttrs['FAIstate'])){
498               $objectAttrs['FAIstate'] .= "|removed"; 
499             }else{
500               $objectAttrs['FAIstate'] = "|removed";
501             }
503             foreach($r as $key ){
504               if(DEBUG_FAI_FUNC) { 
505                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
506                 print_a($objectAttrs);
507               }
508               /* Only save removed parent objects, not their children */
509               if (FAI::is_parent_object($Current_DN)){
510                 FAI::save_FAI_object($key,$objectAttrs);
511               }
512             }
513           }
514         }else{
516           /* check if we must patch the follwing release */
517           if(!empty($r)){
519             foreach($r as $key ){
520               if(DEBUG_FAI_FUNC) { 
521                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
522                 print_a($parent_attrs);
523               }
524              
525               /* Only update the freeze tag if the entry actually exists. */
526               $ldap->cat($key);
527               if($ldap->count()){
528                 /* Append FAIstate tag to ensure that freezed objects stay freezed
529                  */ 
530                 $rTag = FAI::get_release_tag(FAI::get_release_dn($key));
531                 $parent_attrs['FAIstate'] = $rTag;
532                 FAI::save_FAI_object($key,$parent_attrs);
533               }
534             }
535           }
537           if(DEBUG_FAI_FUNC) { 
538             echo "<b>Saving current object</b>".$parent_obj;
539             print_a($objectAttrs);
540           }
541           FAI::save_FAI_object($parent_obj,$objectAttrs);
543           if(($parent_obj != $Current_DN)){
544             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
545           }
546         }
547       }
548     }
550     /* Reload GOsa si FAI DB/cache
551      */
552     if($reload_fai_classes){
553       if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
554         $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);        
555         if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
556           $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db']; 
557           $tmp = new $evt['CLASS_NAME']($config);
558           $tmp->set_type(TRIGGERED_EVENT);
559           $tmp->add_targets(array("GOSA"));
560           $o_queue = new gosaSupportDaemon();
561           if(!$o_queue->append($tmp)){
562             msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
563           }
564         }
565       }
566     }
568     session::set('FAI_objects_to_save',array());
569   }
572   /* this function will remove all unused (deleted) objects,
573      that have no parent object */
574   static function clean_up_releases($Current_DN)
575   {
576     global $config;
577     $ldap = $config->get_ldap_link();
578     $ldap->cd($config->current['BASE']);
580     /* Collect some basic informations and initialize some variables */ 
581     $base_release       = FAI::get_release_dn($Current_DN);
582     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
583     $sub_releases       = array_keys(FAI::get_sub_releases_of_this_release($base_release,false));
584     $Kill = array();
585     $Skip = array();
587     /* We must also include the given release dn */
588     $previous_releases[] = $base_release;
590     /* Merge parent, current and child releases into one big release to 
591        iterate over */
592     $all_releases = $previous_releases;
593     foreach($sub_releases as $sub_release){
594       $all_releases[] = $sub_release;
595     }
597     /* Walk through all releases */
598     foreach($all_releases as $release){
600       /* Get fai departments */
601       $deps_to_search = FAI::get_FAI_departments($release); 
603       /* For every single department  (ou=hoos,ou ..) */
604       foreach($deps_to_search as $fai_base){
606         /* Ldap search for fai classes specified in this release */
607         $ldap->cd($fai_base);
608         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
610         /* check the returned objects, and add/replace them in our return variable */
611         while($attr = $ldap->fetch()){
613           $buffer = array();
614 #        $name = str_ireplace($release,"",$attr['dn']);
615           $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
617           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
619             /* Check if this object is required somehow */    
620             if(!isset($Skip[$name])){
621               $Kill[$attr['dn']] = $attr['dn'];
622             }
623           }else{
625             /* This object is required (not removed), so do not 
626                delete any following sub releases of this object */
627             $Skip[$name] = $attr['dn'];
628           }
629         }
630       }
631     }
632     return($Kill);
633   }
636   /* Remove numeric index and 'count' from ldap->fetch result */
637   static function prepare_ldap_fetch_to_be_saved($attrs)
638   {
639     foreach($attrs as $key => $value){
640       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
641         unset($attrs[$key]);
642       }
643       if(is_array($value) && isset($value['count'])){
644         unset($attrs[$key]['count']);
645       }
646     }
647     return($attrs);
648   }
651   /* Save given attrs to specified dn*/
652   static function save_FAI_object($dn,$attrs)
653   {
654     global $config;
655     $ldap = $config->get_ldap_link();
656     $ldap->cd($config->current['BASE']);
657     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
658     $ldap->cd($dn);
660     $ui= get_userinfo();
661     FAI::tag_attrs($attrs, $dn, $ui->gosaUnitTag);
663     $ldap->cat($dn,array("dn"));
664     if($ldap->count()){
666       /* Remove FAIstate*/
667       if(!isset($attrs['FAIstate'])){
668         $attrs['FAIstate'] = array();
669       }
671       $ldap->modify($attrs);
672     }else{
674       /* Unset description if empty  */
675       if(empty($attrs['description'])){
676         unset($attrs['description']);
677       }    
679       $ldap->add($attrs);
680     }
681     if (!$ldap->success()){
682       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
683     }
684   }
687   /* Return FAIstate freeze branch or "" for specified release department */
688   static function get_release_tag($dn)
689   {
690     global $config;
691     $ldap = $config->get_ldap_link();
692     $ldap->cd($dn);
693     $ldap->cat($dn,array("FAIstate"));
695     if($ldap->count()){
697       $attr = $ldap->fetch();
698       if(isset($attr['FAIstate'][0])){
699         if(preg_match("/freeze/",$attr['FAIstate'][0])){
700           return("freeze");
701         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
702           return("branch");
703         }
704       }
705     }
706     return("");
707   }
710   static function get_following_releases_that_inherit_this_object($dn)
711   {
712     global $config;
713     $ldap = $config->get_ldap_link();
714     $ldap->cd($config->current['BASE']);
716     $ret = array();
718     /* Get base release */
719     $base_release = FAI::get_release_dn($dn);
721     /* Get previous release dns */
722     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
724     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
725 #  $dn_suffix = str_ireplace($base_release,"",$dn);
726     $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
728     /* Check if given object also exists whitin one of these releases */
729     foreach($sub_releases as $p_release => $name){
731       $check_dn = $dn_suffix.$p_release;
733       $ldap->cat($check_dn,array("dn","objectClass"));
735       if($ldap->count()){
736         //return($ret);
737       }else{
738         $ret[$check_dn]=$check_dn;
739       }
740     }
741     return($ret);
742   }
745   /* Get previous version of the object dn */
746   static function get_parent_release_object($dn,$include_myself=true)
747   {
748     global $config;
749     $ldap = $config->get_ldap_link();
750     $ldap->cd($config->current['BASE']);
751     $previous_releases= array();
753     /* Get base release */
754     $base_release = FAI::get_release_dn($dn);
755     if($include_myself){
756       $previous_releases[] = $base_release;  
757     }
759     /* Get previous release dns */
760     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
761     foreach($tmp as $release){
762       $previous_releases[] = $release;
763     }
765     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
766 #  $dn_suffix = str_ireplace($base_release,"",$dn);
767     $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
769     /* Check if given object also exists whitin one of these releases */
770     foreach($previous_releases as $p_release){
771       $check_dn = $dn_suffix.$p_release;
772       $ldap->cat($check_dn,array("dn","objectClass"));
774       if($ldap->count()){
775         return($check_dn);
776       }
777     }
778     return("");
779   }
782   /* return release names of all parent releases */
783   static function get_previous_releases_of_this_release($dn,$flat)
784   {
785     global $config;
786     $ldap = $config->get_ldap_link();
787     $ldap->cd($config->current['BASE']);
788     $ret = array();
790     /* Explode dns into pieces, to be able to build parent dns */
791     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$dn));
793     if(!is_array($dns_to_check)){
794       return;  
795     }
797     /* Unset first entry which represents the given dn */
798     unset($dns_to_check['count']); 
799     unset($dns_to_check[key($dns_to_check)]);
801     /* Create dns addresses and check if this dn is a release dn */
802     $id = 0;
803     while(count($dns_to_check)){
805       /* build parent dn */
806       $new_dn = "";
807       foreach($dns_to_check as $part){
808         $new_dn .= $part.",";
809       }
810       $new_dn .= $config->current['BASE'];
812       /* check if this dn is a release */
813       if(FAI::is_release_department($new_dn)){
814         if($flat){
815           $ret[$id] = $new_dn; 
816         }else{
817           $ret = array($new_dn=>$ret); 
818         }
819         $id ++;
820       }else{
821         return($ret);
822       }
823       reset($dns_to_check);
824       unset($dns_to_check[key($dns_to_check)]);
825     }
826     return($ret);
827   } 
830   /* This function returns all sub release names, recursivly  */
831   static function get_sub_releases_of_this_release($dn,$flat = false)
832   {
833     global $config;
834     $res  = array();
835     $ldap = $config->get_ldap_link();
836     $ldap->cd($config->current['BASE']);
837     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
838     while($attr = $ldap->fetch()){
840       /* Append department name */
841       if($flat){
842         $res[$attr['dn']] = $attr['ou'][0];
843       }else{
844         $res[$attr['dn']] = array();
845       }
847       /* Get sub release departments of this department */
848       if(in_array("FAIbranch",$attr['objectClass'])) {
849         if($flat){
850           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
851           foreach($tmp as $dn => $value){
852             $res[$dn]=$value;
853           }
854         }else{
855           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
856         }
857       }
858     }
859     return($res);
860   }
863   /* Check if the given department is a release department */
864   static function is_release_department($dn)
865   {
866     global $config;
867     $ldap = $config->get_ldap_link();
868     $ldap->cd($config->current['BASE']);
869     $ldap->cat($dn,array("objectClass","ou"));
871     /* Check objectClasses and name to check if this is a release department */
872     if($ldap->count()){
873       $attrs = $ldap->fetch();
875       $ou = "";
876       if(isset($attrs['ou'][0])){
877         $ou = $attrs['ou'][0];  
878       }
880       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
881         return($attrs['dn']);
882       }
883     }
884     return(false);
885   }
888   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
889   {
890     global $config;
891     $start = microtime(TRUE);
892     $source_release = trim($source_release,"/");
894     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
896     $sub_releases = array();
897     $source_dn = "";
898     
899     $tmp = split("\/",$source_release);
900     foreach($tmp as $part){
901       if(empty($part)){
902         continue;
903       }
904       $source_dn            = "ou=".$part.",".$source_dn;
905       $sub_releases[$part]  = $source_dn;
906     }
908     /* Get all groups */
909     $ldap =$config->get_ldap_link();
910     $ldap->cd($config->current['BASE']);
911     $ldap->search("(objectClass=posixGroup)",array("dn"));
912     $groups = array();
913     while($attrs = $ldap->fetch()){
914       $groups[$attrs['dn']] = $attrs;
915     }
917     /* Get all FAI releases, to be able to create missing group application releases 
918         with the correct type of release (FAIstate=freeze/branch).
919      */
920     $f_releases = array();
921     $ldap->cd ($config->current['BASE']);
922     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
923     while($attrs = $ldap->fetch()){
924       foreach($sub_releases as $sub_rel){
925         if(preg_match("/^".preg_quote($sub_rel.get_ou('faiBaseRDN'), '/')."/",$attrs['dn'])){
926           $f_releases[$sub_rel.get_ou('faiBaseRDN')] = $attrs;
927         }
928       }
929     }
931     /* Get all group releases */
932     $g_releases = array();
933     foreach($groups as $dn => $data){
934       $ldap->cd($dn);
935       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
936       while($attrs = $ldap->fetch()){
937         $g_releases[$attrs['dn']] = $attrs;
938       }
939     }
941     /* Check if base releases exists.
942        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
943      */
944     foreach($sub_releases as $name => $sub_rel){
946       $FAIstate = "";
947       if(isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]) && isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'])){
948         $FAIstate = $f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'][0];
949       }
951       foreach($groups as $dn => $data){
952         if(!isset($g_releases[$sub_rel.$dn])){
953           $ldap->cd($dn);
954           $r_data = array();
955           $r_data['ou'] = $name;
956           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
957           if(!empty($FAIstate)) {
958             $r_data['FAIstate'] = $FAIstate;
959           }
960  
961           $ldap->cd($sub_rel.$dn) ;
962           $ldap->add($r_data);
963           echo "&nbsp;<b>"._("Object").":</b> ";
964           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
965           flush();
966         }
967       }
968     } 
969  
970     /* Create new release container in each group.
971      */
972     $n_data = array();
973     $n_data = array();
974     $n_data['ou'] = $destination_name;
975     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
976     if(!empty($type)){
977       $n_data['FAIstate'] = $type."/cow";
978     }
980     foreach($groups as $dn => $att){
981       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
982       if(!isset($g_releases[$n_dn])){
983         $ldap->cd ($n_dn);
984         $ldap->add($n_data);
985         echo "&nbsp;<b>"._("Object").":</b> ";
986         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
987         flush();
988       }
989     }
991     /* If the source release is empty, then create a new release by copying 
992         all group application menus into a new ou=$destination_name release container.
993       
994        If the source release is not empty. 
995          We detect all releases which match the source release dn and copy the contents.
996      */
997     if(empty($source_release)){
998       $source_dns = $groups;
999     }else{
1000       $source_dns = array();
1001       foreach($g_releases as $dn => $data){
1002         if(preg_match("/^".preg_quote($source_dn, '/')."/",$dn)){
1003           $source_dns[$dn] = $data; 
1004         }
1005       }
1006     }
1008     /* Detect all menu object we have to copy 
1009      */
1010     $to_copy = array();
1011     foreach($source_dns as $dn => $attrs){
1012       $ldap->cd($dn);
1013       $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
1014       while($attrs = $ldap->fetch()){
1015         $destination = preg_replace("/".preg_quote($dn, '/')."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
1016         $to_copy[$attrs['dn']] = $destination;
1017       }
1018     }
1019    
1020     /* At least create the menu objects object */
1021     $plug = new plugin($config);
1022     foreach($to_copy as $source => $destination){
1023       $ldap->cat($destination);
1024       if($ldap->count()){
1025         echo "&nbsp;<b>"._("Object").":</b> ";
1026         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
1027         flush();
1028       }else{
1029         $plug->copy($source,$destination);
1030         echo "&nbsp;<b>"._("Object").":</b> ";
1031         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
1032         flush();
1033       }
1034     }
1035   }
1038   /*! \brief Create a new FAI branch.
1039    *  @param $sourcedn          String  The source release dn
1040    *  @param $destinationdn     String  The destination dn
1041    *  @param $destinationName   String  The name of the new release
1042    *  @param $type              String  The release type (freeze/branch)
1043    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
1044    *  @param $depth             Integer Current depth of recursion.
1045    */
1046   static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1047   {
1048     global $config;
1049     error_reporting(E_ALL | E_STRICT);
1050     $ldap     = $config->get_ldap_link();
1051     $basedn   = $config->current['BASE'];
1052     $delarray = array();
1054     /* The following code will output a status string
1055      *  for each handled object, in a seperate iframe.
1056      */
1059     /* Display current action information.
1060      */
1061     if($is_first){
1062       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1063     }else{
1064       if(preg_match("/^ou=/",$sourcedn)){
1065         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1066       }else{
1067         $tmp = split(",",$sourcedn);
1068         echo "&nbsp;<b>"._("Object").":</b> ";
1069         $deststr = LDAP::fix($destinationdn);
1070         if(strlen($deststr) > 96){
1071           $deststr = substr($deststr,0,96)."...";
1072         }
1073         echo $deststr."<br>";
1074       }
1075     }
1076     /* .. immediately display infos */
1077     flush();
1079     /* Check if destination entry already exists
1080      */
1081     $ldap->cat($destinationdn);
1082     if($ldap->count()){
1083       echo _("Could not create new release, the destination dn is already in use.");
1084       return;
1085     }else{
1087       $ldap->clearResult();
1089       /* Get source entry
1090        *  if it does not exist, abort here.
1091        */
1092       $ldap->cd($basedn);
1093       $ldap->cat($sourcedn);
1094       $attr = $ldap->fetch();
1095       if((!$attr) || (count($attr)) ==0) {
1096         echo _("Error while fetching source dn - aborted!");
1097         return;
1098       }
1100       /* The current object we want to create is an department.
1101        * Create the department and add the FAIbranch tag.
1102        */
1103       if(in_array("organizationalUnit",$attr['objectClass'])){
1104         $attr['dn'] = LDAP::convert($destinationdn);
1105         $ldap->cd($basedn);
1106         $ldap->create_missing_trees($destinationdn);
1107         $ldap->cd($destinationdn);
1109         /* If is first entry, append FAIbranch to department entry */
1110         if($is_first){
1111           $ldap->cat($destinationdn);
1112           $attr= $ldap->fetch();
1113           /* Filter unneeded informations */
1114           foreach($attr as $key => $value){
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           }
1123           unset($attr['count']);
1124           unset($attr['dn']);
1126           /* Add marking attribute */
1127           $attr['objectClass'][] = "FAIbranch";
1128           $attr['FAIstate'] = $type;
1130           /* Add this entry */
1131           $ldap->modify($attr);
1132         }
1133       }else{
1135         /* Replicate all relevant FAI objects here.
1136          * FAI objects, Apps and Mimetypes.
1137          * Get all attributes as binary value, to ensure that Icon, File template aso
1138          *  are created correctly.
1139          */
1140         foreach($attr as $key => $value){
1142           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1143             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1144             $ei= ldap_first_entry($ldap->cid, $sr);
1145             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1146               $attr[$key] = $tmp;
1147             }
1148           }
1150           if(is_numeric($key)) unset($attr[$key]);
1151           if(isset($attr[$key]['count'])){
1152             if(is_array($attr[$key])){
1153               unset($attr[$key]['count']);
1154             }
1155           }
1156         }
1157         unset($attr['count']);
1158         unset($attr['dn']);
1159         if(!in_array("FAIobject",$attr['objectClass'])){
1160           $attr['objectClass'][] = "FAIobject";
1161         }
1162         $attr['FAIstate'] = $type;
1164         /* Add entry
1165          */
1166         $ldap->cd($destinationdn);
1167         $ldap->cat($destinationdn);
1169         $a = $ldap->fetch();
1170         if(!count($a)){
1171           $ldap->add($attr);
1172         }
1174         if(!$ldap->success()){
1176           /* Some error occurred */
1177           msg_dialog::display(_("Fatal error"),
1178               sprintf(_("Release creation failed due to ldap errors. Additional informations '%s'."),
1179                 $ldap->get_error()."<br>".$sourcedn."<br>".$destinationdn."<br>"),FATAL_ERROR_DIALOG);
1180           exit();
1181         }
1182       }
1183     }
1185     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1187     /* Prepare for recursive copy.
1188      * Get all object within the source dn and
1189      *  call the recursive copy for each.
1190      */
1191     $ldap->ls ("(objectClass=*)",$sourcedn);
1192     while ($ldap->fetch()){
1193       $deldn= $ldap->getDN();
1194       $delarray[$deldn]= strlen($deldn);
1195     }
1196     asort ($delarray);
1197     reset ($delarray);
1198     $depth ++;
1199     foreach($delarray as $dn => $bla){
1200       if($dn != $destinationdn){
1201         $ldap->cd($basedn);
1202         $item = $ldap->fetch($ldap->cat($dn));
1203         if(!in_array("FAIbranch",$item['objectClass'])){
1204           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1205         }
1206       }
1207     }
1208     if($is_first){
1209       echo "<p class='seperator'>&nbsp;</p>";
1210     }
1211   }
1215   /* This function returns the dn of the object release */
1216   static function get_release_dn($Current_DN)
1217   {
1218     global $config;
1219     $ldap = $config->get_ldap_link();
1220     $ldap->cd($config->current['BASE']);
1222     /* Split dn into pices */ 
1223     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$Current_DN));
1225     if(!is_array($dns_to_check)){
1226       return;  
1227     }
1229     /* Use dn pieces, to create sub dns like 
1230        ou=test,ou=1,ou=0...
1231        ou=1,ou=0...
1232        ou=0... 
1233        To check which dn is our release container.
1234      */
1235     unset($dns_to_check['count']); 
1236     while(count($dns_to_check)){
1238       /* Create dn */
1239       $new_dn = "";
1240       foreach($dns_to_check as $part){
1241         $new_dn .= $part.",";
1242       }
1243       $new_dn .= $config->current['BASE'];
1245       /* Check if this dn is a release dn */
1246       if(FAI::is_release_department($new_dn)){
1247         return($new_dn);
1248       }
1250       /* Remove first element of dn pieces */
1251       reset($dns_to_check);
1252       unset($dns_to_check[key($dns_to_check)]);
1253     }
1254     return("");
1255   }
1258   static function tag_attrs(&$at, $dn= "", $tag= "", $show= false)
1259   {                                                        
1260     /* Remove tags that may already be here... */                         
1261     remove_objectClass("gosaAdministrativeUnitTag", $at);                 
1262     if (isset($at['gosaUnitTag'])){                                       
1263         unset($at['gosaUnitTag']);                                        
1264     }                                                                     
1266     /* Set tag? */
1267     if ($tag != ""){
1268       add_objectClass("gosaAdministrativeUnitTag", $at);
1269       $at['gosaUnitTag']= $tag;                         
1270     }                                                   
1272     /* Initially this object was tagged. 
1273        - But now, it is no longer inside a tagged department. 
1274        So force the remove of the tag.                        
1275        (objectClass was already removed obove)                
1276      */                                                       
1277     if($tag == ""){                     
1278       $at['gosaUnitTag'] = array();                           
1279     }                                                         
1280   }                                                           
1282   /* Returns true if this is a parent object, e.g. FAIpartitionTable, not FAIpartitionDisk */
1283   static function is_parent_object($dn)
1284   {
1285     global $config;
1286     $Current_DN = $dn;
1288     /* special case partitions, as they don't start with cn= in their DN (schema bug?) */
1289     if (preg_match('/^FAIpartitionNr=/', $Current_DN)){
1290       return false;
1291     }
1293     $parent_dn = preg_replace('/^cn=[^,.]*,/', '', $Current_DN);
1294     if (preg_match('/^cn=/', $parent_dn)) {
1295       $ldap = $config->get_ldap_link();
1296       $ldap->cd($config->current['BASE']);
1297       $ldap->cat($parent_dn);
1298       if($ldap->count()){
1299         return false;
1300       }
1301     }else{
1302       return true;
1303     }
1304   }
1306   /* Return a child objects, if there are any */
1307   static function get_child_objects($dn)
1308   {
1309     global $config;
1310     $Current_DN = $dn;
1311     $children= array();
1313     if (FAI::is_parent_object($Current_DN)){
1314       $ldap = $config->get_ldap_link();
1315       $ldap->cd($config->current['BASE']);
1316       $ldap->search("(objectClass=FAIclass)",array("dn"));
1317       while($attrs = $ldap->fetch()){
1318         $newdn=$attrs['dn'];
1319         if(preg_match("/".preg_quote($Current_DN, '/')."/",$attrs['dn']) && $attrs['dn'] != $Current_DN){
1320           $children[] = $attrs['dn'];
1321         }
1322       }
1323     }
1324     return $children;
1325   }
1327   /* Get the DN of the parent object; e.g. the FAIpartitionTable of a FAIpartitionDisk */
1328   static function get_parent_object($dn)
1329   {
1330     global $config;
1331     $Current_DN = $dn;
1333     $tmp_dn = $Current_DN;
1334     $parent_dn = $tmp_dn;
1336     /* special case partitions, as they don't start with cn= in their DN (schema bug?) */
1337     $tmp_dn = preg_replace('/^FAIpartitionNr=/', 'cn=', $tmp_dn);
1339     while (preg_match('/^cn=/', $tmp_dn)){
1340       $parent_dn = $tmp_dn;
1341       $tmp_dn = preg_replace('/^cn=[^,.]*,/', '', $parent_dn);
1342     }
1343     if ($parent_dn != $Current_DN){
1344       $ldap = $config->get_ldap_link();
1345       $ldap->cd($config->current['BASE']);
1346       $ldap->cat($parent_dn);
1348       /* Check objectClasses and name to check if this is a release department */
1349       if($ldap->count()){
1350         return $parent_dn;
1351       }
1352     }
1353     return "";
1354   }
1356   /* Check whether parent object is removed */
1357   static function parent_is_removed($dn)
1358   {
1359     global $config;
1360     $Current_DN = $dn;
1362     $ldap = $config->get_ldap_link();
1363     $parent_dn = FAI::get_parent_object($Current_DN);
1364     if ($parent_dn) { 
1365       $ldap->cd($config->current['BASE']);
1366       $ldap->cat($parent_dn);
1367       $parentObjectAttrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
1368       if(isset($parentObjectAttrs['FAIstate'][0])){
1369         if(preg_match("/removed$/",$parentObjectAttrs['FAIstate'][0])){
1370           return true;
1371         }
1372       }
1373     } 
1374     return false;
1375   }
1381 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1382 ?>