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 global $config;
296 /* Variable init*/
297 $to_save = array();
299 $reload_fai_classes = FALSE;
301 /* check which objects must be saved */
302 $FAI_objects_to_save = session::get('FAI_objects_to_save');
303 if(!is_array($FAI_objects_to_save)) {
304 print_a(array(session::get('FAI_objects_to_save')));
305 trigger_error("Can't save FAI objects, no array given.");
306 return;
307 }
309 foreach($FAI_objects_to_save as $Current_DN => $object){
310 if($object['diff']){
311 $sub_name = $Current_DN;
312 while(isset($FAI_objects_to_save[$sub_name])){
313 $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name];
314 unset($FAI_objects_to_save[$sub_name]);
315 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
316 }
317 }
318 }
319 session::set('FAI_objects_to_save',$FAI_objects_to_save);
321 /* Sort list of objects that must be saved, and ensure that
322 container objects are safed, before their childs are saved */
323 ksort($to_save);
324 $tmp = array();
325 foreach($to_save as $SubObjects){
326 foreach($SubObjects as $object){
327 $tmp[] = $object;
328 }
329 }
330 $to_save = $tmp;
333 /* Save objects and manage the correct release behavior*/
334 foreach($to_save as $save){
336 $Current_DN = $save['Current_DN'];
337 $removed = $save['removed'];
338 $objectAttrs= $save['objectAttrs'];
340 /* Get ldap object */
341 $ldap = $config->get_ldap_link();
342 $ldap->cd($config->current['BASE']);
344 /* Get some basic informations */
345 $base_release = FAI::get_release_dn($Current_DN);
346 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release,true);
347 $parent_obj = FAI::get_parent_release_object($Current_DN);
348 $following_releases = FAI:: get_sub_releases_of_this_release($base_release,true);
350 /* Check if given dn exists or if is a new entry */
351 $ldap->cat($Current_DN);
352 if(!$ldap->count()){
353 $is_new = true;
354 }else{
355 $is_new = false;
356 }
358 /* if parameter removed is true, we have to add FAIstate to the current attrs
359 FAIstate should end with ...|removed after this operation */
360 if($removed ){
361 $ldap->cat($Current_DN);
363 /* Get current object, because we must add the FAIstate ...|removed */
364 if((!$ldap->count()) && !empty($parent_obj)){
365 $ldap->cat($parent_obj);
366 }
368 /* Check if we have found a suiteable object */
369 if(!$ldap->count()){
370 echo "Error can't remove this object ".$Current_DN;
371 return;
372 }else{
374 /* Set FAIstate to current objectAttrs */
375 $objectAttrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
376 if(isset($objectAttrs['FAIstate'][0])){
377 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
378 $objectAttrs['FAIstate'][0] .= "|removed";
379 }
380 }else{
381 $objectAttrs['FAIstate'][0] = "|removed";
382 }
384 /* Force reload of FAI classes */
385 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
386 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
387 $reload_fai_classes = TRUE;
388 }
389 }
390 }
392 /* Check if this a leaf release or not */
393 if(count($following_releases) == 0 ){
395 /* This is a leaf object. It isn't inherited by any other object */
396 if(DEBUG_FAI_FUNC) {
397 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
398 print_a($objectAttrs);
399 }
400 FAI::save_FAI_object($Current_DN,$objectAttrs);
402 /* Force reload of FAI classes */
403 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
404 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
405 $reload_fai_classes = TRUE;
406 }
408 }else{
410 /* This object is inherited by some sub releases */
412 /* Get all releases, that inherit this object */
413 $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
415 /* Get parent object */
416 $ldap->cat($parent_obj);
417 $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
419 /* New objects require special handling */
420 if($is_new){
422 /* Force reload of FAI classes */
423 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
424 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
425 $reload_fai_classes = TRUE;
426 }
428 /* check if there is already an entry named like this,
429 in one of our parent releases */
430 if(!empty($parent_obj)){
431 if(DEBUG_FAI_FUNC) {
432 echo "There is already an entry named like this.</b><br>";
434 echo "<b>Saving main object</b>".$Current_DN;
435 print_a($objectAttrs);
436 }
437 FAI::save_FAI_object($Current_DN,$objectAttrs);
439 foreach($r as $key){
440 if(DEBUG_FAI_FUNC) {
441 echo "<b>Saving parent to following release</b> ".$key;
442 print_a($parent_attrs);
443 }
444 FAI::save_FAI_object($key,$parent_attrs);
445 }
446 }else{
448 if(DEBUG_FAI_FUNC) {
449 echo "<b>Saving main object</b>".$Current_DN;
450 print_a($objectAttrs);
451 }
452 FAI::save_FAI_object($Current_DN,$objectAttrs);
454 if(isset($objectAttrs['FAIstate'])){
455 $objectAttrs['FAIstate'] .= "|removed";
456 }else{
457 $objectAttrs['FAIstate'] = "|removed";
458 }
460 foreach($r as $key ){
461 if(DEBUG_FAI_FUNC) {
462 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
463 print_a($objectAttrs);
464 }
465 FAI::save_FAI_object($key,$objectAttrs);
466 }
467 }
468 }else{
470 /* check if we must patch the follwing release */
471 if(!empty($r)){
472 foreach($r as $key ){
473 if(DEBUG_FAI_FUNC) {
474 echo "<b>Copy current objects original attributes to next release</b> ".$key;
475 print_a($parent_attrs);
476 }
477 FAI::save_FAI_object($key,$parent_attrs);
478 }
479 }
481 if(DEBUG_FAI_FUNC) {
482 echo "<b>Saving current object</b>".$parent_obj;
483 print_a($objectAttrs);
484 }
485 FAI::save_FAI_object($parent_obj,$objectAttrs);
487 if(($parent_obj != $Current_DN)){
488 msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
489 }
490 }
491 }
492 }
494 /* Reload GOsa si FAI DB/cache
495 */
496 if($reload_fai_classes){
497 if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
498 $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);
499 if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
500 $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'];
501 $tmp = new $evt['CLASS_NAME']($config);
502 $tmp->set_type(TRIGGERED_EVENT);
503 $tmp->add_targets(array("GOsa"));
504 $o_queue = new gosaSupportDaemon();
505 if(!$o_queue->append($tmp)){
506 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
507 }
508 }
509 }
510 }
512 session::set('FAI_objects_to_save',array());
513 }
516 /* this function will remove all unused (deleted) objects,
517 that have no parent object */
518 static function clean_up_releases($Current_DN)
519 {
520 global $config;
521 $ldap = $config->get_ldap_link();
522 $ldap->cd($config->current['BASE']);
524 /* Collect some basic informations and initialize some variables */
525 $base_release = FAI::get_release_dn($Current_DN);
526 $previous_releases = array_reverse(FAI:: get_previous_releases_of_this_release($base_release,true));
527 $Kill = array();
528 $Skip = array();
530 /* We must also include the given release dn */
531 $previous_releases[] = $base_release;
533 /* Walk through all releases */
534 foreach($previous_releases as $release){
536 /* Get fai departments */
537 $deps_to_search = FAI::get_FAI_departments($release);
539 /* For every single department (ou=hoos,ou ..) */
540 foreach($deps_to_search as $fai_base){
542 /* Ldap search for fai classes specified in this release */
543 $ldap->cd($fai_base);
544 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
546 /* check the returned objects, and add/replace them in our return variable */
547 while($attr = $ldap->fetch()){
549 $buffer = array();
550 # $name = str_ireplace($release,"",$attr['dn']);
551 $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
553 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
555 /* Check if this object is required somehow */
556 if(!isset($Skip[$name])){
557 $Kill[$attr['dn']] = $attr['dn'];
558 }
559 }else{
561 /* This object is required (not removed), so do not
562 delete any following sub releases of this object */
563 $Skip[$name] = $attr['dn'];
564 }
565 }
566 }
567 }
568 return($Kill);
569 }
572 /* Remove numeric index and 'count' from ldap->fetch result */
573 static function prepare_ldap_fetch_to_be_saved($attrs)
574 {
575 foreach($attrs as $key => $value){
576 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
577 unset($attrs[$key]);
578 }
579 if(is_array($value) && isset($value['count'])){
580 unset($attrs[$key]['count']);
581 }
582 }
583 return($attrs);
584 }
587 /* Save given attrs to specified dn*/
588 static function save_FAI_object($dn,$attrs)
589 {
590 global $config;
591 $ldap = $config->get_ldap_link();
592 $ldap->cd($config->current['BASE']);
593 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
594 $ldap->cd($dn);
596 $ldap->cat($dn,array("dn"));
597 if($ldap->count()){
599 /* Remove FAIstate*/
600 if(!isset($attrs['FAIstate'])){
601 $attrs['FAIstate'] = array();
602 }
604 $ldap->modify($attrs);
605 }else{
607 /* Unset description if empty */
608 if(empty($attrs['description'])){
609 unset($attrs['description']);
610 }
612 $ldap->add($attrs);
613 }
614 if (!$ldap->success()){
615 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
616 }
617 }
620 /* Return FAIstate freeze branch or "" for specified release department */
621 static function get_release_tag($dn)
622 {
623 global $config;
624 $ldap = $config->get_ldap_link();
625 $ldap->cd($dn);
626 $ldap->cat($dn,array("FAIstate"));
628 if($ldap->count()){
630 $attr = $ldap->fetch();
631 if(isset($attr['FAIstate'][0])){
632 if(preg_match("/freeze/",$attr['FAIstate'][0])){
633 return("freeze");
634 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
635 return("branch");
636 }
637 }
638 }
639 return("");
640 }
643 static function get_following_releases_that_inherit_this_object($dn)
644 {
645 global $config;
646 $ldap = $config->get_ldap_link();
647 $ldap->cd($config->current['BASE']);
649 $ret = array();
651 /* Get base release */
652 $base_release = FAI::get_release_dn($dn);
654 /* Get previous release dns */
655 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release);
657 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
658 # $dn_suffix = str_ireplace($base_release,"",$dn);
659 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
661 /* Check if given object also exists whitin one of these releases */
662 foreach($sub_releases as $p_release => $name){
664 $check_dn = $dn_suffix.$p_release;
666 $ldap->cat($check_dn,array("dn","objectClass"));
668 if($ldap->count()){
669 //return($ret);
670 }else{
671 $ret[$check_dn]=$check_dn;
672 }
673 }
674 return($ret);
675 }
678 /* Get previous version of the object dn */
679 static function get_parent_release_object($dn,$include_myself=true)
680 {
681 global $config;
682 $ldap = $config->get_ldap_link();
683 $ldap->cd($config->current['BASE']);
684 $previous_releases= array();
686 /* Get base release */
687 $base_release = FAI::get_release_dn($dn);
688 if($include_myself){
689 $previous_releases[] = $base_release;
690 }
692 /* Get previous release dns */
693 $tmp = FAI:: get_previous_releases_of_this_release($base_release,true);
694 foreach($tmp as $release){
695 $previous_releases[] = $release;
696 }
698 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
699 # $dn_suffix = str_ireplace($base_release,"",$dn);
700 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
702 /* Check if given object also exists whitin one of these releases */
703 foreach($previous_releases as $p_release){
704 $check_dn = $dn_suffix.$p_release;
705 $ldap->cat($check_dn,array("dn","objectClass"));
707 if($ldap->count()){
708 return($check_dn);
709 }
710 }
711 return("");
712 }
715 /* return release names of all parent releases */
716 static function get_previous_releases_of_this_release($dn,$flat)
717 {
718 global $config;
719 $ldap = $config->get_ldap_link();
720 $ldap->cd($config->current['BASE']);
721 $ret = array();
723 /* Explode dns into pieces, to be able to build parent dns */
724 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
726 if(!is_array($dns_to_check)){
727 return;
728 }
730 /* Unset first entry which represents the given dn */
731 unset($dns_to_check['count']);
732 unset($dns_to_check[key($dns_to_check)]);
734 /* Create dns addresses and check if this dn is a release dn */
735 $id = 0;
736 while(count($dns_to_check)){
738 /* build parent dn */
739 $new_dn = "";
740 foreach($dns_to_check as $part){
741 $new_dn .= $part.",";
742 }
743 $new_dn .= $config->current['BASE'];
745 /* check if this dn is a release */
746 if(FAI::is_release_department($new_dn)){
747 if($flat){
748 $ret[$id] = $new_dn;
749 }else{
750 $ret = array($new_dn=>$ret);
751 }
752 $id ++;
753 }else{
754 return($ret);
755 }
756 reset($dns_to_check);
757 unset($dns_to_check[key($dns_to_check)]);
758 }
759 return($ret);
760 }
763 /* This function returns all sub release names, recursivly */
764 static function get_sub_releases_of_this_release($dn,$flat = false)
765 {
766 global $config;
767 $res = array();
768 $ldap = $config->get_ldap_link();
769 $ldap->cd($config->current['BASE']);
770 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
771 while($attr = $ldap->fetch()){
773 /* Append department name */
774 if($flat){
775 $res[$attr['dn']] = $attr['ou'][0];
776 }else{
777 $res[$attr['dn']] = array();
778 }
780 /* Get sub release departments of this department */
781 if(in_array("FAIbranch",$attr['objectClass'])) {
782 if($flat){
783 $tmp = FAI:: get_sub_releases_of_this_release($attr['dn'],$flat);
784 foreach($tmp as $dn => $value){
785 $res[$dn]=$value;
786 }
787 }else{
788 $res[$attr['dn']] = FAI:: get_sub_releases_of_this_release($attr['dn']);
789 }
790 }
791 }
792 return($res);
793 }
796 /* Check if the given department is a release department */
797 static function is_release_department($dn)
798 {
799 global $config;
800 $ldap = $config->get_ldap_link();
801 $ldap->cd($config->current['BASE']);
802 $ldap->cat($dn,array("objectClass","ou"));
804 /* Check objectClasses and name to check if this is a release department */
805 if($ldap->count()){
806 $attrs = $ldap->fetch();
808 $ou = "";
809 if(isset($attrs['ou'][0])){
810 $ou = $attrs['ou'][0];
811 }
813 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
814 return($attrs['dn']);
815 }
816 }
817 return(false);
818 }
821 static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
822 {
823 global $config;
824 $start = microtime(TRUE);
825 $source_release = trim($source_release,"/");
827 echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
829 $sub_releases = array();
830 $source_dn = "";
832 $tmp = split("\/",$source_release);
833 foreach($tmp as $part){
834 if(empty($part)){
835 continue;
836 }
837 $source_dn = "ou=".$part.",".$source_dn;
838 $sub_releases[$part] = $source_dn;
839 }
841 /* Get all groups */
842 $ldap =$config->get_ldap_link();
843 $ldap->cd($config->current['BASE']);
844 $ldap->search("(objectClass=posixGroup)",array("dn"));
845 $groups = array();
846 while($attrs = $ldap->fetch()){
847 $groups[$attrs['dn']] = $attrs;
848 }
850 /* Get all FAI releases, to be able to create missing group application releases
851 with the correct type of release (FAIstate=freeze/branch).
852 */
853 $f_releases = array();
854 $ldap->cd ($config->current['BASE']);
855 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
856 while($attrs = $ldap->fetch()){
857 foreach($sub_releases as $sub_rel){
858 if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
859 $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
860 }
861 }
862 }
864 /* Get all group releases */
865 $g_releases = array();
866 foreach($groups as $dn => $data){
867 $ldap->cd($dn);
868 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
869 while($attrs = $ldap->fetch()){
870 $g_releases[$attrs['dn']] = $attrs;
871 }
872 }
874 /* Check if base releases exists.
875 If they do not exist, create them and adapt FAIstate attribute from FAI releases.
876 */
877 foreach($sub_releases as $name => $sub_rel){
879 $FAIstate = "";
880 if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
881 $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
882 }
884 foreach($groups as $dn => $data){
885 if(!isset($g_releases[$sub_rel.$dn])){
886 $ldap->cd($dn);
887 $r_data = array();
888 $r_data['ou'] = $name;
889 $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
890 if(!empty($FAIstate)) {
891 $r_data['FAIstate'] = $FAIstate;
892 }
894 $ldap->cd($sub_rel.$dn) ;
895 $ldap->add($r_data);
896 echo " <b>"._("Object").":</b> ";
897 echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
898 flush();
899 }
900 }
901 }
903 /* Create new release container in each group.
904 */
905 $n_data = array();
906 $n_data = array();
907 $n_data['ou'] = $destination_name;
908 $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
909 if(!empty($type)){
910 $n_data['FAIstate'] = $type."/cow";
911 }
913 foreach($groups as $dn => $att){
914 $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
915 if(!isset($g_releases[$n_dn])){
916 $ldap->cd ($n_dn);
917 $ldap->add($n_data);
918 echo " <b>"._("Object").":</b> ";
919 echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
920 flush();
921 }
922 }
924 /* If the source release is empty, then create a new release by copying
925 all group application menus into a new ou=$destination_name release container.
927 If the source release is not empty.
928 We detect all releases which match the source release dn and copy the contents.
929 */
930 if(empty($source_release)){
931 $source_dns = $groups;
932 }else{
933 $source_dns = array();
934 foreach($g_releases as $dn => $data){
935 if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
936 $source_dns[$dn] = $data;
937 }
938 }
939 }
941 /* Detect all menu object we have to copy
942 */
943 $to_copy = array();
944 foreach($source_dns as $dn => $attrs){
945 $ldap->cd($dn);
946 $ldap->ls("(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry)",$dn,array("dn"));
947 while($attrs = $ldap->fetch()){
948 $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
949 $to_copy[$attrs['dn']] = $destination;
950 }
951 }
953 /* At least create the menu objects object */
954 $plug = new plugin($config);
955 foreach($to_copy as $source => $destination){
956 $ldap->cat($destination);
957 if($ldap->count()){
958 echo " <b>"._("Object").":</b> ";
959 echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
960 flush();
961 }else{
962 $plug->copy($source,$destination);
963 echo " <b>"._("Object").":</b> ";
964 echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
965 flush();
966 }
967 }
968 }
971 /*! \brief Create a new FAI branch.
972 * @param $sourcedn String The source release dn
973 * @param $destinationdn String The destination dn
974 * @param $destinationName String The name of the new release
975 * @param $type String The release type (freeze/branch)
976 * @param $is_first Boolean Use to identify the first func. call when recursivly called.
977 * @param $depth Integer Current depth of recursion.
978 */
979 function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
980 {
981 global $config;
982 error_reporting(E_ALL | E_STRICT);
983 $ldap = $config->get_ldap_link();
984 $basedn = $config->current['BASE'];
985 $delarray = array();
987 /* The following code will output a status string
988 * for each handled object, in a seperate iframe.
989 */
992 /* Display current action information.
993 */
994 if($is_first){
995 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
996 }else{
997 if(preg_match("/^ou=/",$sourcedn)){
998 echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
999 }else{
1000 $tmp = split(",",$sourcedn);
1001 echo " <b>"._("Object").":</b> ";
1002 $deststr = LDAP::fix($destinationdn);
1003 if(strlen($deststr) > 96){
1004 $deststr = substr($deststr,0,96)."...";
1005 }
1006 echo $deststr."<br>";
1007 }
1008 }
1009 /* .. immediately display infos */
1010 flush();
1012 /* Check if destination entry already exists
1013 */
1014 $ldap->cat($destinationdn);
1015 if($ldap->count()){
1016 echo _("Could not create new release, the destination dn is already in use.");
1017 return;
1018 }else{
1020 $ldap->clearResult();
1022 /* Get source entry
1023 * if it does not exist, abort here.
1024 */
1025 $ldap->cd($basedn);
1026 $ldap->cat($sourcedn);
1027 $attr = $ldap->fetch();
1028 if((!$attr) || (count($attr)) ==0) {
1029 echo _("Error while fetching source dn - aborted!");
1030 return;
1031 }
1033 /* The current object we want to create is an department.
1034 * Create the department and add the FAIbranch tag.
1035 */
1036 if(in_array("organizationalUnit",$attr['objectClass'])){
1037 $attr['dn'] = LDAP::convert($destinationdn);
1038 $ldap->cd($basedn);
1039 $ldap->create_missing_trees($destinationdn);
1040 $ldap->cd($destinationdn);
1042 /* If is first entry, append FAIbranch to department entry */
1043 if($is_first){
1044 $ldap->cat($destinationdn);
1045 $attr= $ldap->fetch();
1046 /* Filter unneeded informations */
1047 foreach($attr as $key => $value){
1048 if(is_numeric($key)) unset($attr[$key]);
1049 if(isset($attr[$key]['count'])){
1050 if(is_array($attr[$key])){
1051 unset($attr[$key]['count']);
1052 }
1053 }
1054 }
1056 unset($attr['count']);
1057 unset($attr['dn']);
1059 /* Add marking attribute */
1060 $attr['objectClass'][] = "FAIbranch";
1062 /* Add this entry */
1063 $ldap->modify($attr);
1064 }
1065 }else{
1067 /* Replicate all relevant FAI objects here.
1068 * FAI objects, Apps and Mimetypes.
1069 * Get all attributes as binary value, to ensure that Icon, File template aso
1070 * are created correctly.
1071 */
1072 foreach($attr as $key => $value){
1074 if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1075 $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1076 $ei= ldap_first_entry($ldap->cid, $sr);
1077 if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1078 $attr[$key] = $tmp;
1079 }
1080 }
1082 if(is_numeric($key)) unset($attr[$key]);
1083 if(isset($attr[$key]['count'])){
1084 if(is_array($attr[$key])){
1085 unset($attr[$key]['count']);
1086 }
1087 }
1088 }
1089 unset($attr['count']);
1090 unset($attr['dn']);
1092 /* Add entry
1093 */
1094 $ldap->cd($destinationdn);
1095 $ldap->cat($destinationdn);
1097 $a = $ldap->fetch();
1098 if(!count($a)){
1099 $ldap->add($attr);
1100 }
1102 if(!$ldap->success()){
1104 /* Some error occurred */
1105 print "---------------------------------------------";
1106 print $ldap->get_error()."<br>";
1107 print $sourcedn."<br>";
1108 print $destinationdn."<br>";
1109 print_a( $attr);
1110 exit();
1111 }
1112 }
1113 }
1115 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1117 /* Prepare for recursive copy.
1118 * Get all object within the source dn and
1119 * call the recursive copy for each.
1120 */
1121 $ldap->ls ("(objectClass=*)",$sourcedn);
1122 while ($ldap->fetch()){
1123 $deldn= $ldap->getDN();
1124 $delarray[$deldn]= strlen($deldn);
1125 }
1126 asort ($delarray);
1127 reset ($delarray);
1128 $depth ++;
1129 foreach($delarray as $dn => $bla){
1130 if($dn != $destinationdn){
1131 $ldap->cd($basedn);
1132 $item = $ldap->fetch($ldap->cat($dn));
1133 if(!in_array("FAIbranch",$item['objectClass'])){
1134 FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1135 }
1136 }
1137 }
1138 if($is_first){
1139 echo "<p class='seperator'> </p>";
1140 }
1141 }
1145 /* This function returns the dn of the object release */
1146 static function get_release_dn($Current_DN)
1147 {
1148 global $config;
1149 $ldap = $config->get_ldap_link();
1150 $ldap->cd($config->current['BASE']);
1152 /* Split dn into pices */
1153 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1155 if(!is_array($dns_to_check)){
1156 return;
1157 }
1159 /* Use dn pieces, to create sub dns like
1160 ou=test,ou=1,ou=0...
1161 ou=1,ou=0...
1162 ou=0...
1163 To check which dn is our release container.
1164 */
1165 unset($dns_to_check['count']);
1166 while(count($dns_to_check)){
1168 /* Create dn */
1169 $new_dn = "";
1170 foreach($dns_to_check as $part){
1171 $new_dn .= $part.",";
1172 }
1173 $new_dn .= $config->current['BASE'];
1175 /* Check if this dn is a release dn */
1176 if(FAI::is_release_department($new_dn)){
1177 return($new_dn);
1178 }
1180 /* Remove first element of dn pieces */
1181 reset($dns_to_check);
1182 unset($dns_to_check[key($dns_to_check)]);
1183 }
1184 return("");
1185 }
1186 }
1191 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1192 ?>