Code

Updated fai management
[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         trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);        
174         echo "<br>-->".$Current_DN."<br>";
175         echo "<br>-->".$obj_dn."<br>";
176       }else{
178         /* Get source object and check if it is a base FAIclass
179          */
180         $ldap->cat($obj_dn);
181         $attrs = $ldap->fetch();
182         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
183         if(count(array_intersect($classes,$attrs['objectClass']))){
184           $cn    = $attrs['cn'][0];
186           /* Check if this is the last with this name in the current release.
187               In this case we have to remove the package name 
188               from all profiles in this release.
189            */
190           $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
191               "(&(objectClass=FAIclass)(cn=".$cn."))"); 
193           /* Check if this is the last class with this name.
194            */
195           if(count($classes) == 1){
197             /* Get all FAI Profiles 
198              */
199             $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
200                 "(&(objectClass=FAIprofile)(FAIclass=*))"); 
202             /* Walk though all profiles and remove the source class name
203              */
204             foreach($profiles as $dn){
205               $ldap->cat($dn['dn']);
206               $attrs = $ldap->fetch();
208               $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
210               /* Check if this Profile uses the source class ($cn)
211                */
212               if(preg_match("/".normalizePreg($cn)."/",$attrs['FAIclass'])){
213                 $attrs['FAIclass'] = preg_replace("/[ ]*".normalizePreg($cn)."[ ]*/i"," ",$attrs['FAIclass']);
214                 if(empty($attrs['FAIclass'])){
215                   $attrs['FAIclass'] = array();
216                 }
217                 $ldap->cd($dn['dn']);
218                 $ldap->modify($attrs);
220                 if (!$ldap->success()){
221                   msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
222                 }
223               }
224             }
225           }
226         }
227       }
228     }
232     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
233     $FAI_objects_to_save[$Current_DN] =  $addObj;
234     session::set('FAI_objects_to_save',$FAI_objects_to_save);
235   }
238   /* Detect differences in attribute arrays  */
239   static function array_diff_FAI($ar1,$ar2)
240   {
242     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
243       $ar1['description'] = "";
244     }
245     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
246       $ar2['description'] = "";
247     }
249     if(count($ar1) != count($ar2)) {
250       return (true);
251     }
253     foreach($ar1 as $key1 => $val1){
255       if((is_array($val1)) && (count($val1)==1)){
256         $ar1[$key1] = $val1[0];
257       }
259       if(isset($ar2[$key1])&&  (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
260         $val1 = $val1[0];
261         $ar2[$key1] = $ar2[$key1][0];
262       }
263     }
264     ksort($ar1);
265     ksort($ar2);
266     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
267       return(true);
268     }else{
269       return(false);
270     }
271   }
274   static function arr_diff($ar1,$ar2)
275   {
276     foreach($ar1 as $ak1 => $av1){
277       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
278         return(TRUE);    
279       }elseif(is_array($av1)){
280         $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
281         if($ret) {
282           return(TRUE);
283         }
284       }
285     }
286     return(FALSE);
287   }
292   /* check which objects must be saved, and save them */
293   static function save_release_changes_now()
294   {
295     /* Variable init*/
296     $to_save = array();
298     /* check which objects must be saved */
299     $FAI_objects_to_save = session::get('FAI_objects_to_save');
300     if(!is_array($FAI_objects_to_save)) {
301       print_a(array(session::get('FAI_objects_to_save')));
302       trigger_error("Can't save FAI objects, no array given.");
303       return;
304     }
305   
306     foreach($FAI_objects_to_save as $Current_DN => $object){
307       if($object['diff']){
308         $sub_name = $Current_DN;
309         while(isset($FAI_objects_to_save[$sub_name])){
310           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
311           unset($FAI_objects_to_save[$sub_name]);
312           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
313         }
314       }
315     }
316     session::set('FAI_objects_to_save',$FAI_objects_to_save);
318     /* Sort list of objects that must be saved, and ensure that 
319        container   objects are safed, before their childs are saved */
320     ksort($to_save);
321     $tmp = array();
322     foreach($to_save as $SubObjects){
323       foreach($SubObjects as $object){
324         $tmp[] = $object;
325       }
326     }
327     $to_save = $tmp;
330     /* Save objects and manage the correct release behavior*/
331     foreach($to_save as $save){
333       $Current_DN = $save['Current_DN'];
334       $removed    = $save['removed'];
335       $objectAttrs= $save['objectAttrs'];
337       /* Get ldap object */ 
338       global $config;
339       $ldap = $config->get_ldap_link();
340       $ldap->cd($config->current['BASE']);
342       /* Get some basic informations */
343       $base_release       = FAI::get_release_dn($Current_DN);
344       $sub_releases       = FAI::                       get_sub_releases_of_this_release($base_release,true);
345       $parent_obj         = FAI::get_parent_release_object($Current_DN);
346       $following_releases = FAI::                       get_sub_releases_of_this_release($base_release,true);
348       /* Check if given dn exists or if is a new entry */
349       $ldap->cat($Current_DN);
350       if(!$ldap->count()){
351         $is_new = true;
352       }else{
353         $is_new = false;
354       }
356       /* if parameter removed is true, we have to add FAIstate to the current attrs 
357          FAIstate should end with ...|removed after this operation */  
358       if($removed ){
359         $ldap->cat($Current_DN);
361         /* Get current object, because we must add the FAIstate ...|removed */
362         if((!$ldap->count()) && !empty($parent_obj)){
363           $ldap->cat($parent_obj);
364         }
366         /* Check if we have found a suiteable object */ 
367         if(!$ldap->count()){
368           echo "Error can't remove this object ".$Current_DN;
369           return;
370         }else{
372           /* Set FAIstate to current objectAttrs */
373           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
374           if(isset($objectAttrs['FAIstate'][0])){
375             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
376               $objectAttrs['FAIstate'][0] .= "|removed";
377             }
378           }else{
379             $objectAttrs['FAIstate'][0] = "|removed";
380           }
381         }
382       }
384       /* Check if this a leaf release or not */ 
385       if(count($following_releases) == 0 ){
387         /* This is a leaf object. It isn't inherited by any other object */    
388         if(DEBUG_FAI_FUNC) { 
389           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
390           print_a($objectAttrs);
391         }
392         FAI::save_FAI_object($Current_DN,$objectAttrs);
393       }else{
395         /* This object is inherited by some sub releases */  
397         /* Get all releases, that inherit this object */ 
398         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
400         /* Get parent object */
401         $ldap->cat($parent_obj);
402         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
404         /* New objects require special handling */
405         if($is_new){
407           /* check if there is already an entry named like this,
408              in one of our parent releases */
409           if(!empty($parent_obj)){
410             if(DEBUG_FAI_FUNC) { 
411               echo "There is already an entry named like this.</b><br>";
413               echo "<b>Saving main object</b>".$Current_DN;
414               print_a($objectAttrs);
415             }    
416             FAI::save_FAI_object($Current_DN,$objectAttrs);
418             foreach($r as $key){
419               if(DEBUG_FAI_FUNC) { 
420                 echo "<b>Saving parent to following release</b> ".$key;
421                 print_a($parent_attrs);
422               }
423               FAI::save_FAI_object($key,$parent_attrs);
424             }
425           }else{
427             if(DEBUG_FAI_FUNC) { 
428               echo "<b>Saving main object</b>".$Current_DN;
429               print_a($objectAttrs);
430             }
431             FAI::save_FAI_object($Current_DN,$objectAttrs);
433             if(isset($objectAttrs['FAIstate'])){
434               $objectAttrs['FAIstate'] .= "|removed"; 
435             }else{
436               $objectAttrs['FAIstate'] = "|removed";
437             }
439             foreach($r as $key ){
440               if(DEBUG_FAI_FUNC) { 
441                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
442                 print_a($objectAttrs);
443               }
444               FAI::save_FAI_object($key,$objectAttrs);
445             }
446           }
447         }else{
449           /* check if we must patch the follwing release */
450           if(!empty($r)){
451             foreach($r as $key ){
452               if(DEBUG_FAI_FUNC) { 
453                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
454                 print_a($parent_attrs);
455               }
456               FAI::save_FAI_object($key,$parent_attrs);
457             }
458           }
460           if(DEBUG_FAI_FUNC) { 
461             echo "<b>Saving current object</b>".$parent_obj;
462             print_a($objectAttrs);
463           }
464           FAI::save_FAI_object($parent_obj,$objectAttrs);
466           if(($parent_obj != $Current_DN)){
467             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
468           }
469         }
470       }
471     } 
472     session::set('FAI_objects_to_save',array());
473   }
476   /* this function will remove all unused (deleted) objects,
477      that have no parent object */
478   static function clean_up_releases($Current_DN)
479   {
480     global $config;
481     $ldap = $config->get_ldap_link();
482     $ldap->cd($config->current['BASE']);
484     /* Collect some basic informations and initialize some variables */ 
485     $base_release       = FAI::get_release_dn($Current_DN);
486     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
487     $Kill = array();
488     $Skip = array();
490     /* We must also include the given release dn */
491     $previous_releases[] = $base_release;
493     /* Walk through all releases */
494     foreach($previous_releases as $release){
496       /* Get fai departments */
497       $deps_to_search = FAI::get_FAI_departments($release); 
499       /* For every single department  (ou=hoos,ou ..) */
500       foreach($deps_to_search as $fai_base){
502         /* Ldap search for fai classes specified in this release */
503         $ldap->cd($fai_base);
504         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
506         /* check the returned objects, and add/replace them in our return variable */
507         while($attr = $ldap->fetch()){
509           $buffer = array();
510 #        $name = str_ireplace($release,"",$attr['dn']);
511           $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
513           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
515             /* Check if this object is required somehow */    
516             if(!isset($Skip[$name])){
517               $Kill[$attr['dn']] = $attr['dn'];
518             }
519           }else{
521             /* This object is required (not removed), so do not 
522                delete any following sub releases of this object */
523             $Skip[$name] = $attr['dn'];
524           }
525         }
526       }
527     }
528     return($Kill);
529   }
532   /* Remove numeric index and 'count' from ldap->fetch result */
533   static function prepare_ldap_fetch_to_be_saved($attrs)
534   {
535     foreach($attrs as $key => $value){
536       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
537         unset($attrs[$key]);
538       }
539       if(is_array($value) && isset($value['count'])){
540         unset($attrs[$key]['count']);
541       }
542     }
543     return($attrs);
544   }
547   /* Save given attrs to specified dn*/
548   static function save_FAI_object($dn,$attrs)
549   {
550     global $config;
551     $ldap = $config->get_ldap_link();
552     $ldap->cd($config->current['BASE']);
553     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
554     $ldap->cd($dn);
556     $ldap->cat($dn,array("dn"));
557     if($ldap->count()){
559       /* Remove FAIstate*/
560       if(!isset($attrs['FAIstate'])){
561         $attrs['FAIstate'] = array();
562       }
564       $ldap->modify($attrs);
565     }else{
567       /* Unset description if empty  */
568       if(empty($attrs['description'])){
569         unset($attrs['description']);
570       }    
572       $ldap->add($attrs);
573     }
574     if (!$ldap->success()){
575       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
576     }
577   }
580   /* Return FAIstate freeze branch or "" for specified release department */
581   static function get_release_tag($dn)
582   {
583     global $config;
584     $ldap = $config->get_ldap_link();
585     $ldap->cd($dn);
586     $ldap->cat($dn,array("FAIstate"));
588     if($ldap->count()){
590       $attr = $ldap->fetch();
591       if(isset($attr['FAIstate'][0])){
592         if(preg_match("/freeze/",$attr['FAIstate'][0])){
593           return("freeze");
594         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
595           return("branch");
596         }
597       }
598     }
599     return("");
600   }
603   static function get_following_releases_that_inherit_this_object($dn)
604   {
605     global $config;
606     $ldap = $config->get_ldap_link();
607     $ldap->cd($config->current['BASE']);
609     $ret = array();
611     /* Get base release */
612     $base_release = FAI::get_release_dn($dn);
614     /* Get previous release dns */
615     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
617     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
618 #  $dn_suffix = str_ireplace($base_release,"",$dn);
619     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
621     /* Check if given object also exists whitin one of these releases */
622     foreach($sub_releases as $p_release => $name){
624       $check_dn = $dn_suffix.$p_release;
626       $ldap->cat($check_dn,array("dn","objectClass"));
628       if($ldap->count()){
629         //return($ret);
630       }else{
631         $ret[$check_dn]=$check_dn;
632       }
633     }
634     return($ret);
635   }
638   /* Get previous version of the object dn */
639   static function get_parent_release_object($dn,$include_myself=true)
640   {
641     global $config;
642     $ldap = $config->get_ldap_link();
643     $ldap->cd($config->current['BASE']);
644     $previous_releases= array();
646     /* Get base release */
647     $base_release = FAI::get_release_dn($dn);
648     if($include_myself){
649       $previous_releases[] = $base_release;  
650     }
652     /* Get previous release dns */
653     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
654     foreach($tmp as $release){
655       $previous_releases[] = $release;
656     }
658     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
659 #  $dn_suffix = str_ireplace($base_release,"",$dn);
660     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
662     /* Check if given object also exists whitin one of these releases */
663     foreach($previous_releases as $p_release){
664       $check_dn = $dn_suffix.$p_release;
665       $ldap->cat($check_dn,array("dn","objectClass"));
667       if($ldap->count()){
668         return($check_dn);
669       }
670     }
671     return("");
672   }
675   /* return release names of all parent releases */
676   static function get_previous_releases_of_this_release($dn,$flat)
677   {
678     global $config;
679     $ldap = $config->get_ldap_link();
680     $ldap->cd($config->current['BASE']);
681     $ret = array();
683     /* Explode dns into pieces, to be able to build parent dns */
684     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
686     if(!is_array($dns_to_check)){
687       return;  
688     }
690     /* Unset first entry which represents the given dn */
691     unset($dns_to_check['count']); 
692     unset($dns_to_check[key($dns_to_check)]);
694     /* Create dns addresses and check if this dn is a release dn */
695     $id = 0;
696     while(count($dns_to_check)){
698       /* build parent dn */
699       $new_dn = "";
700       foreach($dns_to_check as $part){
701         $new_dn .= $part.",";
702       }
703       $new_dn .= $config->current['BASE'];
705       /* check if this dn is a release */
706       if(FAI::is_release_department($new_dn)){
707         if($flat){
708           $ret[$id] = $new_dn; 
709         }else{
710           $ret = array($new_dn=>$ret); 
711         }
712         $id ++;
713       }else{
714         return($ret);
715       }
716       reset($dns_to_check);
717       unset($dns_to_check[key($dns_to_check)]);
718     }
719     return($ret);
720   } 
723   /* This function returns all sub release names, recursivly  */
724   static function get_sub_releases_of_this_release($dn,$flat = false)
725   {
726     global $config;
727     $res  = array();
728     $ldap = $config->get_ldap_link();
729     $ldap->cd($config->current['BASE']);
730     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
731     while($attr = $ldap->fetch()){
733       /* Append department name */
734       if($flat){
735         $res[$attr['dn']] = $attr['ou'][0];
736       }else{
737         $res[$attr['dn']] = array();
738       }
740       /* Get sub release departments of this department */
741       if(in_array("FAIbranch",$attr['objectClass'])) {
742         if($flat){
743           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
744           foreach($tmp as $dn => $value){
745             $res[$dn]=$value;
746           }
747         }else{
748           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
749         }
750       }
751     }
752     return($res);
753   }
756   /* Check if the given department is a release department */
757   static function is_release_department($dn)
758   {
759     global $config;
760     $ldap = $config->get_ldap_link();
761     $ldap->cd($config->current['BASE']);
762     $ldap->cat($dn,array("objectClass","ou"));
764     /* Check objectClasses and name to check if this is a release department */
765     if($ldap->count()){
766       $attrs = $ldap->fetch();
768       $ou = "";
769       if(isset($attrs['ou'][0])){
770         $ou = $attrs['ou'][0];  
771       }
773       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
774         return($attrs['dn']);
775       }
776     }
777     return(false);
778   }
781   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
782   {
783     global $config;
784     $start = microtime(TRUE);
785     $source_release = trim($source_release,"/");
787     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
789     $sub_releases = array();
790     $source_dn = "";
791     
792     $tmp = split("\/",$source_release);
793     foreach($tmp as $part){
794       if(empty($part)){
795         continue;
796       }
797       $source_dn            = "ou=".$part.",".$source_dn;
798       $sub_releases[$part]  = $source_dn;
799     }
801     /* Get all groups */
802     $ldap =$config->get_ldap_link();
803     $ldap->cd($config->current['BASE']);
804     $ldap->search("(objectClass=posixGroup)",array("dn"));
805     $groups = array();
806     while($attrs = $ldap->fetch()){
807       $groups[$attrs['dn']] = $attrs;
808     }
810     /* Get all FAI releases, to be able to create missing group application releases 
811         with the correct type of release (FAIstate=freeze/branch).
812      */
813     $f_releases = array();
814     $ldap->cd ($config->current['BASE']);
815     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
816     while($attrs = $ldap->fetch()){
817       foreach($sub_releases as $sub_rel){
818         if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
819           $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
820         }
821       }
822     }
824     /* Get all group releases */
825     $g_releases = array();
826     foreach($groups as $dn => $data){
827       $ldap->cd($dn);
828       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
829       while($attrs = $ldap->fetch()){
830         $g_releases[$attrs['dn']] = $attrs;
831       }
832     }
834     /* Check if base releases exists.
835        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
836      */
837     foreach($sub_releases as $name => $sub_rel){
839       $FAIstate = "";
840       if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
841         $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
842       }
844       foreach($groups as $dn => $data){
845         if(!isset($g_releases[$sub_rel.$dn])){
846           $ldap->cd($dn);
847           $r_data = array();
848           $r_data['ou'] = $name;
849           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
850           if(!empty($FAIstate)) {
851             $r_data['FAIstate'] = $FAIstate;
852           }
853  
854           $ldap->cd($sub_rel.$dn) ;
855           $ldap->add($r_data);
856           echo "&nbsp;<b>"._("Object").":</b> ";
857           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
858           flush();
859         }
860       }
861     } 
862  
863     /* Create new release container in each group.
864      */
865     $n_data = array();
866     $n_data = array();
867     $n_data['ou'] = $destination_name;
868     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
869     if(!empty($type)){
870       $n_data['FAIstate'] = $type."/cow";
871     }
873     foreach($groups as $dn => $att){
874       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
875       if(!isset($g_releases[$n_dn])){
876         $ldap->cd ($n_dn);
877         $ldap->add($n_data);
878         echo "&nbsp;<b>"._("Object").":</b> ";
879         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
880         flush();
881       }
882     }
884     /* If the source release is empty, then create a new release by copying 
885         all group application menus into a new ou=$destination_name release container.
886       
887        If the source release is not empty. 
888          We detect all releases which match the source release dn and copy the contents.
889      */
890     if(empty($source_release)){
891       $source_dns = $groups;
892     }else{
893       $source_dns = array();
894       foreach($g_releases as $dn => $data){
895         if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
896           $source_dns[$dn] = $data; 
897         }
898       }
899     }
901     /* Detect all menu object we have to copy 
902      */
903     $to_copy = array();
904     foreach($source_dns as $dn => $attrs){
905       $ldap->cd($dn);
906       $ldap->ls("(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry)",$dn,array("dn"));
907       while($attrs = $ldap->fetch()){
908         $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
909         $to_copy[$attrs['dn']] = $destination;
910       }
911     }
912    
913     /* At least create the menu objects object */
914     $plug = new plugin($config);
915     foreach($to_copy as $source => $destination){
916       $ldap->cat($destination);
917       if($ldap->count()){
918         echo "&nbsp;<b>"._("Object").":</b> ";
919         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
920         flush();
921       }else{
922         $plug->copy($source,$destination);
923         echo "&nbsp;<b>"._("Object").":</b> ";
924         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
925         flush();
926       }
927     }
928   }
931   /*! \brief Create a new FAI branch.
932    *  @param $sourcedn          String  The source release dn
933    *  @param $destinationdn     String  The destination dn
934    *  @param $destinationName   String  The name of the new release
935    *  @param $type              String  The release type (freeze/branch)
936    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
937    *  @param $depth             Integer Current depth of recursion.
938    */
939   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
940   {
941     global $config;
942     error_reporting(E_ALL | E_STRICT);
943     $ldap     = $config->get_ldap_link();
944     $basedn   = $config->current['BASE'];
945     $delarray = array();
947     /* The following code will output a status string
948      *  for each handled object, in a seperate iframe.
949      */
952     /* Display current action information.
953      */
954     if($is_first){
955       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
956     }else{
957       if(preg_match("/^ou=/",$sourcedn)){
958         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
959       }else{
960         $tmp = split(",",$sourcedn);
961         echo "&nbsp;<b>"._("Object").":</b> ";
962         $deststr = LDAP::fix($destinationdn);
963         if(strlen($deststr) > 96){
964           $deststr = substr($deststr,0,96)."...";
965         }
966         echo $deststr."<br>";
967       }
968     }
969     /* .. immediately display infos */
970     flush();
972     /* Check if destination entry already exists
973      */
974     $ldap->cat($destinationdn);
975     if($ldap->count()){
976       echo _("Could not create new release, the destination dn is already in use.");
977       return;
978     }else{
980       $ldap->clearResult();
982       /* Get source entry
983        *  if it does not exist, abort here.
984        */
985       $ldap->cd($basedn);
986       $ldap->cat($sourcedn);
987       $attr = $ldap->fetch();
988       if((!$attr) || (count($attr)) ==0) {
989         echo _("Error while fetching source dn - aborted!");
990         return;
991       }
993       /* The current object we want to create is an department.
994        * Create the department and add the FAIbranch tag.
995        */
996       if(in_array("organizationalUnit",$attr['objectClass'])){
997         $attr['dn'] = LDAP::convert($destinationdn);
998         $ldap->cd($basedn);
999         $ldap->create_missing_trees($destinationdn);
1000         $ldap->cd($destinationdn);
1002         /* If is first entry, append FAIbranch to department entry */
1003         if($is_first){
1004           $ldap->cat($destinationdn);
1005           $attr= $ldap->fetch();
1006           /* Filter unneeded informations */
1007           foreach($attr as $key => $value){
1008             if(is_numeric($key)) unset($attr[$key]);
1009             if(isset($attr[$key]['count'])){
1010               if(is_array($attr[$key])){
1011                 unset($attr[$key]['count']);
1012               }
1013             }
1014           }
1016           unset($attr['count']);
1017           unset($attr['dn']);
1019           /* Add marking attribute */
1020           $attr['objectClass'][] = "FAIbranch";
1022           /* Add this entry */
1023           $ldap->modify($attr);
1024         }
1025       }else{
1027         /* Replicate all relevant FAI objects here.
1028          * FAI objects, Apps and Mimetypes.
1029          * Get all attributes as binary value, to ensure that Icon, File template aso
1030          *  are created correctly.
1031          */
1032         foreach($attr as $key => $value){
1034           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1035             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1036             $ei= ldap_first_entry($ldap->cid, $sr);
1037             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1038               $attr[$key] = $tmp;
1039             }
1040           }
1042           if(is_numeric($key)) unset($attr[$key]);
1043           if(isset($attr[$key]['count'])){
1044             if(is_array($attr[$key])){
1045               unset($attr[$key]['count']);
1046             }
1047           }
1048         }
1049         unset($attr['count']);
1050         unset($attr['dn']);
1052         /* Add entry
1053          */
1054         $ldap->cd($destinationdn);
1055         $ldap->cat($destinationdn);
1057         $a = $ldap->fetch();
1058         if(!count($a)){
1059           $ldap->add($attr);
1060         }
1062         if(!$ldap->success()){
1064           /* Some error occurred */
1065           print "---------------------------------------------";
1066           print $ldap->get_error()."<br>";
1067           print $sourcedn."<br>";
1068           print $destinationdn."<br>";
1069           print_a( $attr);
1070           exit();
1071         }
1072       }
1073     }
1075     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1077     /* Prepare for recursive copy.
1078      * Get all object within the source dn and
1079      *  call the recursive copy for each.
1080      */
1081     $ldap->ls ("(objectClass=*)",$sourcedn);
1082     while ($ldap->fetch()){
1083       $deldn= $ldap->getDN();
1084       $delarray[$deldn]= strlen($deldn);
1085     }
1086     asort ($delarray);
1087     reset ($delarray);
1088     $depth ++;
1089     foreach($delarray as $dn => $bla){
1090       if($dn != $destinationdn){
1091         $ldap->cd($basedn);
1092         $item = $ldap->fetch($ldap->cat($dn));
1093         if(!in_array("FAIbranch",$item['objectClass'])){
1094           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1095         }
1096       }
1097     }
1098     if($is_first){
1099       echo "<p class='seperator'>&nbsp;</p>";
1100     }
1101   }
1105   /* This function returns the dn of the object release */
1106   static function get_release_dn($Current_DN)
1107   {
1108     global $config;
1109     $ldap = $config->get_ldap_link();
1110     $ldap->cd($config->current['BASE']);
1112     /* Split dn into pices */ 
1113     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1115     if(!is_array($dns_to_check)){
1116       return;  
1117     }
1119     /* Use dn pieces, to create sub dns like 
1120        ou=test,ou=1,ou=0...
1121        ou=1,ou=0...
1122        ou=0... 
1123        To check which dn is our release container.
1124      */
1125     unset($dns_to_check['count']); 
1126     while(count($dns_to_check)){
1128       /* Create dn */
1129       $new_dn = "";
1130       foreach($dns_to_check as $part){
1131         $new_dn .= $part.",";
1132       }
1133       $new_dn .= $config->current['BASE'];
1135       /* Check if this dn is a release dn */
1136       if(FAI::is_release_department($new_dn)){
1137         return($new_dn);
1138       }
1140       /* Remove first element of dn pieces */
1141       reset($dns_to_check);
1142       unset($dns_to_check[key($dns_to_check)]);
1143     }
1144     return("");
1145   }
1151 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1152 ?>