78861fb18e299995febf183880edc0e8d011f9c0
1 <?php
3 define("DEBUG_FAI_FUNC",FALSE);
6 class FAI
7 {
9 /* TEST PHASE .... */
11 static function get_all_objects_for_given_object($dn,$filter,$detailed = false)
12 {
13 $res = FAI::get_all_objects_for_given_base($dn,$filter,$detailed);
14 $name = preg_replace("/,ou=.*$/","",$dn);
15 $entries = array();
16 foreach($res as $entry_dn => $data){
17 if(!preg_match("/,".$name.",/",$entry_dn)) continue;
18 $entries[$entry_dn] = $data;
19 }
20 return($entries);
21 }
26 /* Returns all object for the given release.
27 This function resolves the releases
28 from base up to the given dn.
29 */
30 static function get_all_objects_for_given_base($Current_DN,$filter,$detailed = false)
31 {
32 global $config;
33 $ldap = $config->get_ldap_link();
34 $ldap->cd($config->current['BASE']);
35 $res = array();
36 $tmp = array();
38 if(!FAI::is_release_department($Current_DN)) {
39 # return($res);
40 }
42 /* Collect some basic informations and initialize some variables */
43 $base_release = FAI::get_release_dn($Current_DN);
44 $previous_releases = array_reverse(FAI::get_previous_releases_of_this_release($base_release,true));
46 $ldap->cat($base_release);
47 $attrs = $ldap->fetch();
48 $FAIstate = "branch";
49 if(isset($attrs['FAIstate'][0])){
50 $FAIstate = $attrs['FAIstate'][0];
51 }
53 /* We must also include the given release dn */
54 $previous_releases[] = $base_release;
56 /* Walk through all releases */
57 foreach($previous_releases as $release){
59 /* Get fai departments */
60 $deps_to_search = FAI::get_FAI_departments($release);
62 /* For every single department (ou=hoos,ou ..) */
63 foreach($deps_to_search as $fai_base){
65 /* Ldap search for fai classes specified in this release */
66 $attributes = array("dn","objectClass","FAIstate","cn","FAIdiskType","FAIlvmDevice","FAIdiskOption");
67 $res_tmp = get_list($filter,"fai",$fai_base,$attributes,GL_SUBSEARCH | GL_SIZELIMIT);
69 /* check the returned objects, and add/replace them in our return variable */
70 foreach($res_tmp as $attr){
72 $buffer = array();
73 $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
75 if(isset($attr['FAIstate'][0])){
76 if(preg_match("/removed$/",$attr['FAIstate'][0])){
77 if(isset($res[$name])){
78 unset($res[$name]);
79 }
80 continue;
81 }
82 }
84 /* Seems to be an inherited class, apply current FAIstate to this classes
85 */
86 if(!preg_match("/".preg_quote($base_release, '/')."$/i",$attr['dn'])){
87 $buffer['FAIstate'] = $FAIstate;
88 }else{
90 /* Seems to be created within this release department.
91 This indicates - it can't be of state "freeze"
92 */
93 if(isset($attr['FAIstate'])){
94 $buffer['FAIstate'] = $attr['FAIstate'][0];
95 }else{
96 $buffer['FAIstate'] = "branch";
97 }
98 }
100 if(isset($attr['FAIdiskType'])){
101 $buffer['FAIdiskType'] = $attr['FAIdiskType'][0];
102 } else {
103 $buffer['FAIdiskType'] = "old";
104 }
106 if(isset($attr['FAIdiskOption'])){
107 $buffer['FAIdiskOption'] = $attr['FAIdiskOption'];
108 } else {
109 $buffer['FAIdiskOption'] = null;
110 }
111 if(isset($attr['FAIlvmDevice'])){
112 $buffer['FAIlvmDevice'] = $attr['FAIlvmDevice'];
113 }
115 /* In detailed mode are some additonal informations visible */
116 if($detailed){
118 /* Create list of parents */
119 if(isset($res[$name])){
120 $buffer = $res[$name];
121 $buffer['parents'][] = $res[$name]['dn'];
122 }else{
123 $buffer['parents'] = array();
124 }
126 /* Append objectClass to resulsts */
127 foreach($attributes as $val){
128 if(isset($attr[$val])){
129 $buffer[$val] = $attr[$val];
130 }
131 }
132 unset($buffer['objectClass']['count']);
133 }
135 /* Add this object to our list */
136 $buffer['dn'] = $attr['dn'];
137 $res[$name] = $buffer;
138 }
139 }
140 }
141 return($res);
142 }
145 /* Return all relevant FAI departments */
146 static function get_FAI_departments($suffix = "")
147 {
148 $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
149 $tmp = array();
150 if(preg_match("/^,/",$suffix)){
151 $suffix = preg_replace("/^,/","",$suffix);
152 }
153 foreach($arr as $name){
154 if(empty($suffix)){
155 $tmp[$name] = "ou=".$name;
156 }else{
157 $tmp[$name] = "ou=".$name.",".$suffix;
158 }
159 }
160 return($tmp);
161 }
164 /* Return all releases within the given base */
165 static function get_all_releases_from_base($dn,$appendedName=false)
166 {
167 global $config;
169 if(!preg_match("/".preg_quote(get_ou('faiBaseRDN'), '/')."/",$dn)){
170 $base = get_ou('faiBaseRDN').$dn;
171 }else{
172 $base = $dn;
173 }
174 $res = array();
176 $ldap = $config->get_ldap_link();
177 $ldap->cd($base);
178 $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
179 while($attrs = $ldap->fetch()){
180 if($appendedName){
181 $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".preg_quote(get_ou('faiBaseRDN'), '/').".*$/","",$attrs['dn']));
182 }else{
183 $res[$attrs['dn']] = $attrs['ou'][0];
184 }
185 }
186 return($res);
187 }
190 /* Add this object to list of objects, that must be checked for release saving */
191 static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
192 {
193 /* Get ldap object */
194 global $config;
195 $addObj['Current_DN'] = $Current_DN;
196 $addObj['objectAttrs']= $objectAttrs;
197 $addObj['removed'] = $removed;
198 $addObj['diff'] = TRUE;
200 if(!$removed){
201 $ldap = $config->get_ldap_link();
202 $ldap->cd($config->current['BASE']);
204 /* Get some basic informations */
205 $parent_obj = FAI::get_parent_release_object($Current_DN);
206 if(!empty($parent_obj)){
207 $ldap->cat($parent_obj,array("*"));
208 $attrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
210 if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
211 $addObj['diff'] = FALSE;
212 }
213 }
214 }else{
216 /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
217 we have to remove this name from all profiles in this release.
218 */
219 $ldap = $config->get_ldap_link();
220 $ldap->cd($config->current['BASE']);
221 $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
223 /* Dont't try to modify non FAIclasses
224 */
225 if(!preg_match("/[^,]+,".preg_quote(get_ou("faiBaseRDN"), '/')."/",$obj_dn)){
226 trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);
227 echo "<br>-->".$Current_DN."<br>";
228 echo "<br>-->".$obj_dn."<br>";
229 }else{
231 /* Get source object and check if it is a base FAIclass
232 */
233 $ldap->cat($obj_dn);
234 $attrs = $ldap->fetch();
235 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
236 if(count(array_intersect($classes,$attrs['objectClass']))){
237 $cn = $attrs['cn'][0];
239 /* Check if this is the last with this name in the current release.
240 In this case we have to remove the package name
241 from all profiles in this release.
242 */
243 $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
244 "(&(objectClass=FAIclass)(cn=".$cn."))");
246 /* Check if this is the last class with this name.
247 */
248 if(count($classes) == 1){
250 /* Get all FAI Profiles
251 */
252 $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
253 "(&(objectClass=FAIprofile)(FAIclass=*))");
255 /* Walk though all profiles and remove the source class name
256 */
257 foreach($profiles as $dn){
258 $ldap->cat($dn['dn']);
259 $attrs = $ldap->fetch();
261 $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
263 /* Check if this Profile uses the source class ($cn)
264 */
265 if(preg_match("/".preg_quote($cn, '/')."/",$attrs['FAIclass'])){
266 $attrs['FAIclass'] = preg_replace("/[ ]*".preg_quote($cn, '/')."[ ]*/i"," ",$attrs['FAIclass']);
267 if(empty($attrs['FAIclass'])){
268 $attrs['FAIclass'] = array();
269 }
270 $ldap->cd($dn['dn']);
271 $ldap->modify($attrs);
273 if (!$ldap->success()){
274 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
275 }
276 }
277 }
278 }
279 }
280 }
281 }
285 $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
286 $FAI_objects_to_save[$Current_DN] = $addObj;
287 session::set('FAI_objects_to_save',$FAI_objects_to_save);
288 }
291 /* Detect differences in attribute arrays */
292 static function array_diff_FAI($ar1,$ar2)
293 {
295 if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
296 $ar1['description'] = "";
297 }
298 if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
299 $ar2['description'] = "";
300 }
302 if(count($ar1) != count($ar2)) {
303 return (true);
304 }
306 foreach($ar1 as $key1 => $val1){
308 if((is_array($val1)) && (count($val1)==1)){
309 $ar1[$key1] = $val1[0];
310 }
312 if(isset($ar2[$key1])&& (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
313 $val1 = $val1[0];
314 $ar2[$key1] = $ar2[$key1][0];
315 }
316 }
317 ksort($ar1);
318 ksort($ar2);
319 if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
320 return(true);
321 }else{
322 return(false);
323 }
324 }
327 static function arr_diff($ar1,$ar2)
328 {
329 foreach($ar1 as $ak1 => $av1){
330 if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
331 return(TRUE);
332 }elseif(is_array($av1)){
333 $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
334 if($ret) {
335 return(TRUE);
336 }
337 }
338 }
339 return(FALSE);
340 }
345 /* check which objects must be saved, and save them */
346 static function save_release_changes_now()
347 {
348 global $config;
349 /* Variable init*/
350 $to_save = array();
352 $reload_fai_classes = FALSE;
354 /* check which objects must be saved */
355 if(!session::is_set('FAI_objects_to_save')){
356 return;
357 }
358 $FAI_objects_to_save = session::get('FAI_objects_to_save');
359 if(!is_array($FAI_objects_to_save)) {
360 print_a(array(session::get('FAI_objects_to_save')));
361 trigger_error("Can't save FAI objects, no array given.");
362 return;
363 }
365 foreach($FAI_objects_to_save as $Current_DN => $object){
366 if($object['diff']){
367 $sub_name = $Current_DN;
368 while(isset($FAI_objects_to_save[$sub_name])){
369 $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name];
370 unset($FAI_objects_to_save[$sub_name]);
371 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
372 }
373 }
374 }
375 session::set('FAI_objects_to_save',$FAI_objects_to_save);
377 /* Sort list of objects that must be saved, and ensure that
378 container objects are safed, before their childs are saved */
379 ksort($to_save);
380 $tmp = array();
381 foreach($to_save as $SubObjects){
382 foreach($SubObjects as $object){
383 $tmp[] = $object;
384 }
385 }
386 $to_save = $tmp;
389 /* Save objects and manage the correct release behavior*/
390 foreach($to_save as $save){
392 $Current_DN = $save['Current_DN'];
393 $removed = $save['removed'];
394 $objectAttrs= $save['objectAttrs'];
396 /* Get ldap object */
397 $ldap = $config->get_ldap_link();
398 $ldap->cd($config->current['BASE']);
400 /* Get some basic informations */
401 $base_release = FAI::get_release_dn($Current_DN);
402 $sub_releases = FAI::get_sub_releases_of_this_release($base_release,true);
403 $parent_obj = FAI::get_parent_release_object($Current_DN);
404 $following_releases = $sub_releases;
406 /* Check if given dn exists or if is a new entry */
407 $ldap->cat($Current_DN);
408 if(!$ldap->count()){
409 $is_new = true;
410 }else{
411 $is_new = false;
412 }
414 /* if parameter removed is true, we have to add FAIstate to the current attrs
415 FAIstate should end with ...|removed after this operation */
416 if($removed ){
417 $ldap->cat($Current_DN);
419 /* Get current object, because we must add the FAIstate ...|removed */
420 if((!$ldap->count()) && !empty($parent_obj)){
421 $ldap->cat($parent_obj);
422 }
424 /* Check if we have found a suiteable object */
425 if(!$ldap->count()){
426 echo "Error can't remove this object ".$Current_DN;
427 return;
428 }else{
430 /* Set FAIstate to current objectAttrs */
431 $objectAttrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
432 if(isset($objectAttrs['FAIstate'][0])){
433 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
434 $objectAttrs['FAIstate'][0] .= "|removed";
435 }
436 }else{
437 $objectAttrs['FAIstate'][0] = "|removed";
438 }
440 /* Force reload of FAI classes */
441 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
442 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
443 $reload_fai_classes = TRUE;
444 }
445 }
446 }
448 /* Check if this a leaf release or not */
449 if(count($following_releases) == 0 ){
451 /* This is a leaf object. It isn't inherited by any other object */
452 if(DEBUG_FAI_FUNC) {
453 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
454 print_a($objectAttrs);
455 }
456 FAI::save_FAI_object($Current_DN,$objectAttrs);
458 /* Force reload of FAI classes */
459 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
460 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
461 $reload_fai_classes = TRUE;
462 }
464 }else{
466 /* This object is inherited by some sub releases */
468 /* Get all releases, that inherit this object */
469 $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
471 /* Get parent object */
472 $ldap->cat($parent_obj);
473 $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
475 /* New objects require special handling */
476 if($is_new){
478 /* Force reload of FAI classes */
479 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
480 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
481 $reload_fai_classes = TRUE;
482 }
484 /* check if there is already an entry named like this,
485 in one of our parent releases */
486 if(!empty($parent_obj)){
487 if(DEBUG_FAI_FUNC) {
488 echo "There is already an entry named like this.</b><br>";
490 echo "<b>Saving main object</b>".$Current_DN;
491 print_a($objectAttrs);
492 }
493 FAI::save_FAI_object($Current_DN,$objectAttrs);
495 foreach($r as $key){
496 if(DEBUG_FAI_FUNC) {
497 echo "<b>Saving parent to following release</b> ".$key;
498 print_a($parent_attrs);
499 }
500 FAI::save_FAI_object($key,$parent_attrs);
501 }
502 }else{
504 if(DEBUG_FAI_FUNC) {
505 echo "<b>Saving main object</b>".$Current_DN;
506 print_a($objectAttrs);
507 }
508 FAI::save_FAI_object($Current_DN,$objectAttrs);
510 if(isset($objectAttrs['FAIstate'])){
511 $objectAttrs['FAIstate'] .= "|removed";
512 }else{
513 $objectAttrs['FAIstate'] = "|removed";
514 }
516 foreach($r as $key ){
517 if(DEBUG_FAI_FUNC) {
518 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
519 print_a($objectAttrs);
520 }
521 FAI::save_FAI_object($key,$objectAttrs);
522 }
523 }
524 }else{
526 /* check if we must patch the follwing release */
527 if(!empty($r)){
529 foreach($r as $key ){
530 if(DEBUG_FAI_FUNC) {
531 echo "<b>Copy current objects original attributes to next release</b> ".$key;
532 print_a($parent_attrs);
533 }
535 /* Append FAIstate tag to ensure that freezed objects stay freezed
536 */
537 $rTag = FAI::get_release_tag(FAI::get_release_dn($key));
538 $parent_attrs['FAIstate'] = $rTag;
539 FAI::save_FAI_object($key,$parent_attrs);
540 }
541 }
543 if(DEBUG_FAI_FUNC) {
544 echo "<b>Saving current object</b>".$parent_obj;
545 print_a($objectAttrs);
546 }
547 FAI::save_FAI_object($parent_obj,$objectAttrs);
549 if(($parent_obj != $Current_DN)){
550 msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
551 }
552 }
553 }
554 }
556 /* Reload GOsa si FAI DB/cache
557 */
558 if($reload_fai_classes){
559 if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
560 $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);
561 if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
562 $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'];
563 $tmp = new $evt['CLASS_NAME']($config);
564 $tmp->set_type(TRIGGERED_EVENT);
565 $tmp->add_targets(array("GOSA"));
566 $o_queue = new gosaSupportDaemon();
567 if(!$o_queue->append($tmp)){
568 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
569 }
570 }
571 }
572 }
574 session::set('FAI_objects_to_save',array());
575 }
578 /* this function will remove all unused (deleted) objects,
579 that have no parent object */
580 static function clean_up_releases($Current_DN)
581 {
582 global $config;
583 $ldap = $config->get_ldap_link();
584 $ldap->cd($config->current['BASE']);
586 /* Collect some basic informations and initialize some variables */
587 $base_release = FAI::get_release_dn($Current_DN);
588 $previous_releases = array_reverse(FAI:: get_previous_releases_of_this_release($base_release,true));
589 $Kill = array();
590 $Skip = array();
592 /* We must also include the given release dn */
593 $previous_releases[] = $base_release;
595 /* Walk through all releases */
596 foreach($previous_releases as $release){
598 /* Get fai departments */
599 $deps_to_search = FAI::get_FAI_departments($release);
601 /* For every single department (ou=hoos,ou ..) */
602 foreach($deps_to_search as $fai_base){
604 /* Ldap search for fai classes specified in this release */
605 $ldap->cd($fai_base);
606 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
608 /* check the returned objects, and add/replace them in our return variable */
609 while($attr = $ldap->fetch()){
611 $buffer = array();
612 # $name = str_ireplace($release,"",$attr['dn']);
613 $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
615 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
617 /* Check if this object is required somehow */
618 if(!isset($Skip[$name])){
619 $Kill[$attr['dn']] = $attr['dn'];
620 }
621 }else{
623 /* This object is required (not removed), so do not
624 delete any following sub releases of this object */
625 $Skip[$name] = $attr['dn'];
626 }
627 }
628 }
629 }
630 return($Kill);
631 }
634 /* Remove numeric index and 'count' from ldap->fetch result */
635 static function prepare_ldap_fetch_to_be_saved($attrs)
636 {
637 foreach($attrs as $key => $value){
638 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
639 unset($attrs[$key]);
640 }
641 if(is_array($value) && isset($value['count'])){
642 unset($attrs[$key]['count']);
643 }
644 }
645 return($attrs);
646 }
649 /* Save given attrs to specified dn*/
650 static function save_FAI_object($dn,$attrs)
651 {
652 global $config;
653 $ldap = $config->get_ldap_link();
654 $ldap->cd($config->current['BASE']);
655 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
656 $ldap->cd($dn);
658 $ldap->cat($dn,array("dn"));
659 if($ldap->count()){
661 /* Remove FAIstate*/
662 if(!isset($attrs['FAIstate'])){
663 $attrs['FAIstate'] = array();
664 }
666 $ldap->modify($attrs);
667 }else{
669 /* Unset description if empty */
670 if(empty($attrs['description'])){
671 unset($attrs['description']);
672 }
674 $ldap->add($attrs);
675 }
676 if (!$ldap->success()){
677 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
678 }
679 }
682 /* Return FAIstate freeze branch or "" for specified release department */
683 static function get_release_tag($dn)
684 {
685 global $config;
686 $ldap = $config->get_ldap_link();
687 $ldap->cd($dn);
688 $ldap->cat($dn,array("FAIstate"));
690 if($ldap->count()){
692 $attr = $ldap->fetch();
693 if(isset($attr['FAIstate'][0])){
694 if(preg_match("/freeze/",$attr['FAIstate'][0])){
695 return("freeze");
696 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
697 return("branch");
698 }
699 }
700 }
701 return("");
702 }
705 static function get_following_releases_that_inherit_this_object($dn)
706 {
707 global $config;
708 $ldap = $config->get_ldap_link();
709 $ldap->cd($config->current['BASE']);
711 $ret = array();
713 /* Get base release */
714 $base_release = FAI::get_release_dn($dn);
716 /* Get previous release dns */
717 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release);
719 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
720 # $dn_suffix = str_ireplace($base_release,"",$dn);
721 $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
723 /* Check if given object also exists whitin one of these releases */
724 foreach($sub_releases as $p_release => $name){
726 $check_dn = $dn_suffix.$p_release;
728 $ldap->cat($check_dn,array("dn","objectClass"));
730 if($ldap->count()){
731 //return($ret);
732 }else{
733 $ret[$check_dn]=$check_dn;
734 }
735 }
736 return($ret);
737 }
740 /* Get previous version of the object dn */
741 static function get_parent_release_object($dn,$include_myself=true)
742 {
743 global $config;
744 $ldap = $config->get_ldap_link();
745 $ldap->cd($config->current['BASE']);
746 $previous_releases= array();
748 /* Get base release */
749 $base_release = FAI::get_release_dn($dn);
750 if($include_myself){
751 $previous_releases[] = $base_release;
752 }
754 /* Get previous release dns */
755 $tmp = FAI:: get_previous_releases_of_this_release($base_release,true);
756 foreach($tmp as $release){
757 $previous_releases[] = $release;
758 }
760 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
761 # $dn_suffix = str_ireplace($base_release,"",$dn);
762 $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
764 /* Check if given object also exists whitin one of these releases */
765 foreach($previous_releases as $p_release){
766 $check_dn = $dn_suffix.$p_release;
767 $ldap->cat($check_dn,array("dn","objectClass"));
769 if($ldap->count()){
770 return($check_dn);
771 }
772 }
773 return("");
774 }
777 /* return release names of all parent releases */
778 static function get_previous_releases_of_this_release($dn,$flat)
779 {
780 global $config;
781 $ldap = $config->get_ldap_link();
782 $ldap->cd($config->current['BASE']);
783 $ret = array();
785 /* Explode dns into pieces, to be able to build parent dns */
786 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$dn));
788 if(!is_array($dns_to_check)){
789 return;
790 }
792 /* Unset first entry which represents the given dn */
793 unset($dns_to_check['count']);
794 unset($dns_to_check[key($dns_to_check)]);
796 /* Create dns addresses and check if this dn is a release dn */
797 $id = 0;
798 while(count($dns_to_check)){
800 /* build parent dn */
801 $new_dn = "";
802 foreach($dns_to_check as $part){
803 $new_dn .= $part.",";
804 }
805 $new_dn .= $config->current['BASE'];
807 /* check if this dn is a release */
808 if(FAI::is_release_department($new_dn)){
809 if($flat){
810 $ret[$id] = $new_dn;
811 }else{
812 $ret = array($new_dn=>$ret);
813 }
814 $id ++;
815 }else{
816 return($ret);
817 }
818 reset($dns_to_check);
819 unset($dns_to_check[key($dns_to_check)]);
820 }
821 return($ret);
822 }
825 /* This function returns all sub release names, recursivly */
826 static function get_sub_releases_of_this_release($dn,$flat = false)
827 {
828 global $config;
829 $res = array();
830 $ldap = $config->get_ldap_link();
831 $ldap->cd($config->current['BASE']);
832 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
833 while($attr = $ldap->fetch()){
835 /* Append department name */
836 if($flat){
837 $res[$attr['dn']] = $attr['ou'][0];
838 }else{
839 $res[$attr['dn']] = array();
840 }
842 /* Get sub release departments of this department */
843 if(in_array("FAIbranch",$attr['objectClass'])) {
844 if($flat){
845 $tmp = FAI:: get_sub_releases_of_this_release($attr['dn'],$flat);
846 foreach($tmp as $dn => $value){
847 $res[$dn]=$value;
848 }
849 }else{
850 $res[$attr['dn']] = FAI:: get_sub_releases_of_this_release($attr['dn']);
851 }
852 }
853 }
854 return($res);
855 }
858 /* Check if the given department is a release department */
859 static function is_release_department($dn)
860 {
861 global $config;
862 $ldap = $config->get_ldap_link();
863 $ldap->cd($config->current['BASE']);
864 $ldap->cat($dn,array("objectClass","ou"));
866 /* Check objectClasses and name to check if this is a release department */
867 if($ldap->count()){
868 $attrs = $ldap->fetch();
870 $ou = "";
871 if(isset($attrs['ou'][0])){
872 $ou = $attrs['ou'][0];
873 }
875 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
876 return($attrs['dn']);
877 }
878 }
879 return(false);
880 }
883 static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
884 {
885 global $config;
886 $start = microtime(TRUE);
887 $source_release = trim($source_release,"/");
889 echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
891 $sub_releases = array();
892 $source_dn = "";
894 $tmp = split("\/",$source_release);
895 foreach($tmp as $part){
896 if(empty($part)){
897 continue;
898 }
899 $source_dn = "ou=".$part.",".$source_dn;
900 $sub_releases[$part] = $source_dn;
901 }
903 /* Get all groups */
904 $ldap =$config->get_ldap_link();
905 $ldap->cd($config->current['BASE']);
906 $ldap->search("(objectClass=posixGroup)",array("dn"));
907 $groups = array();
908 while($attrs = $ldap->fetch()){
909 $groups[$attrs['dn']] = $attrs;
910 }
912 /* Get all FAI releases, to be able to create missing group application releases
913 with the correct type of release (FAIstate=freeze/branch).
914 */
915 $f_releases = array();
916 $ldap->cd ($config->current['BASE']);
917 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
918 while($attrs = $ldap->fetch()){
919 foreach($sub_releases as $sub_rel){
920 if(preg_match("/^".preg_quote($sub_rel.get_ou('faiBaseRDN'), '/')."/",$attrs['dn'])){
921 $f_releases[$sub_rel.get_ou('faiBaseRDN')] = $attrs;
922 }
923 }
924 }
926 /* Get all group releases */
927 $g_releases = array();
928 foreach($groups as $dn => $data){
929 $ldap->cd($dn);
930 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
931 while($attrs = $ldap->fetch()){
932 $g_releases[$attrs['dn']] = $attrs;
933 }
934 }
936 /* Check if base releases exists.
937 If they do not exist, create them and adapt FAIstate attribute from FAI releases.
938 */
939 foreach($sub_releases as $name => $sub_rel){
941 $FAIstate = "";
942 if(isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]) && isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'])){
943 $FAIstate = $f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'][0];
944 }
946 foreach($groups as $dn => $data){
947 if(!isset($g_releases[$sub_rel.$dn])){
948 $ldap->cd($dn);
949 $r_data = array();
950 $r_data['ou'] = $name;
951 $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
952 if(!empty($FAIstate)) {
953 $r_data['FAIstate'] = $FAIstate;
954 }
956 $ldap->cd($sub_rel.$dn) ;
957 $ldap->add($r_data);
958 echo " <b>"._("Object").":</b> ";
959 echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
960 flush();
961 }
962 }
963 }
965 /* Create new release container in each group.
966 */
967 $n_data = array();
968 $n_data = array();
969 $n_data['ou'] = $destination_name;
970 $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
971 if(!empty($type)){
972 $n_data['FAIstate'] = $type."/cow";
973 }
975 foreach($groups as $dn => $att){
976 $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
977 if(!isset($g_releases[$n_dn])){
978 $ldap->cd ($n_dn);
979 $ldap->add($n_data);
980 echo " <b>"._("Object").":</b> ";
981 echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
982 flush();
983 }
984 }
986 /* If the source release is empty, then create a new release by copying
987 all group application menus into a new ou=$destination_name release container.
989 If the source release is not empty.
990 We detect all releases which match the source release dn and copy the contents.
991 */
992 if(empty($source_release)){
993 $source_dns = $groups;
994 }else{
995 $source_dns = array();
996 foreach($g_releases as $dn => $data){
997 if(preg_match("/^".preg_quote($source_dn, '/')."/",$dn)){
998 $source_dns[$dn] = $data;
999 }
1000 }
1001 }
1003 /* Detect all menu object we have to copy
1004 */
1005 $to_copy = array();
1006 foreach($source_dns as $dn => $attrs){
1007 $ldap->cd($dn);
1008 $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
1009 while($attrs = $ldap->fetch()){
1010 $destination = preg_replace("/".preg_quote($dn, '/')."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
1011 $to_copy[$attrs['dn']] = $destination;
1012 }
1013 }
1015 /* At least create the menu objects object */
1016 $plug = new plugin($config);
1017 foreach($to_copy as $source => $destination){
1018 $ldap->cat($destination);
1019 if($ldap->count()){
1020 echo " <b>"._("Object").":</b> ";
1021 echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
1022 flush();
1023 }else{
1024 $plug->copy($source,$destination);
1025 echo " <b>"._("Object").":</b> ";
1026 echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
1027 flush();
1028 }
1029 }
1030 }
1033 /*! \brief Create a new FAI branch.
1034 * @param $sourcedn String The source release dn
1035 * @param $destinationdn String The destination dn
1036 * @param $destinationName String The name of the new release
1037 * @param $type String The release type (freeze/branch)
1038 * @param $is_first Boolean Use to identify the first func. call when recursivly called.
1039 * @param $depth Integer Current depth of recursion.
1040 */
1041 static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1042 {
1043 global $config;
1044 error_reporting(E_ALL | E_STRICT);
1045 $ldap = $config->get_ldap_link();
1046 $basedn = $config->current['BASE'];
1047 $delarray = array();
1049 /* The following code will output a status string
1050 * for each handled object, in a seperate iframe.
1051 */
1054 /* Display current action information.
1055 */
1056 if($is_first){
1057 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1058 }else{
1059 if(preg_match("/^ou=/",$sourcedn)){
1060 echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1061 }else{
1062 $tmp = split(",",$sourcedn);
1063 echo " <b>"._("Object").":</b> ";
1064 $deststr = LDAP::fix($destinationdn);
1065 if(strlen($deststr) > 96){
1066 $deststr = substr($deststr,0,96)."...";
1067 }
1068 echo $deststr."<br>";
1069 }
1070 }
1071 /* .. immediately display infos */
1072 flush();
1074 /* Check if destination entry already exists
1075 */
1076 $ldap->cat($destinationdn);
1077 if($ldap->count()){
1078 echo _("Could not create new release, the destination dn is already in use.");
1079 return;
1080 }else{
1082 $ldap->clearResult();
1084 /* Get source entry
1085 * if it does not exist, abort here.
1086 */
1087 $ldap->cd($basedn);
1088 $ldap->cat($sourcedn);
1089 $attr = $ldap->fetch();
1090 if((!$attr) || (count($attr)) ==0) {
1091 echo _("Error while fetching source dn - aborted!");
1092 return;
1093 }
1095 /* The current object we want to create is an department.
1096 * Create the department and add the FAIbranch tag.
1097 */
1098 if(in_array("organizationalUnit",$attr['objectClass'])){
1099 $attr['dn'] = LDAP::convert($destinationdn);
1100 $ldap->cd($basedn);
1101 $ldap->create_missing_trees($destinationdn);
1102 $ldap->cd($destinationdn);
1104 /* If is first entry, append FAIbranch to department entry */
1105 if($is_first){
1106 $ldap->cat($destinationdn);
1107 $attr= $ldap->fetch();
1108 /* Filter unneeded informations */
1109 foreach($attr as $key => $value){
1110 if(is_numeric($key)) unset($attr[$key]);
1111 if(isset($attr[$key]['count'])){
1112 if(is_array($attr[$key])){
1113 unset($attr[$key]['count']);
1114 }
1115 }
1116 }
1118 unset($attr['count']);
1119 unset($attr['dn']);
1121 /* Add marking attribute */
1122 $attr['objectClass'][] = "FAIbranch";
1123 $attr['FAIstate'] = $type;
1125 /* Add this entry */
1126 $ldap->modify($attr);
1127 }
1128 }else{
1130 /* Replicate all relevant FAI objects here.
1131 * FAI objects, Apps and Mimetypes.
1132 * Get all attributes as binary value, to ensure that Icon, File template aso
1133 * are created correctly.
1134 */
1135 foreach($attr as $key => $value){
1137 if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1138 $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1139 $ei= ldap_first_entry($ldap->cid, $sr);
1140 if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1141 $attr[$key] = $tmp;
1142 }
1143 }
1145 if(is_numeric($key)) unset($attr[$key]);
1146 if(isset($attr[$key]['count'])){
1147 if(is_array($attr[$key])){
1148 unset($attr[$key]['count']);
1149 }
1150 }
1151 }
1152 unset($attr['count']);
1153 unset($attr['dn']);
1154 if(!in_array("FAIobject",$attr['objectClass'])){
1155 $attr['objectClass'][] = "FAIobject";
1156 }
1157 $attr['FAIstate'] = $type;
1159 /* Add entry
1160 */
1161 $ldap->cd($destinationdn);
1162 $ldap->cat($destinationdn);
1164 $a = $ldap->fetch();
1165 if(!count($a)){
1166 $ldap->add($attr);
1167 }
1169 if(!$ldap->success()){
1171 /* Some error occurred */
1172 msg_dialog::display(_("Fatal error"),
1173 sprintf(_("Release creation failed due to ldap errors. Additional informations '%s'."),
1174 $ldap->get_error()."<br>".$sourcedn."<br>".$destinationdn."<br>"),FATAL_ERROR_DIALOG);
1175 exit();
1176 }
1177 }
1178 }
1180 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1182 /* Prepare for recursive copy.
1183 * Get all object within the source dn and
1184 * call the recursive copy for each.
1185 */
1186 $ldap->ls ("(objectClass=*)",$sourcedn);
1187 while ($ldap->fetch()){
1188 $deldn= $ldap->getDN();
1189 $delarray[$deldn]= strlen($deldn);
1190 }
1191 asort ($delarray);
1192 reset ($delarray);
1193 $depth ++;
1194 foreach($delarray as $dn => $bla){
1195 if($dn != $destinationdn){
1196 $ldap->cd($basedn);
1197 $item = $ldap->fetch($ldap->cat($dn));
1198 if(!in_array("FAIbranch",$item['objectClass'])){
1199 FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1200 }
1201 }
1202 }
1203 if($is_first){
1204 echo "<p class='seperator'> </p>";
1205 }
1206 }
1210 /* This function returns the dn of the object release */
1211 static function get_release_dn($Current_DN)
1212 {
1213 global $config;
1214 $ldap = $config->get_ldap_link();
1215 $ldap->cd($config->current['BASE']);
1217 /* Split dn into pices */
1218 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$Current_DN));
1220 if(!is_array($dns_to_check)){
1221 return;
1222 }
1224 /* Use dn pieces, to create sub dns like
1225 ou=test,ou=1,ou=0...
1226 ou=1,ou=0...
1227 ou=0...
1228 To check which dn is our release container.
1229 */
1230 unset($dns_to_check['count']);
1231 while(count($dns_to_check)){
1233 /* Create dn */
1234 $new_dn = "";
1235 foreach($dns_to_check as $part){
1236 $new_dn .= $part.",";
1237 }
1238 $new_dn .= $config->current['BASE'];
1240 /* Check if this dn is a release dn */
1241 if(FAI::is_release_department($new_dn)){
1242 return($new_dn);
1243 }
1245 /* Remove first element of dn pieces */
1246 reset($dns_to_check);
1247 unset($dns_to_check[key($dns_to_check)]);
1248 }
1249 return("");
1250 }
1251 }
1256 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1257 ?>