73848e7faf953ebd55959eb828532ea4cb0bdcc8
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 foreach($FAI_objects_to_save as $Current_DN => $object){
296 if($object['diff']){
297 $sub_name = $Current_DN;
298 while(isset($FAI_objects_to_save[$sub_name])){
299 $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name];
300 unset($FAI_objects_to_save[$sub_name]);
301 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
302 }
303 }
304 }
305 session::set('FAI_objects_to_save',$FAI_objects_to_save);
307 /* Sort list of objects that must be saved, and ensure that
308 container objects are safed, before their childs are saved */
309 ksort($to_save);
310 $tmp = array();
311 foreach($to_save as $SubObjects){
312 foreach($SubObjects as $object){
313 $tmp[] = $object;
314 }
315 }
316 $to_save = $tmp;
318 /* Save objects and manage the correct release behavior*/
319 foreach($to_save as $save){
321 $Current_DN = $save['Current_DN'];
322 $removed = $save['removed'];
323 $objectAttrs= $save['objectAttrs'];
325 /* Get ldap object */
326 global $config;
327 $ldap = $config->get_ldap_link();
328 $ldap->cd($config->current['BASE']);
330 /* Get some basic informations */
331 $base_release = FAI::get_release_dn($Current_DN);
332 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release,true);
333 $parent_obj = FAI::get_parent_release_object($Current_DN);
334 $following_releases = FAI:: get_sub_releases_of_this_release($base_release,true);
336 /* Check if given dn exists or if is a new entry */
337 $ldap->cat($Current_DN);
338 if(!$ldap->count()){
339 $is_new = true;
340 }else{
341 $is_new = false;
342 }
344 /* if parameter removed is true, we have to add FAIstate to the current attrs
345 FAIstate should end with ...|removed after this operation */
346 if($removed ){
347 $ldap->cat($Current_DN);
349 /* Get current object, because we must add the FAIstate ...|removed */
350 if((!$ldap->count()) && !empty($parent_obj)){
351 $ldap->cat($parent_obj);
352 }
354 /* Check if we have found a suiteable object */
355 if(!$ldap->count()){
356 echo "Error can't remove this object ".$Current_DN;
357 return;
358 }else{
360 /* Set FAIstate to current objectAttrs */
361 $objectAttrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
362 if(isset($objectAttrs['FAIstate'][0])){
363 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
364 $objectAttrs['FAIstate'][0] .= "|removed";
365 }
366 }else{
367 $objectAttrs['FAIstate'][0] = "|removed";
368 }
369 }
370 }
372 /* Check if this a leaf release or not */
373 if(count($following_releases) == 0 ){
375 /* This is a leaf object. It isn't inherited by any other object */
376 if(DEBUG_FAI_FUNC) {
377 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
378 print_a($objectAttrs);
379 }
380 FAI::save_FAI_object($Current_DN,$objectAttrs);
381 }else{
383 /* This object is inherited by some sub releases */
385 /* Get all releases, that inherit this object */
386 $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
388 /* Get parent object */
389 $ldap->cat($parent_obj);
390 $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
392 /* New objects require special handling */
393 if($is_new){
395 /* check if there is already an entry named like this,
396 in one of our parent releases */
397 if(!empty($parent_obj)){
398 if(DEBUG_FAI_FUNC) {
399 echo "There is already an entry named like this.</b><br>";
401 echo "<b>Saving main object</b>".$Current_DN;
402 print_a($objectAttrs);
403 }
404 FAI::save_FAI_object($Current_DN,$objectAttrs);
406 foreach($r as $key){
407 if(DEBUG_FAI_FUNC) {
408 echo "<b>Saving parent to following release</b> ".$key;
409 print_a($parent_attrs);
410 }
411 FAI::save_FAI_object($key,$parent_attrs);
412 }
413 }else{
415 if(DEBUG_FAI_FUNC) {
416 echo "<b>Saving main object</b>".$Current_DN;
417 print_a($objectAttrs);
418 }
419 FAI::save_FAI_object($Current_DN,$objectAttrs);
421 if(isset($objectAttrs['FAIstate'])){
422 $objectAttrs['FAIstate'] .= "|removed";
423 }else{
424 $objectAttrs['FAIstate'] = "|removed";
425 }
427 foreach($r as $key ){
428 if(DEBUG_FAI_FUNC) {
429 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
430 print_a($objectAttrs);
431 }
432 FAI::save_FAI_object($key,$objectAttrs);
433 }
434 }
435 }else{
437 /* check if we must patch the follwing release */
438 if(!empty($r)){
439 foreach($r as $key ){
440 if(DEBUG_FAI_FUNC) {
441 echo "<b>Copy current objects original attributes to next release</b> ".$key;
442 print_a($parent_attrs);
443 }
444 FAI::save_FAI_object($key,$parent_attrs);
445 }
446 }
448 if(DEBUG_FAI_FUNC) {
449 echo "<b>Saving current object</b>".$parent_obj;
450 print_a($objectAttrs);
451 }
452 FAI::save_FAI_object($parent_obj,$objectAttrs);
454 if(($parent_obj != $Current_DN)){
455 msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
456 }
457 }
458 }
459 }
460 session::set('FAI_objects_to_save',array());
461 }
464 /* this function will remove all unused (deleted) objects,
465 that have no parent object */
466 static function clean_up_releases($Current_DN)
467 {
468 global $config;
469 $ldap = $config->get_ldap_link();
470 $ldap->cd($config->current['BASE']);
472 /* Collect some basic informations and initialize some variables */
473 $base_release = FAI::get_release_dn($Current_DN);
474 $previous_releases = array_reverse(FAI:: get_previous_releases_of_this_release($base_release,true));
475 $Kill = array();
476 $Skip = array();
478 /* We must also include the given release dn */
479 $previous_releases[] = $base_release;
481 /* Walk through all releases */
482 foreach($previous_releases as $release){
484 /* Get fai departments */
485 $deps_to_search = FAI::get_FAI_departments($release);
487 /* For every single department (ou=hoos,ou ..) */
488 foreach($deps_to_search as $fai_base){
490 /* Ldap search for fai classes specified in this release */
491 $ldap->cd($fai_base);
492 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
494 /* check the returned objects, and add/replace them in our return variable */
495 while($attr = $ldap->fetch()){
497 $buffer = array();
498 # $name = str_ireplace($release,"",$attr['dn']);
499 $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
501 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
503 /* Check if this object is required somehow */
504 if(!isset($Skip[$name])){
505 $Kill[$attr['dn']] = $attr['dn'];
506 }
507 }else{
509 /* This object is required (not removed), so do not
510 delete any following sub releases of this object */
511 $Skip[$name] = $attr['dn'];
512 }
513 }
514 }
515 }
516 return($Kill);
517 }
520 /* Remove numeric index and 'count' from ldap->fetch result */
521 static function prepare_ldap_fetch_to_be_saved($attrs)
522 {
523 foreach($attrs as $key => $value){
524 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
525 unset($attrs[$key]);
526 }
527 if(is_array($value) && isset($value['count'])){
528 unset($attrs[$key]['count']);
529 }
530 }
531 return($attrs);
532 }
535 /* Save given attrs to specified dn*/
536 static function save_FAI_object($dn,$attrs)
537 {
538 global $config;
539 $ldap = $config->get_ldap_link();
540 $ldap->cd($config->current['BASE']);
541 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
542 $ldap->cd($dn);
544 $ldap->cat($dn,array("dn"));
545 if($ldap->count()){
547 /* Remove FAIstate*/
548 if(!isset($attrs['FAIstate'])){
549 $attrs['FAIstate'] = array();
550 }
552 $ldap->modify($attrs);
553 }else{
555 /* Unset description if empty */
556 if(empty($attrs['description'])){
557 unset($attrs['description']);
558 }
560 $ldap->add($attrs);
561 }
562 if (!$ldap->success()){
563 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
564 }
565 }
568 /* Return FAIstate freeze branch or "" for specified release department */
569 static function get_release_tag($dn)
570 {
571 global $config;
572 $ldap = $config->get_ldap_link();
573 $ldap->cd($dn);
574 $ldap->cat($dn,array("FAIstate"));
576 if($ldap->count()){
578 $attr = $ldap->fetch();
579 if(isset($attr['FAIstate'][0])){
580 if(preg_match("/freeze/",$attr['FAIstate'][0])){
581 return("freeze");
582 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
583 return("branch");
584 }
585 }
586 }
587 return("");
588 }
591 static function get_following_releases_that_inherit_this_object($dn)
592 {
593 global $config;
594 $ldap = $config->get_ldap_link();
595 $ldap->cd($config->current['BASE']);
597 $ret = array();
599 /* Get base release */
600 $base_release = FAI::get_release_dn($dn);
602 /* Get previous release dns */
603 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release);
605 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
606 # $dn_suffix = str_ireplace($base_release,"",$dn);
607 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
609 /* Check if given object also exists whitin one of these releases */
610 foreach($sub_releases as $p_release => $name){
612 $check_dn = $dn_suffix.$p_release;
614 $ldap->cat($check_dn,array("dn","objectClass"));
616 if($ldap->count()){
617 //return($ret);
618 }else{
619 $ret[$check_dn]=$check_dn;
620 }
621 }
622 return($ret);
623 }
626 /* Get previous version of the object dn */
627 static function get_parent_release_object($dn,$include_myself=true)
628 {
629 global $config;
630 $ldap = $config->get_ldap_link();
631 $ldap->cd($config->current['BASE']);
632 $previous_releases= array();
634 /* Get base release */
635 $base_release = FAI::get_release_dn($dn);
636 if($include_myself){
637 $previous_releases[] = $base_release;
638 }
640 /* Get previous release dns */
641 $tmp = FAI:: get_previous_releases_of_this_release($base_release,true);
642 foreach($tmp as $release){
643 $previous_releases[] = $release;
644 }
646 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
647 # $dn_suffix = str_ireplace($base_release,"",$dn);
648 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
650 /* Check if given object also exists whitin one of these releases */
651 foreach($previous_releases as $p_release){
652 $check_dn = $dn_suffix.$p_release;
653 $ldap->cat($check_dn,array("dn","objectClass"));
655 if($ldap->count()){
656 return($check_dn);
657 }
658 }
659 return("");
660 }
663 /* return release names of all parent releases */
664 static function get_previous_releases_of_this_release($dn,$flat)
665 {
666 global $config;
667 $ldap = $config->get_ldap_link();
668 $ldap->cd($config->current['BASE']);
669 $ret = array();
671 /* Explode dns into pieces, to be able to build parent dns */
672 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
674 if(!is_array($dns_to_check)){
675 return;
676 }
678 /* Unset first entry which represents the given dn */
679 unset($dns_to_check['count']);
680 unset($dns_to_check[key($dns_to_check)]);
682 /* Create dns addresses and check if this dn is a release dn */
683 $id = 0;
684 while(count($dns_to_check)){
686 /* build parent dn */
687 $new_dn = "";
688 foreach($dns_to_check as $part){
689 $new_dn .= $part.",";
690 }
691 $new_dn .= $config->current['BASE'];
693 /* check if this dn is a release */
694 if(FAI::is_release_department($new_dn)){
695 if($flat){
696 $ret[$id] = $new_dn;
697 }else{
698 $ret = array($new_dn=>$ret);
699 }
700 $id ++;
701 }else{
702 return($ret);
703 }
704 reset($dns_to_check);
705 unset($dns_to_check[key($dns_to_check)]);
706 }
707 return($ret);
708 }
711 /* This function returns all sub release names, recursivly */
712 static function get_sub_releases_of_this_release($dn,$flat = false)
713 {
714 global $config;
715 $res = array();
716 $ldap = $config->get_ldap_link();
717 $ldap->cd($config->current['BASE']);
718 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
719 while($attr = $ldap->fetch()){
721 /* Append department name */
722 if($flat){
723 $res[$attr['dn']] = $attr['ou'][0];
724 }else{
725 $res[$attr['dn']] = array();
726 }
728 /* Get sub release departments of this department */
729 if(in_array("FAIbranch",$attr['objectClass'])) {
730 if($flat){
731 $tmp = FAI:: get_sub_releases_of_this_release($attr['dn'],$flat);
732 foreach($tmp as $dn => $value){
733 $res[$dn]=$value;
734 }
735 }else{
736 $res[$attr['dn']] = FAI:: get_sub_releases_of_this_release($attr['dn']);
737 }
738 }
739 }
740 return($res);
741 }
744 /* Check if the given department is a release department */
745 static function is_release_department($dn)
746 {
747 global $config;
748 $ldap = $config->get_ldap_link();
749 $ldap->cd($config->current['BASE']);
750 $ldap->cat($dn,array("objectClass","ou"));
752 /* Check objectClasses and name to check if this is a release department */
753 if($ldap->count()){
754 $attrs = $ldap->fetch();
756 $ou = "";
757 if(isset($attrs['ou'][0])){
758 $ou = $attrs['ou'][0];
759 }
761 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
762 return($attrs['dn']);
763 }
764 }
765 return(false);
766 }
769 static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
770 {
771 global $config;
772 $start = microtime(TRUE);
773 $source_release = trim($source_release,"/");
775 echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
777 $sub_releases = array();
778 $source_dn = "";
780 $tmp = split("\/",$source_release);
781 foreach($tmp as $part){
782 if(empty($part)){
783 continue;
784 }
785 $source_dn = "ou=".$part.",".$source_dn;
786 $sub_releases[$part] = $source_dn;
787 }
789 /* Get all groups */
790 $ldap =$config->get_ldap_link();
791 $ldap->cd($config->current['BASE']);
792 $ldap->search("(objectClass=posixGroup)",array("dn"));
793 $groups = array();
794 while($attrs = $ldap->fetch()){
795 $groups[$attrs['dn']] = $attrs;
796 }
798 /* Get all FAI releases, to be able to create missing group application releases
799 with the correct type of release (FAIstate=freeze/branch).
800 */
801 $f_releases = array();
802 $ldap->cd ($config->current['BASE']);
803 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
804 while($attrs = $ldap->fetch()){
805 foreach($sub_releases as $sub_rel){
806 if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
807 $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
808 }
809 }
810 }
812 /* Get all group releases */
813 $g_releases = array();
814 foreach($groups as $dn => $data){
815 $ldap->cd($dn);
816 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
817 while($attrs = $ldap->fetch()){
818 $g_releases[$attrs['dn']] = $attrs;
819 }
820 }
822 /* Check if base releases exists.
823 If they do not exist, create them and adapt FAIstate attribute from FAI releases.
824 */
825 foreach($sub_releases as $name => $sub_rel){
827 $FAIstate = "";
828 if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
829 $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
830 }
832 foreach($groups as $dn => $data){
833 if(!isset($g_releases[$sub_rel.$dn])){
834 $ldap->cd($dn);
835 $r_data = array();
836 $r_data['ou'] = $name;
837 $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
838 if(!empty($FAIstate)) {
839 $r_data['FAIstate'] = $FAIstate;
840 }
842 $ldap->cd($sub_rel.$dn) ;
843 $ldap->add($r_data);
844 echo " <b>"._("Object").":</b> ";
845 echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
846 flush();
847 }
848 }
849 }
851 /* Create new release container in each group.
852 */
853 $n_data = array();
854 $n_data = array();
855 $n_data['ou'] = $destination_name;
856 $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
857 if(!empty($type)){
858 $n_data['FAIstate'] = $type."/cow";
859 }
861 foreach($groups as $dn => $att){
862 $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
863 if(!isset($g_releases[$n_dn])){
864 $ldap->cd ($n_dn);
865 $ldap->add($n_data);
866 echo " <b>"._("Object").":</b> ";
867 echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
868 flush();
869 }
870 }
872 /* If the source release is empty, then create a new release by copying
873 all group application menus into a new ou=$destination_name release container.
875 If the source release is not empty.
876 We detect all releases which match the source release dn and copy the contents.
877 */
878 if(empty($source_release)){
879 $source_dns = $groups;
880 }else{
881 $source_dns = array();
882 foreach($g_releases as $dn => $data){
883 if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
884 $source_dns[$dn] = $data;
885 }
886 }
887 }
889 /* Detect all menu object we have to copy
890 */
891 $to_copy = array();
892 foreach($source_dns as $dn => $attrs){
893 $ldap->cd($dn);
894 $ldap->ls("(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry)",$dn,array("dn"));
895 while($attrs = $ldap->fetch()){
896 $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
897 $to_copy[$attrs['dn']] = $destination;
898 }
899 }
901 /* At least create the menu objects object */
902 $plug = new plugin($config);
903 foreach($to_copy as $source => $destination){
904 $ldap->cat($destination);
905 if($ldap->count()){
906 echo " <b>"._("Object").":</b> ";
907 echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
908 flush();
909 }else{
910 $plug->copy($source,$destination);
911 echo " <b>"._("Object").":</b> ";
912 echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
913 flush();
914 }
915 }
916 }
919 /*! \brief Create a new FAI branch.
920 * @param $sourcedn String The source release dn
921 * @param $destinationdn String The destination dn
922 * @param $destinationName String The name of the new release
923 * @param $type String The release type (freeze/branch)
924 * @param $is_first Boolean Use to identify the first func. call when recursivly called.
925 * @param $depth Integer Current depth of recursion.
926 */
927 function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
928 {
929 global $config;
930 error_reporting(E_ALL | E_STRICT);
931 $ldap = $config->get_ldap_link();
932 $basedn = $config->current['BASE'];
933 $delarray = array();
935 /* The following code will output a status string
936 * for each handled object, in a seperate iframe.
937 */
940 /* Display current action information.
941 */
942 if($is_first){
943 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
944 }else{
945 if(preg_match("/^ou=/",$sourcedn)){
946 echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
947 }else{
948 $tmp = split(",",$sourcedn);
949 echo " <b>"._("Object").":</b> ";
950 $deststr = LDAP::fix($destinationdn);
951 if(strlen($deststr) > 96){
952 $deststr = substr($deststr,0,96)."...";
953 }
954 echo $deststr."<br>";
955 }
956 }
957 /* .. immediately display infos */
958 flush();
960 /* Check if destination entry already exists
961 */
962 $ldap->cat($destinationdn);
963 if($ldap->count()){
964 echo _("Could not create new release, the destination dn is already in use.");
965 return;
966 }else{
968 $ldap->clearResult();
970 /* Get source entry
971 * if it does not exist, abort here.
972 */
973 $ldap->cd($basedn);
974 $ldap->cat($sourcedn);
975 $attr = $ldap->fetch();
976 if((!$attr) || (count($attr)) ==0) {
977 echo _("Error while fetching source dn - aborted!");
978 return;
979 }
981 /* The current object we want to create is an department.
982 * Create the department and add the FAIbranch tag.
983 */
984 if(in_array("organizationalUnit",$attr['objectClass'])){
985 $attr['dn'] = LDAP::convert($destinationdn);
986 $ldap->cd($basedn);
987 $ldap->create_missing_trees($destinationdn);
988 $ldap->cd($destinationdn);
990 /* If is first entry, append FAIbranch to department entry */
991 if($is_first){
992 $ldap->cat($destinationdn);
993 $attr= $ldap->fetch();
994 /* Filter unneeded informations */
995 foreach($attr as $key => $value){
996 if(is_numeric($key)) unset($attr[$key]);
997 if(isset($attr[$key]['count'])){
998 if(is_array($attr[$key])){
999 unset($attr[$key]['count']);
1000 }
1001 }
1002 }
1004 unset($attr['count']);
1005 unset($attr['dn']);
1007 /* Add marking attribute */
1008 $attr['objectClass'][] = "FAIbranch";
1010 /* Add this entry */
1011 $ldap->modify($attr);
1012 }
1013 }else{
1015 /* Replicate all relevant FAI objects here.
1016 * FAI objects, Apps and Mimetypes.
1017 * Get all attributes as binary value, to ensure that Icon, File template aso
1018 * are created correctly.
1019 */
1020 foreach($attr as $key => $value){
1022 if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1023 $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1024 $ei= ldap_first_entry($ldap->cid, $sr);
1025 if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1026 $attr[$key] = $tmp;
1027 }
1028 }
1030 if(is_numeric($key)) unset($attr[$key]);
1031 if(isset($attr[$key]['count'])){
1032 if(is_array($attr[$key])){
1033 unset($attr[$key]['count']);
1034 }
1035 }
1036 }
1037 unset($attr['count']);
1038 unset($attr['dn']);
1040 /* Add entry
1041 */
1042 $ldap->cd($destinationdn);
1043 $ldap->cat($destinationdn);
1045 $a = $ldap->fetch();
1046 if(!count($a)){
1047 $ldap->add($attr);
1048 }
1050 if(!$ldap->success()){
1052 /* Some error occurred */
1053 print "---------------------------------------------";
1054 print $ldap->get_error()."<br>";
1055 print $sourcedn."<br>";
1056 print $destinationdn."<br>";
1057 print_a( $attr);
1058 exit();
1059 }
1060 }
1061 }
1063 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1065 /* Prepare for recursive copy.
1066 * Get all object within the source dn and
1067 * call the recursive copy for each.
1068 */
1069 $ldap->ls ("(objectClass=*)",$sourcedn);
1070 while ($ldap->fetch()){
1071 $deldn= $ldap->getDN();
1072 $delarray[$deldn]= strlen($deldn);
1073 }
1074 asort ($delarray);
1075 reset ($delarray);
1076 $depth ++;
1077 foreach($delarray as $dn => $bla){
1078 if($dn != $destinationdn){
1079 $ldap->cd($basedn);
1080 $item = $ldap->fetch($ldap->cat($dn));
1081 if(!in_array("FAIbranch",$item['objectClass'])){
1082 FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1083 }
1084 }
1085 }
1086 if($is_first){
1087 echo "<p class='seperator'> </p>";
1088 }
1089 }
1093 /* This function returns the dn of the object release */
1094 static function get_release_dn($Current_DN)
1095 {
1096 global $config;
1097 $ldap = $config->get_ldap_link();
1098 $ldap->cd($config->current['BASE']);
1100 /* Split dn into pices */
1101 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1103 if(!is_array($dns_to_check)){
1104 return;
1105 }
1107 /* Use dn pieces, to create sub dns like
1108 ou=test,ou=1,ou=0...
1109 ou=1,ou=0...
1110 ou=0...
1111 To check which dn is our release container.
1112 */
1113 unset($dns_to_check['count']);
1114 while(count($dns_to_check)){
1116 /* Create dn */
1117 $new_dn = "";
1118 foreach($dns_to_check as $part){
1119 $new_dn .= $part.",";
1120 }
1121 $new_dn .= $config->current['BASE'];
1123 /* Check if this dn is a release dn */
1124 if(FAI::is_release_department($new_dn)){
1125 return($new_dn);
1126 }
1128 /* Remove first element of dn pieces */
1129 reset($dns_to_check);
1130 unset($dns_to_check[key($dns_to_check)]);
1131 }
1132 return("");
1133 }
1134 }
1139 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1140 ?>