Code

1fef153b638bc87723acf6a0508d7f0c0725b73e
[gosa.git] / gosa-plugins / fai / admin / fai / class_FAI.inc
1 <?php
3 define("DEBUG_FAI_FUNC",FALSE);
6 class FAI
7 {
9   /* TEST PHASE .... */
11   /* Returns all object for the given release.
12      This function resolves the releases  
13      from base up to the given dn.
14    */
15   static function get_all_objects_for_given_base($Current_DN,$filter,$detailed = false)
16   {
17     global $config;
18     $ldap = $config->get_ldap_link();
19     $ldap->cd($config->current['BASE']);
20     $res = array();
21     $tmp = array();
23     if(!FAI::is_release_department($Current_DN)) {
24       return($res);
25     }
27     /* Collect some basic informations and initialize some variables */ 
28     $base_release       = FAI::get_release_dn($Current_DN);
29     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
31     /* We must also include the given release dn */
32     $previous_releases[] = $base_release;
34     /* Walk through all releases */
35     foreach($previous_releases as $release){
37       /* Get fai departments */
38       $deps_to_search = FAI::get_FAI_departments($release); 
40       /* For every single department  (ou=hoos,ou ..) */
41       foreach($deps_to_search as $fai_base){
43         /* Ldap search for fai classes specified in this release */
44         $attributes  = array("dn","objectClass","FAIstate","cn");
45         $res_tmp = get_list($filter,"fai",$fai_base,$attributes,GL_SUBSEARCH | GL_SIZELIMIT);
47         /* check the returned objects, and add/replace them in our return variable */
48         foreach($res_tmp as $attr){
50           $buffer = array();
51           $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
53           if(isset($attr['FAIstate'][0])){
54             if(preg_match("/removed$/",$attr['FAIstate'][0])){
55               if(isset($res[$name])){
56                 unset($res[$name]);
57               }
58               continue;
59             }
60           }
62           /* In detailed mode are some additonal informations visible */
63           if($detailed){
65             /* Create list of parents */
66             if(isset($res[$name])){
67               $buffer = $res[$name];
68               $buffer['parents'][] = $res[$name]['dn'];
69             }else{
70               $buffer['parents'] = array();
71             }
73             /* Append objectClass to resulsts */
74             foreach($attributes as $val){
75               if(isset($attr[$val])){
76                 $buffer[$val] = $attr[$val];
77               }
78             }
79             unset($buffer['objectClass']['count']);
80           }
82           /* Add this object to our list */
83           $buffer['dn']           = $attr['dn'];
84           $res[$name] = $buffer;
85         }
86       }
87     }
88     return($res);
89   }
92   /* Return all relevant FAI departments */
93   static function get_FAI_departments($suffix = "")
94   {
95     $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
96     $tmp = array();
97     if(preg_match("/^,/",$suffix)){
98       $suffix = preg_replace("/^,/","",$suffix);
99     }
100     foreach($arr as $name){
101       if(empty($suffix)){
102         $tmp[$name] = "ou=".$name;
103       }else{
104         $tmp[$name] = "ou=".$name.",".$suffix;
105       }
106     }
107     return($tmp);
108   }
111   /* Return all releases within the given base */
112   static function get_all_releases_from_base($dn,$appendedName=false)
113   {
114     global $config;
116     if(!preg_match("/".normalizePreg(get_ou('faiou'))."/",$dn)){
117       $base = get_ou('faiou').$dn;
118     }else{
119       $base = $dn;
120     }
121     $res = array();  
123     $ldap = $config->get_ldap_link();
124     $ldap->cd($base);
125     $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
126     while($attrs = $ldap->fetch()){
127       if($appendedName){
128         $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".normalizePreg(get_ou('faiou')).".*$/","",$attrs['dn']));
129       }else{
130         $res[$attrs['dn']] = $attrs['ou'][0];
131       }
132     }
133     return($res);
134   }
137   /* Add this object to list of objects, that must be checked for release saving */
138   static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
139   {
140     /* Get ldap object */  
141     global $config;
142     $addObj['Current_DN'] = $Current_DN;
143     $addObj['objectAttrs']= $objectAttrs;
144     $addObj['removed']    = $removed;
145     $addObj['diff']       = TRUE;
147     if(!$removed){
148       $ldap = $config->get_ldap_link();
149       $ldap->cd($config->current['BASE']);
151       /* Get some basic informations */
152       $parent_obj   = FAI::get_parent_release_object($Current_DN);
153       if(!empty($parent_obj)){
154         $ldap->cat($parent_obj,array("*"));
155         $attrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
157         if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
158           $addObj['diff'] = FALSE;
159         }
160       } 
161     }else{
163       /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
164           we have to remove this name from all profiles in this release.
165       */
166       $ldap = $config->get_ldap_link();
167       $ldap->cd($config->current['BASE']);
168       $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
170       /* Dont't try to modify non FAIclasses  
171        */
172       if(!preg_match("/[^,]+,".normalizePreg(get_ou("faiou"))."/",$obj_dn)){
173         echo "PLEASE check fai class handling in ".__LINE__." -> ".__FILE__;        
174       }else{
176         /* Get source object and check if it is a base FAIclass
177          */
178         $ldap->cat($obj_dn);
179         $attrs = $ldap->fetch();
180         $classes = array("FAIprofile","FAIscript","FAIpackage","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
181         if(count(array_intersect($classes,$attrs['objectClass']))){
182           $cn    = $attrs['cn'][0];
184           /* Check if this is the last with this name in the current release.
185               In this case we have to remove the package name 
186               from all profiles in this release.
187            */
188           $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
189               "(&(objectClass=FAIclass)(cn=".$cn."))"); 
191           /* Check if this is the last class with this name.
192            */
193           if(count($classes) == 1){
195             /* Get all FAI Profiles 
196              */
197             $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
198                 "(&(objectClass=FAIprofile)(FAIclass=*))"); 
200             /* Walk though all profiles and remove the source class name
201              */
202             foreach($profiles as $dn){
203               $ldap->cat($dn['dn']);
204               $attrs = $ldap->fetch();
206               $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
208               /* Check if this Profile uses the source class ($cn)
209                */
210               if(preg_match("/".normalizePreg($cn)."/",$attrs['FAIclass'])){
211                 $attrs['FAIclass'] = preg_replace("/[ ]*".normalizePreg($cn)."[ ]*/i"," ",$attrs['FAIclass']);
212                 if(empty($attrs['FAIclass'])){
213                   $attrs['FAIclass'] = array();
214                 }
215                 $ldap->cd($dn['dn']);
216                 $ldap->modify($attrs);
218                 if (!$ldap->success()){
219                   msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
220                 }
221               }
222             }
223           }
224         }
225       }
226     }
230     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
231     $FAI_objects_to_save[$Current_DN] =  $addObj;
232     session::set('FAI_objects_to_save',$FAI_objects_to_save);
233   }
236   /* Detect differences in attribute arrays  */
237   static function array_diff_FAI($ar1,$ar2)
238   {
240     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
241       $ar1['description'] = "";
242     }
243     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
244       $ar2['description'] = "";
245     }
247     if(count($ar1) != count($ar2)) {
248       return (true);
249     }
251     foreach($ar1 as $key1 => $val1){
253       if((is_array($val1)) && (count($val1)==1)){
254         $ar1[$key1] = $val1[0];
255       }
257       if(isset($ar2[$key1])&&  (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
258         $val1 = $val1[0];
259         $ar2[$key1] = $ar2[$key1][0];
260       }
261     }
262     ksort($ar1);
263     ksort($ar2);
264     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
265       return(true);
266     }else{
267       return(false);
268     }
269   }
272   static function arr_diff($ar1,$ar2)
273   {
274     foreach($ar1 as $ak1 => $av1){
275       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
276         return(true);
277       }elseif(is_array($av1)){
278         return(FAI::arr_diff($av1,$ar2[$ak1]));
279       }
280     }
281     return(FALSE);
282   }
287   /* check which objects must be saved, and save them */
288   static function save_release_changes_now()
289   {
290     /* Variable init*/
291     $to_save = array();
293     /* check which objects must be saved */
294     $FAI_objects_to_save = session::get('FAI_objects_to_save');
295     if(!is_array($FAI_objects_to_save)) {
296       trigger_error("Can't save FAI objects, no array given.");
297       return;
298     }
299     foreach($FAI_objects_to_save as $Current_DN => $object){
300       if($object['diff']){
301         $sub_name = $Current_DN;
302         while(isset($FAI_objects_to_save[$sub_name])){
303           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
304           unset($FAI_objects_to_save[$sub_name]);
305           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
306         }
307       }
308     }
309     session::set('FAI_objects_to_save',$FAI_objects_to_save);
311     /* Sort list of objects that must be saved, and ensure that 
312        container   objects are safed, before their childs are saved */
313     ksort($to_save);
314     $tmp = array();
315     foreach($to_save as $SubObjects){
316       foreach($SubObjects as $object){
317         $tmp[] = $object;
318       }
319     }
320     $to_save = $tmp;
322     /* Save objects and manage the correct release behavior*/
323     foreach($to_save as $save){
325       $Current_DN = $save['Current_DN'];
326       $removed    = $save['removed'];
327       $objectAttrs= $save['objectAttrs'];
329       /* Get ldap object */ 
330       global $config;
331       $ldap = $config->get_ldap_link();
332       $ldap->cd($config->current['BASE']);
334       /* Get some basic informations */
335       $base_release       = FAI::get_release_dn($Current_DN);
336       $sub_releases       = FAI::                       get_sub_releases_of_this_release($base_release,true);
337       $parent_obj         = FAI::get_parent_release_object($Current_DN);
338       $following_releases = FAI::                       get_sub_releases_of_this_release($base_release,true);
340       /* Check if given dn exists or if is a new entry */
341       $ldap->cat($Current_DN);
342       if(!$ldap->count()){
343         $is_new = true;
344       }else{
345         $is_new = false;
346       }
348       /* if parameter removed is true, we have to add FAIstate to the current attrs 
349          FAIstate should end with ...|removed after this operation */  
350       if($removed ){
351         $ldap->cat($Current_DN);
353         /* Get current object, because we must add the FAIstate ...|removed */
354         if((!$ldap->count()) && !empty($parent_obj)){
355           $ldap->cat($parent_obj);
356         }
358         /* Check if we have found a suiteable object */ 
359         if(!$ldap->count()){
360           echo "Error can't remove this object ".$Current_DN;
361           return;
362         }else{
364           /* Set FAIstate to current objectAttrs */
365           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
366           if(isset($objectAttrs['FAIstate'][0])){
367             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
368               $objectAttrs['FAIstate'][0] .= "|removed";
369             }
370           }else{
371             $objectAttrs['FAIstate'][0] = "|removed";
372           }
373         }
374       }
376       /* Check if this a leaf release or not */ 
377       if(count($following_releases) == 0 ){
379         /* This is a leaf object. It isn't inherited by any other object */    
380         if(DEBUG_FAI_FUNC) { 
381           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
382           print_a($objectAttrs);
383         }
384         FAI::save_FAI_object($Current_DN,$objectAttrs);
385       }else{
387         /* This object is inherited by some sub releases */  
389         /* Get all releases, that inherit this object */ 
390         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
392         /* Get parent object */
393         $ldap->cat($parent_obj);
394         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
396         /* New objects require special handling */
397         if($is_new){
399           /* check if there is already an entry named like this,
400              in one of our parent releases */
401           if(!empty($parent_obj)){
402             if(DEBUG_FAI_FUNC) { 
403               echo "There is already an entry named like this.</b><br>";
405               echo "<b>Saving main object</b>".$Current_DN;
406               print_a($objectAttrs);
407             }    
408             FAI::save_FAI_object($Current_DN,$objectAttrs);
410             foreach($r as $key){
411               if(DEBUG_FAI_FUNC) { 
412                 echo "<b>Saving parent to following release</b> ".$key;
413                 print_a($parent_attrs);
414               }
415               FAI::save_FAI_object($key,$parent_attrs);
416             }
417           }else{
419             if(DEBUG_FAI_FUNC) { 
420               echo "<b>Saving main object</b>".$Current_DN;
421               print_a($objectAttrs);
422             }
423             FAI::save_FAI_object($Current_DN,$objectAttrs);
425             if(isset($objectAttrs['FAIstate'])){
426               $objectAttrs['FAIstate'] .= "|removed"; 
427             }else{
428               $objectAttrs['FAIstate'] = "|removed";
429             }
431             foreach($r as $key ){
432               if(DEBUG_FAI_FUNC) { 
433                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
434                 print_a($objectAttrs);
435               }
436               FAI::save_FAI_object($key,$objectAttrs);
437             }
438           }
439         }else{
441           /* check if we must patch the follwing release */
442           if(!empty($r)){
443             foreach($r as $key ){
444               if(DEBUG_FAI_FUNC) { 
445                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
446                 print_a($parent_attrs);
447               }
448               FAI::save_FAI_object($key,$parent_attrs);
449             }
450           }
452           if(DEBUG_FAI_FUNC) { 
453             echo "<b>Saving current object</b>".$parent_obj;
454             print_a($objectAttrs);
455           }
456           FAI::save_FAI_object($parent_obj,$objectAttrs);
458           if(($parent_obj != $Current_DN)){
459             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
460           }
461         }
462       }
463     } 
464     session::set('FAI_objects_to_save',array());
465   }
468   /* this function will remove all unused (deleted) objects,
469      that have no parent object */
470   static function clean_up_releases($Current_DN)
471   {
472     global $config;
473     $ldap = $config->get_ldap_link();
474     $ldap->cd($config->current['BASE']);
476     /* Collect some basic informations and initialize some variables */ 
477     $base_release       = FAI::get_release_dn($Current_DN);
478     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
479     $Kill = array();
480     $Skip = array();
482     /* We must also include the given release dn */
483     $previous_releases[] = $base_release;
485     /* Walk through all releases */
486     foreach($previous_releases as $release){
488       /* Get fai departments */
489       $deps_to_search = FAI::get_FAI_departments($release); 
491       /* For every single department  (ou=hoos,ou ..) */
492       foreach($deps_to_search as $fai_base){
494         /* Ldap search for fai classes specified in this release */
495         $ldap->cd($fai_base);
496         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
498         /* check the returned objects, and add/replace them in our return variable */
499         while($attr = $ldap->fetch()){
501           $buffer = array();
502 #        $name = str_ireplace($release,"",$attr['dn']);
503           $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
505           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
507             /* Check if this object is required somehow */    
508             if(!isset($Skip[$name])){
509               $Kill[$attr['dn']] = $attr['dn'];
510             }
511           }else{
513             /* This object is required (not removed), so do not 
514                delete any following sub releases of this object */
515             $Skip[$name] = $attr['dn'];
516           }
517         }
518       }
519     }
520     return($Kill);
521   }
524   /* Remove numeric index and 'count' from ldap->fetch result */
525   static function prepare_ldap_fetch_to_be_saved($attrs)
526   {
527     foreach($attrs as $key => $value){
528       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
529         unset($attrs[$key]);
530       }
531       if(is_array($value) && isset($value['count'])){
532         unset($attrs[$key]['count']);
533       }
534     }
535     return($attrs);
536   }
539   /* Save given attrs to specified dn*/
540   static function save_FAI_object($dn,$attrs)
541   {
542     global $config;
543     $ldap = $config->get_ldap_link();
544     $ldap->cd($config->current['BASE']);
545     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
546     $ldap->cd($dn);
548     $ldap->cat($dn,array("dn"));
549     if($ldap->count()){
551       /* Remove FAIstate*/
552       if(!isset($attrs['FAIstate'])){
553         $attrs['FAIstate'] = array();
554       }
556       $ldap->modify($attrs);
557     }else{
559       /* Unset description if empty  */
560       if(empty($attrs['description'])){
561         unset($attrs['description']);
562       }    
564       $ldap->add($attrs);
565     }
566     if (!$ldap->success()){
567       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
568     }
569   }
572   /* Return FAIstate freeze branch or "" for specified release department */
573   static function get_release_tag($dn)
574   {
575     global $config;
576     $ldap = $config->get_ldap_link();
577     $ldap->cd($dn);
578     $ldap->cat($dn,array("FAIstate"));
580     if($ldap->count()){
582       $attr = $ldap->fetch();
583       if(isset($attr['FAIstate'][0])){
584         if(preg_match("/freeze/",$attr['FAIstate'][0])){
585           return("freeze");
586         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
587           return("branch");
588         }
589       }
590     }
591     return("");
592   }
595   static function get_following_releases_that_inherit_this_object($dn)
596   {
597     global $config;
598     $ldap = $config->get_ldap_link();
599     $ldap->cd($config->current['BASE']);
601     $ret = array();
603     /* Get base release */
604     $base_release = FAI::get_release_dn($dn);
606     /* Get previous release dns */
607     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
609     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
610 #  $dn_suffix = str_ireplace($base_release,"",$dn);
611     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
613     /* Check if given object also exists whitin one of these releases */
614     foreach($sub_releases as $p_release => $name){
616       $check_dn = $dn_suffix.$p_release;
618       $ldap->cat($check_dn,array("dn","objectClass"));
620       if($ldap->count()){
621         //return($ret);
622       }else{
623         $ret[$check_dn]=$check_dn;
624       }
625     }
626     return($ret);
627   }
630   /* Get previous version of the object dn */
631   static function get_parent_release_object($dn,$include_myself=true)
632   {
633     global $config;
634     $ldap = $config->get_ldap_link();
635     $ldap->cd($config->current['BASE']);
636     $previous_releases= array();
638     /* Get base release */
639     $base_release = FAI::get_release_dn($dn);
640     if($include_myself){
641       $previous_releases[] = $base_release;  
642     }
644     /* Get previous release dns */
645     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
646     foreach($tmp as $release){
647       $previous_releases[] = $release;
648     }
650     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
651 #  $dn_suffix = str_ireplace($base_release,"",$dn);
652     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
654     /* Check if given object also exists whitin one of these releases */
655     foreach($previous_releases as $p_release){
656       $check_dn = $dn_suffix.$p_release;
657       $ldap->cat($check_dn,array("dn","objectClass"));
659       if($ldap->count()){
660         return($check_dn);
661       }
662     }
663     return("");
664   }
667   /* return release names of all parent releases */
668   static function get_previous_releases_of_this_release($dn,$flat)
669   {
670     global $config;
671     $ldap = $config->get_ldap_link();
672     $ldap->cd($config->current['BASE']);
673     $ret = array();
675     /* Explode dns into pieces, to be able to build parent dns */
676     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
678     if(!is_array($dns_to_check)){
679       return;  
680     }
682     /* Unset first entry which represents the given dn */
683     unset($dns_to_check['count']); 
684     unset($dns_to_check[key($dns_to_check)]);
686     /* Create dns addresses and check if this dn is a release dn */
687     $id = 0;
688     while(count($dns_to_check)){
690       /* build parent dn */
691       $new_dn = "";
692       foreach($dns_to_check as $part){
693         $new_dn .= $part.",";
694       }
695       $new_dn .= $config->current['BASE'];
697       /* check if this dn is a release */
698       if(FAI::is_release_department($new_dn)){
699         if($flat){
700           $ret[$id] = $new_dn; 
701         }else{
702           $ret = array($new_dn=>$ret); 
703         }
704         $id ++;
705       }else{
706         return($ret);
707       }
708       reset($dns_to_check);
709       unset($dns_to_check[key($dns_to_check)]);
710     }
711     return($ret);
712   } 
715   /* This function returns all sub release names, recursivly  */
716   static function get_sub_releases_of_this_release($dn,$flat = false)
717   {
718     global $config;
719     $res  = array();
720     $ldap = $config->get_ldap_link();
721     $ldap->cd($config->current['BASE']);
722     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
723     while($attr = $ldap->fetch()){
725       /* Append department name */
726       if($flat){
727         $res[$attr['dn']] = $attr['ou'][0];
728       }else{
729         $res[$attr['dn']] = array();
730       }
732       /* Get sub release departments of this department */
733       if(in_array("FAIbranch",$attr['objectClass'])) {
734         if($flat){
735           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
736           foreach($tmp as $dn => $value){
737             $res[$dn]=$value;
738           }
739         }else{
740           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
741         }
742       }
743     }
744     return($res);
745   }
748   /* Check if the given department is a release department */
749   static function is_release_department($dn)
750   {
751     global $config;
752     $ldap = $config->get_ldap_link();
753     $ldap->cd($config->current['BASE']);
754     $ldap->cat($dn,array("objectClass","ou"));
756     /* Check objectClasses and name to check if this is a release department */
757     if($ldap->count()){
758       $attrs = $ldap->fetch();
760       $ou = "";
761       if(isset($attrs['ou'][0])){
762         $ou = $attrs['ou'][0];  
763       }
765       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
766         return($attrs['dn']);
767       }
768     }
769     return(false);
770   }
773   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
774   {
775     global $config;
776     $start = microtime(TRUE);
777     $source_release = trim($source_release,"/");
779     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
781     $sub_releases = array();
782     $source_dn = "";
783     
784     $tmp = split("\/",$source_release);
785     foreach($tmp as $part){
786       if(empty($part)){
787         continue;
788       }
789       $source_dn            = "ou=".$part.",".$source_dn;
790       $sub_releases[$part]  = $source_dn;
791     }
793     /* Get all groups */
794     $ldap =$config->get_ldap_link();
795     $ldap->cd($config->current['BASE']);
796     $ldap->search("(objectClass=posixGroup)",array("dn"));
797     $groups = array();
798     while($attrs = $ldap->fetch()){
799       $groups[$attrs['dn']] = $attrs;
800     }
802     /* Get all FAI releases, to be able to create missing group application releases 
803         with the correct type of release (FAIstate=freeze/branch).
804      */
805     $f_releases = array();
806     $ldap->cd ($config->current['BASE']);
807     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
808     while($attrs = $ldap->fetch()){
809       foreach($sub_releases as $sub_rel){
810         if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
811           $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
812         }
813       }
814     }
816     /* Get all group releases */
817     $g_releases = array();
818     foreach($groups as $dn => $data){
819       $ldap->cd($dn);
820       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
821       while($attrs = $ldap->fetch()){
822         $g_releases[$attrs['dn']] = $attrs;
823       }
824     }
826     /* Check if base releases exists.
827        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
828      */
829     foreach($sub_releases as $name => $sub_rel){
831       $FAIstate = "";
832       if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
833         $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
834       }
836       foreach($groups as $dn => $data){
837         if(!isset($g_releases[$sub_rel.$dn])){
838           $ldap->cd($dn);
839           $r_data = array();
840           $r_data['ou'] = $name;
841           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
842           if(!empty($FAIstate)) {
843             $r_data['FAIstate'] = $FAIstate;
844           }
845  
846           $ldap->cd($sub_rel.$dn) ;
847           $ldap->add($r_data);
848           echo "&nbsp;<b>"._("Object").":</b> ";
849           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
850           flush();
851         }
852       }
853     } 
854  
855     /* Create new release container in each group.
856      */
857     $n_data = array();
858     $n_data = array();
859     $n_data['ou'] = $destination_name;
860     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
861     if(!empty($type)){
862       $n_data['FAIstate'] = $type."/cow";
863     }
865     foreach($groups as $dn => $att){
866       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
867       if(!isset($g_releases[$n_dn])){
868         $ldap->cd ($n_dn);
869         $ldap->add($n_data);
870         echo "&nbsp;<b>"._("Object").":</b> ";
871         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
872         flush();
873       }
874     }
876     /* If the source release is empty, then create a new release by copying 
877         all group application menus into a new ou=$destination_name release container.
878       
879        If the source release is not empty. 
880          We detect all releases which match the source release dn and copy the contents.
881      */
882     if(empty($source_release)){
883       $source_dns = $groups;
884     }else{
885       $source_dns = array();
886       foreach($g_releases as $dn => $data){
887         if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
888           $source_dns[$dn] = $data; 
889         }
890       }
891     }
893     /* Detect all menu object we have to copy 
894      */
895     $to_copy = array();
896     foreach($source_dns as $dn => $attrs){
897       $ldap->cd($dn);
898       $ldap->ls("(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry)",$dn,array("dn"));
899       while($attrs = $ldap->fetch()){
900         $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
901         $to_copy[$attrs['dn']] = $destination;
902       }
903     }
904    
905     /* At least create the menu objects object */
906     $plug = new plugin($config);
907     foreach($to_copy as $source => $destination){
908       $ldap->cat($destination);
909       if($ldap->count()){
910         echo "&nbsp;<b>"._("Object").":</b> ";
911         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
912         flush();
913       }else{
914         $plug->copy($source,$destination);
915         echo "&nbsp;<b>"._("Object").":</b> ";
916         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
917         flush();
918       }
919     }
920   }
923   /*! \brief Create a new FAI branch.
924    *  @param $sourcedn          String  The source release dn
925    *  @param $destinationdn     String  The destination dn
926    *  @param $destinationName   String  The name of the new release
927    *  @param $type              String  The release type (freeze/branch)
928    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
929    *  @param $depth             Integer Current depth of recursion.
930    */
931   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
932   {
933     global $config;
934     error_reporting(E_ALL | E_STRICT);
935     $ldap     = $config->get_ldap_link();
936     $basedn   = $config->current['BASE'];
937     $delarray = array();
939     /* The following code will output a status string
940      *  for each handled object, in a seperate iframe.
941      */
944     /* Display current action information.
945      */
946     if($is_first){
947       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
948     }else{
949       if(preg_match("/^ou=/",$sourcedn)){
950         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
951       }else{
952         $tmp = split(",",$sourcedn);
953         echo "&nbsp;<b>"._("Object").":</b> ";
954         $deststr = LDAP::fix($destinationdn);
955         if(strlen($deststr) > 96){
956           $deststr = substr($deststr,0,96)."...";
957         }
958         echo $deststr."<br>";
959       }
960     }
961     /* .. immediately display infos */
962     flush();
964     /* Check if destination entry already exists
965      */
966     $ldap->cat($destinationdn);
967     if($ldap->count()){
968       echo _("Could not create new release, the destination dn is already in use.");
969       return;
970     }else{
972       $ldap->clearResult();
974       /* Get source entry
975        *  if it does not exist, abort here.
976        */
977       $ldap->cd($basedn);
978       $ldap->cat($sourcedn);
979       $attr = $ldap->fetch();
980       if((!$attr) || (count($attr)) ==0) {
981         echo _("Error while fetching source dn - aborted!");
982         return;
983       }
985       /* The current object we want to create is an department.
986        * Create the department and add the FAIbranch tag.
987        */
988       if(in_array("organizationalUnit",$attr['objectClass'])){
989         $attr['dn'] = LDAP::convert($destinationdn);
990         $ldap->cd($basedn);
991         $ldap->create_missing_trees($destinationdn);
992         $ldap->cd($destinationdn);
994         /* If is first entry, append FAIbranch to department entry */
995         if($is_first){
996           $ldap->cat($destinationdn);
997           $attr= $ldap->fetch();
998           /* Filter unneeded informations */
999           foreach($attr as $key => $value){
1000             if(is_numeric($key)) unset($attr[$key]);
1001             if(isset($attr[$key]['count'])){
1002               if(is_array($attr[$key])){
1003                 unset($attr[$key]['count']);
1004               }
1005             }
1006           }
1008           unset($attr['count']);
1009           unset($attr['dn']);
1011           /* Add marking attribute */
1012           $attr['objectClass'][] = "FAIbranch";
1014           /* Add this entry */
1015           $ldap->modify($attr);
1016         }
1017       }else{
1019         /* Replicate all relevant FAI objects here.
1020          * FAI objects, Apps and Mimetypes.
1021          * Get all attributes as binary value, to ensure that Icon, File template aso
1022          *  are created correctly.
1023          */
1024         foreach($attr as $key => $value){
1026           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1027             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1028             $ei= ldap_first_entry($ldap->cid, $sr);
1029             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1030               $attr[$key] = $tmp;
1031             }
1032           }
1034           if(is_numeric($key)) unset($attr[$key]);
1035           if(isset($attr[$key]['count'])){
1036             if(is_array($attr[$key])){
1037               unset($attr[$key]['count']);
1038             }
1039           }
1040         }
1041         unset($attr['count']);
1042         unset($attr['dn']);
1044         /* Add entry
1045          */
1046         $ldap->cd($destinationdn);
1047         $ldap->cat($destinationdn);
1049         $a = $ldap->fetch();
1050         if(!count($a)){
1051           $ldap->add($attr);
1052         }
1054         if(!$ldap->success()){
1056           /* Some error occurred */
1057           print "---------------------------------------------";
1058           print $ldap->get_error()."<br>";
1059           print $sourcedn."<br>";
1060           print $destinationdn."<br>";
1061           print_a( $attr);
1062           exit();
1063         }
1064       }
1065     }
1067     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1069     /* Prepare for recursive copy.
1070      * Get all object within the source dn and
1071      *  call the recursive copy for each.
1072      */
1073     $ldap->ls ("(objectClass=*)",$sourcedn);
1074     while ($ldap->fetch()){
1075       $deldn= $ldap->getDN();
1076       $delarray[$deldn]= strlen($deldn);
1077     }
1078     asort ($delarray);
1079     reset ($delarray);
1080     $depth ++;
1081     foreach($delarray as $dn => $bla){
1082       if($dn != $destinationdn){
1083         $ldap->cd($basedn);
1084         $item = $ldap->fetch($ldap->cat($dn));
1085         if(!in_array("FAIbranch",$item['objectClass'])){
1086           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1087         }
1088       }
1089     }
1090     if($is_first){
1091       echo "<p class='seperator'>&nbsp;</p>";
1092     }
1093   }
1097   /* This function returns the dn of the object release */
1098   static function get_release_dn($Current_DN)
1099   {
1100     global $config;
1101     $ldap = $config->get_ldap_link();
1102     $ldap->cd($config->current['BASE']);
1104     /* Split dn into pices */ 
1105     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1107     if(!is_array($dns_to_check)){
1108       return;  
1109     }
1111     /* Use dn pieces, to create sub dns like 
1112        ou=test,ou=1,ou=0...
1113        ou=1,ou=0...
1114        ou=0... 
1115        To check which dn is our release container.
1116      */
1117     unset($dns_to_check['count']); 
1118     while(count($dns_to_check)){
1120       /* Create dn */
1121       $new_dn = "";
1122       foreach($dns_to_check as $part){
1123         $new_dn .= $part.",";
1124       }
1125       $new_dn .= $config->current['BASE'];
1127       /* Check if this dn is a release dn */
1128       if(FAI::is_release_department($new_dn)){
1129         return($new_dn);
1130       }
1132       /* Remove first element of dn pieces */
1133       reset($dns_to_check);
1134       unset($dns_to_check[key($dns_to_check)]);
1135     }
1136     return("");
1137   }
1143 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1144 ?>