1123681049897bb186f1f014d1405c3356808b94
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");
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['FAIlvmDevice'])){
107 $buffer['FAIlvmDevice'] = $attr['FAIlvmDevice'];
108 }
110 /* In detailed mode are some additonal informations visible */
111 if($detailed){
113 /* Create list of parents */
114 if(isset($res[$name])){
115 $buffer = $res[$name];
116 $buffer['parents'][] = $res[$name]['dn'];
117 }else{
118 $buffer['parents'] = array();
119 }
121 /* Append objectClass to resulsts */
122 foreach($attributes as $val){
123 if(isset($attr[$val])){
124 $buffer[$val] = $attr[$val];
125 }
126 }
127 unset($buffer['objectClass']['count']);
128 }
130 /* Add this object to our list */
131 $buffer['dn'] = $attr['dn'];
132 $res[$name] = $buffer;
133 }
134 }
135 }
136 return($res);
137 }
140 /* Return all relevant FAI departments */
141 static function get_FAI_departments($suffix = "")
142 {
143 $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
144 $tmp = array();
145 if(preg_match("/^,/",$suffix)){
146 $suffix = preg_replace("/^,/","",$suffix);
147 }
148 foreach($arr as $name){
149 if(empty($suffix)){
150 $tmp[$name] = "ou=".$name;
151 }else{
152 $tmp[$name] = "ou=".$name.",".$suffix;
153 }
154 }
155 return($tmp);
156 }
159 /* Return all releases within the given base */
160 static function get_all_releases_from_base($dn,$appendedName=false)
161 {
162 global $config;
164 if(!preg_match("/".preg_quote(get_ou('faiBaseRDN'), '/')."/",$dn)){
165 $base = get_ou('faiBaseRDN').$dn;
166 }else{
167 $base = $dn;
168 }
169 $res = array();
171 $ldap = $config->get_ldap_link();
172 $ldap->cd($base);
173 $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
174 while($attrs = $ldap->fetch()){
175 if($appendedName){
176 $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".preg_quote(get_ou('faiBaseRDN'), '/').".*$/","",$attrs['dn']));
177 }else{
178 $res[$attrs['dn']] = $attrs['ou'][0];
179 }
180 }
181 return($res);
182 }
185 /* Add this object to list of objects, that must be checked for release saving */
186 static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
187 {
188 /* Get ldap object */
189 global $config;
190 $addObj['Current_DN'] = $Current_DN;
191 $addObj['objectAttrs']= $objectAttrs;
192 $addObj['removed'] = $removed;
193 $addObj['diff'] = TRUE;
195 if(!$removed){
196 $ldap = $config->get_ldap_link();
197 $ldap->cd($config->current['BASE']);
199 /* Get some basic informations */
200 $parent_obj = FAI::get_parent_release_object($Current_DN);
201 if(!empty($parent_obj)){
202 $ldap->cat($parent_obj,array("*"));
203 $attrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
205 if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
206 $addObj['diff'] = FALSE;
207 }
208 }
209 }else{
211 /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
212 we have to remove this name from all profiles in this release.
213 */
214 $ldap = $config->get_ldap_link();
215 $ldap->cd($config->current['BASE']);
216 $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
218 /* Dont't try to modify non FAIclasses
219 */
220 if(!preg_match("/[^,]+,".preg_quote(get_ou("faiBaseRDN"), '/')."/",$obj_dn)){
221 trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);
222 echo "<br>-->".$Current_DN."<br>";
223 echo "<br>-->".$obj_dn."<br>";
224 }else{
226 /* Get source object and check if it is a base FAIclass
227 */
228 $ldap->cat($obj_dn);
229 $attrs = $ldap->fetch();
230 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
231 if(count(array_intersect($classes,$attrs['objectClass']))){
232 $cn = $attrs['cn'][0];
234 /* Check if this is the last with this name in the current release.
235 In this case we have to remove the package name
236 from all profiles in this release.
237 */
238 $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
239 "(&(objectClass=FAIclass)(cn=".$cn."))");
241 /* Check if this is the last class with this name.
242 */
243 if(count($classes) == 1){
245 /* Get all FAI Profiles
246 */
247 $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
248 "(&(objectClass=FAIprofile)(FAIclass=*))");
250 /* Walk though all profiles and remove the source class name
251 */
252 foreach($profiles as $dn){
253 $ldap->cat($dn['dn']);
254 $attrs = $ldap->fetch();
256 $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
258 /* Check if this Profile uses the source class ($cn)
259 */
260 if(preg_match("/".preg_quote($cn, '/')."/",$attrs['FAIclass'])){
261 $attrs['FAIclass'] = preg_replace("/[ ]*".preg_quote($cn, '/')."[ ]*/i"," ",$attrs['FAIclass']);
262 if(empty($attrs['FAIclass'])){
263 $attrs['FAIclass'] = array();
264 }
265 $ldap->cd($dn['dn']);
266 $ldap->modify($attrs);
268 if (!$ldap->success()){
269 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
270 }
271 }
272 }
273 }
274 }
275 }
276 }
280 $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
281 $FAI_objects_to_save[$Current_DN] = $addObj;
282 session::set('FAI_objects_to_save',$FAI_objects_to_save);
283 }
286 /* Detect differences in attribute arrays */
287 static function array_diff_FAI($ar1,$ar2)
288 {
290 if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
291 $ar1['description'] = "";
292 }
293 if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
294 $ar2['description'] = "";
295 }
297 if(count($ar1) != count($ar2)) {
298 return (true);
299 }
301 foreach($ar1 as $key1 => $val1){
303 if((is_array($val1)) && (count($val1)==1)){
304 $ar1[$key1] = $val1[0];
305 }
307 if(isset($ar2[$key1])&& (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
308 $val1 = $val1[0];
309 $ar2[$key1] = $ar2[$key1][0];
310 }
311 }
312 ksort($ar1);
313 ksort($ar2);
314 if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
315 return(true);
316 }else{
317 return(false);
318 }
319 }
322 static function arr_diff($ar1,$ar2)
323 {
324 foreach($ar1 as $ak1 => $av1){
325 if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
326 return(TRUE);
327 }elseif(is_array($av1)){
328 $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
329 if($ret) {
330 return(TRUE);
331 }
332 }
333 }
334 return(FALSE);
335 }
340 /* check which objects must be saved, and save them */
341 static function save_release_changes_now()
342 {
343 global $config;
344 /* Variable init*/
345 $to_save = array();
347 $reload_fai_classes = FALSE;
349 /* check which objects must be saved */
350 if(!session::is_set('FAI_objects_to_save')){
351 return;
352 }
353 $FAI_objects_to_save = session::get('FAI_objects_to_save');
354 if(!is_array($FAI_objects_to_save)) {
355 print_a(array(session::get('FAI_objects_to_save')));
356 trigger_error("Can't save FAI objects, no array given.");
357 return;
358 }
360 foreach($FAI_objects_to_save as $Current_DN => $object){
361 if($object['diff']){
362 $sub_name = $Current_DN;
363 while(isset($FAI_objects_to_save[$sub_name])){
364 $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name];
365 unset($FAI_objects_to_save[$sub_name]);
366 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
367 }
368 }
369 }
370 session::set('FAI_objects_to_save',$FAI_objects_to_save);
372 /* Sort list of objects that must be saved, and ensure that
373 container objects are safed, before their childs are saved */
374 ksort($to_save);
375 $tmp = array();
376 foreach($to_save as $SubObjects){
377 foreach($SubObjects as $object){
378 $tmp[] = $object;
379 }
380 }
381 $to_save = $tmp;
384 /* Save objects and manage the correct release behavior*/
385 foreach($to_save as $save){
387 $Current_DN = $save['Current_DN'];
388 $removed = $save['removed'];
389 $objectAttrs= $save['objectAttrs'];
391 /* Get ldap object */
392 $ldap = $config->get_ldap_link();
393 $ldap->cd($config->current['BASE']);
395 /* Get some basic informations */
396 $base_release = FAI::get_release_dn($Current_DN);
397 $sub_releases = FAI::get_sub_releases_of_this_release($base_release,true);
398 $parent_obj = FAI::get_parent_release_object($Current_DN);
399 $following_releases = $sub_releases;
401 /* Check if given dn exists or if is a new entry */
402 $ldap->cat($Current_DN);
403 if(!$ldap->count()){
404 $is_new = true;
405 }else{
406 $is_new = false;
407 }
409 /* if parameter removed is true, we have to add FAIstate to the current attrs
410 FAIstate should end with ...|removed after this operation */
411 if($removed ){
412 $ldap->cat($Current_DN);
414 /* Get current object, because we must add the FAIstate ...|removed */
415 if((!$ldap->count()) && !empty($parent_obj)){
416 $ldap->cat($parent_obj);
417 }
419 /* Check if we have found a suiteable object */
420 if(!$ldap->count()){
421 echo "Error can't remove this object ".$Current_DN;
422 return;
423 }else{
425 /* Set FAIstate to current objectAttrs */
426 $objectAttrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
427 if(isset($objectAttrs['FAIstate'][0])){
428 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
429 $objectAttrs['FAIstate'][0] .= "|removed";
430 }
431 }else{
432 $objectAttrs['FAIstate'][0] = "|removed";
433 }
435 /* Force reload of FAI classes */
436 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
437 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
438 $reload_fai_classes = TRUE;
439 }
440 }
441 }
443 /* Check if this a leaf release or not */
444 if(count($following_releases) == 0 ){
446 /* This is a leaf object. It isn't inherited by any other object */
447 if(DEBUG_FAI_FUNC) {
448 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
449 print_a($objectAttrs);
450 }
451 FAI::save_FAI_object($Current_DN,$objectAttrs);
453 /* Force reload of FAI classes */
454 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
455 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
456 $reload_fai_classes = TRUE;
457 }
459 }else{
461 /* This object is inherited by some sub releases */
463 /* Get all releases, that inherit this object */
464 $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
466 /* Get parent object */
467 $ldap->cat($parent_obj);
468 $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
470 /* New objects require special handling */
471 if($is_new){
473 /* Force reload of FAI classes */
474 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
475 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
476 $reload_fai_classes = TRUE;
477 }
479 /* check if there is already an entry named like this,
480 in one of our parent releases */
481 if(!empty($parent_obj)){
482 if(DEBUG_FAI_FUNC) {
483 echo "There is already an entry named like this.</b><br>";
485 echo "<b>Saving main object</b>".$Current_DN;
486 print_a($objectAttrs);
487 }
488 FAI::save_FAI_object($Current_DN,$objectAttrs);
490 foreach($r as $key){
491 if(DEBUG_FAI_FUNC) {
492 echo "<b>Saving parent to following release</b> ".$key;
493 print_a($parent_attrs);
494 }
495 FAI::save_FAI_object($key,$parent_attrs);
496 }
497 }else{
499 if(DEBUG_FAI_FUNC) {
500 echo "<b>Saving main object</b>".$Current_DN;
501 print_a($objectAttrs);
502 }
503 FAI::save_FAI_object($Current_DN,$objectAttrs);
505 if(isset($objectAttrs['FAIstate'])){
506 $objectAttrs['FAIstate'] .= "|removed";
507 }else{
508 $objectAttrs['FAIstate'] = "|removed";
509 }
511 foreach($r as $key ){
512 if(DEBUG_FAI_FUNC) {
513 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
514 print_a($objectAttrs);
515 }
516 FAI::save_FAI_object($key,$objectAttrs);
517 }
518 }
519 }else{
521 /* check if we must patch the follwing release */
522 if(!empty($r)){
524 foreach($r as $key ){
525 if(DEBUG_FAI_FUNC) {
526 echo "<b>Copy current objects original attributes to next release</b> ".$key;
527 print_a($parent_attrs);
528 }
530 /* Append FAIstate tag to ensure that freezed objects stay freezed
531 */
532 $rTag = FAI::get_release_tag(FAI::get_release_dn($key));
533 $parent_attrs['FAIstate'] = $rTag;
534 FAI::save_FAI_object($key,$parent_attrs);
535 }
536 }
538 if(DEBUG_FAI_FUNC) {
539 echo "<b>Saving current object</b>".$parent_obj;
540 print_a($objectAttrs);
541 }
542 FAI::save_FAI_object($parent_obj,$objectAttrs);
544 if(($parent_obj != $Current_DN)){
545 msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
546 }
547 }
548 }
549 }
551 /* Reload GOsa si FAI DB/cache
552 */
553 if($reload_fai_classes){
554 if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
555 $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);
556 if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
557 $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'];
558 $tmp = new $evt['CLASS_NAME']($config);
559 $tmp->set_type(TRIGGERED_EVENT);
560 $tmp->add_targets(array("GOSA"));
561 $o_queue = new gosaSupportDaemon();
562 if(!$o_queue->append($tmp)){
563 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
564 }
565 }
566 }
567 }
569 session::set('FAI_objects_to_save',array());
570 }
573 /* this function will remove all unused (deleted) objects,
574 that have no parent object */
575 static function clean_up_releases($Current_DN)
576 {
577 global $config;
578 $ldap = $config->get_ldap_link();
579 $ldap->cd($config->current['BASE']);
581 /* Collect some basic informations and initialize some variables */
582 $base_release = FAI::get_release_dn($Current_DN);
583 $previous_releases = array_reverse(FAI:: get_previous_releases_of_this_release($base_release,true));
584 $Kill = array();
585 $Skip = array();
587 /* We must also include the given release dn */
588 $previous_releases[] = $base_release;
590 /* Walk through all releases */
591 foreach($previous_releases as $release){
593 /* Get fai departments */
594 $deps_to_search = FAI::get_FAI_departments($release);
596 /* For every single department (ou=hoos,ou ..) */
597 foreach($deps_to_search as $fai_base){
599 /* Ldap search for fai classes specified in this release */
600 $ldap->cd($fai_base);
601 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
603 /* check the returned objects, and add/replace them in our return variable */
604 while($attr = $ldap->fetch()){
606 $buffer = array();
607 # $name = str_ireplace($release,"",$attr['dn']);
608 $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
610 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
612 /* Check if this object is required somehow */
613 if(!isset($Skip[$name])){
614 $Kill[$attr['dn']] = $attr['dn'];
615 }
616 }else{
618 /* This object is required (not removed), so do not
619 delete any following sub releases of this object */
620 $Skip[$name] = $attr['dn'];
621 }
622 }
623 }
624 }
625 return($Kill);
626 }
629 /* Remove numeric index and 'count' from ldap->fetch result */
630 static function prepare_ldap_fetch_to_be_saved($attrs)
631 {
632 foreach($attrs as $key => $value){
633 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
634 unset($attrs[$key]);
635 }
636 if(is_array($value) && isset($value['count'])){
637 unset($attrs[$key]['count']);
638 }
639 }
640 return($attrs);
641 }
644 /* Save given attrs to specified dn*/
645 static function save_FAI_object($dn,$attrs)
646 {
647 global $config;
648 $ldap = $config->get_ldap_link();
649 $ldap->cd($config->current['BASE']);
650 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
651 $ldap->cd($dn);
653 $ldap->cat($dn,array("dn"));
654 if($ldap->count()){
656 /* Remove FAIstate*/
657 if(!isset($attrs['FAIstate'])){
658 $attrs['FAIstate'] = array();
659 }
661 $ldap->modify($attrs);
662 }else{
664 /* Unset description if empty */
665 if(empty($attrs['description'])){
666 unset($attrs['description']);
667 }
669 $ldap->add($attrs);
670 }
671 if (!$ldap->success()){
672 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
673 }
674 }
677 /* Return FAIstate freeze branch or "" for specified release department */
678 static function get_release_tag($dn)
679 {
680 global $config;
681 $ldap = $config->get_ldap_link();
682 $ldap->cd($dn);
683 $ldap->cat($dn,array("FAIstate"));
685 if($ldap->count()){
687 $attr = $ldap->fetch();
688 if(isset($attr['FAIstate'][0])){
689 if(preg_match("/freeze/",$attr['FAIstate'][0])){
690 return("freeze");
691 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
692 return("branch");
693 }
694 }
695 }
696 return("");
697 }
700 static function get_following_releases_that_inherit_this_object($dn)
701 {
702 global $config;
703 $ldap = $config->get_ldap_link();
704 $ldap->cd($config->current['BASE']);
706 $ret = array();
708 /* Get base release */
709 $base_release = FAI::get_release_dn($dn);
711 /* Get previous release dns */
712 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release);
714 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
715 # $dn_suffix = str_ireplace($base_release,"",$dn);
716 $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
718 /* Check if given object also exists whitin one of these releases */
719 foreach($sub_releases as $p_release => $name){
721 $check_dn = $dn_suffix.$p_release;
723 $ldap->cat($check_dn,array("dn","objectClass"));
725 if($ldap->count()){
726 //return($ret);
727 }else{
728 $ret[$check_dn]=$check_dn;
729 }
730 }
731 return($ret);
732 }
735 /* Get previous version of the object dn */
736 static function get_parent_release_object($dn,$include_myself=true)
737 {
738 global $config;
739 $ldap = $config->get_ldap_link();
740 $ldap->cd($config->current['BASE']);
741 $previous_releases= array();
743 /* Get base release */
744 $base_release = FAI::get_release_dn($dn);
745 if($include_myself){
746 $previous_releases[] = $base_release;
747 }
749 /* Get previous release dns */
750 $tmp = FAI:: get_previous_releases_of_this_release($base_release,true);
751 foreach($tmp as $release){
752 $previous_releases[] = $release;
753 }
755 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
756 # $dn_suffix = str_ireplace($base_release,"",$dn);
757 $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
759 /* Check if given object also exists whitin one of these releases */
760 foreach($previous_releases as $p_release){
761 $check_dn = $dn_suffix.$p_release;
762 $ldap->cat($check_dn,array("dn","objectClass"));
764 if($ldap->count()){
765 return($check_dn);
766 }
767 }
768 return("");
769 }
772 /* return release names of all parent releases */
773 static function get_previous_releases_of_this_release($dn,$flat)
774 {
775 global $config;
776 $ldap = $config->get_ldap_link();
777 $ldap->cd($config->current['BASE']);
778 $ret = array();
780 /* Explode dns into pieces, to be able to build parent dns */
781 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$dn));
783 if(!is_array($dns_to_check)){
784 return;
785 }
787 /* Unset first entry which represents the given dn */
788 unset($dns_to_check['count']);
789 unset($dns_to_check[key($dns_to_check)]);
791 /* Create dns addresses and check if this dn is a release dn */
792 $id = 0;
793 while(count($dns_to_check)){
795 /* build parent dn */
796 $new_dn = "";
797 foreach($dns_to_check as $part){
798 $new_dn .= $part.",";
799 }
800 $new_dn .= $config->current['BASE'];
802 /* check if this dn is a release */
803 if(FAI::is_release_department($new_dn)){
804 if($flat){
805 $ret[$id] = $new_dn;
806 }else{
807 $ret = array($new_dn=>$ret);
808 }
809 $id ++;
810 }else{
811 return($ret);
812 }
813 reset($dns_to_check);
814 unset($dns_to_check[key($dns_to_check)]);
815 }
816 return($ret);
817 }
820 /* This function returns all sub release names, recursivly */
821 static function get_sub_releases_of_this_release($dn,$flat = false)
822 {
823 global $config;
824 $res = array();
825 $ldap = $config->get_ldap_link();
826 $ldap->cd($config->current['BASE']);
827 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
828 while($attr = $ldap->fetch()){
830 /* Append department name */
831 if($flat){
832 $res[$attr['dn']] = $attr['ou'][0];
833 }else{
834 $res[$attr['dn']] = array();
835 }
837 /* Get sub release departments of this department */
838 if(in_array("FAIbranch",$attr['objectClass'])) {
839 if($flat){
840 $tmp = FAI:: get_sub_releases_of_this_release($attr['dn'],$flat);
841 foreach($tmp as $dn => $value){
842 $res[$dn]=$value;
843 }
844 }else{
845 $res[$attr['dn']] = FAI:: get_sub_releases_of_this_release($attr['dn']);
846 }
847 }
848 }
849 return($res);
850 }
853 /* Check if the given department is a release department */
854 static function is_release_department($dn)
855 {
856 global $config;
857 $ldap = $config->get_ldap_link();
858 $ldap->cd($config->current['BASE']);
859 $ldap->cat($dn,array("objectClass","ou"));
861 /* Check objectClasses and name to check if this is a release department */
862 if($ldap->count()){
863 $attrs = $ldap->fetch();
865 $ou = "";
866 if(isset($attrs['ou'][0])){
867 $ou = $attrs['ou'][0];
868 }
870 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
871 return($attrs['dn']);
872 }
873 }
874 return(false);
875 }
878 static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
879 {
880 global $config;
881 $start = microtime(TRUE);
882 $source_release = trim($source_release,"/");
884 echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
886 $sub_releases = array();
887 $source_dn = "";
889 $tmp = split("\/",$source_release);
890 foreach($tmp as $part){
891 if(empty($part)){
892 continue;
893 }
894 $source_dn = "ou=".$part.",".$source_dn;
895 $sub_releases[$part] = $source_dn;
896 }
898 /* Get all groups */
899 $ldap =$config->get_ldap_link();
900 $ldap->cd($config->current['BASE']);
901 $ldap->search("(objectClass=posixGroup)",array("dn"));
902 $groups = array();
903 while($attrs = $ldap->fetch()){
904 $groups[$attrs['dn']] = $attrs;
905 }
907 /* Get all FAI releases, to be able to create missing group application releases
908 with the correct type of release (FAIstate=freeze/branch).
909 */
910 $f_releases = array();
911 $ldap->cd ($config->current['BASE']);
912 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
913 while($attrs = $ldap->fetch()){
914 foreach($sub_releases as $sub_rel){
915 if(preg_match("/^".preg_quote($sub_rel.get_ou('faiBaseRDN'), '/')."/",$attrs['dn'])){
916 $f_releases[$sub_rel.get_ou('faiBaseRDN')] = $attrs;
917 }
918 }
919 }
921 /* Get all group releases */
922 $g_releases = array();
923 foreach($groups as $dn => $data){
924 $ldap->cd($dn);
925 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
926 while($attrs = $ldap->fetch()){
927 $g_releases[$attrs['dn']] = $attrs;
928 }
929 }
931 /* Check if base releases exists.
932 If they do not exist, create them and adapt FAIstate attribute from FAI releases.
933 */
934 foreach($sub_releases as $name => $sub_rel){
936 $FAIstate = "";
937 if(isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]) && isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'])){
938 $FAIstate = $f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'][0];
939 }
941 foreach($groups as $dn => $data){
942 if(!isset($g_releases[$sub_rel.$dn])){
943 $ldap->cd($dn);
944 $r_data = array();
945 $r_data['ou'] = $name;
946 $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
947 if(!empty($FAIstate)) {
948 $r_data['FAIstate'] = $FAIstate;
949 }
951 $ldap->cd($sub_rel.$dn) ;
952 $ldap->add($r_data);
953 echo " <b>"._("Object").":</b> ";
954 echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
955 flush();
956 }
957 }
958 }
960 /* Create new release container in each group.
961 */
962 $n_data = array();
963 $n_data = array();
964 $n_data['ou'] = $destination_name;
965 $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
966 if(!empty($type)){
967 $n_data['FAIstate'] = $type."/cow";
968 }
970 foreach($groups as $dn => $att){
971 $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
972 if(!isset($g_releases[$n_dn])){
973 $ldap->cd ($n_dn);
974 $ldap->add($n_data);
975 echo " <b>"._("Object").":</b> ";
976 echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
977 flush();
978 }
979 }
981 /* If the source release is empty, then create a new release by copying
982 all group application menus into a new ou=$destination_name release container.
984 If the source release is not empty.
985 We detect all releases which match the source release dn and copy the contents.
986 */
987 if(empty($source_release)){
988 $source_dns = $groups;
989 }else{
990 $source_dns = array();
991 foreach($g_releases as $dn => $data){
992 if(preg_match("/^".preg_quote($source_dn, '/')."/",$dn)){
993 $source_dns[$dn] = $data;
994 }
995 }
996 }
998 /* Detect all menu object we have to copy
999 */
1000 $to_copy = array();
1001 foreach($source_dns as $dn => $attrs){
1002 $ldap->cd($dn);
1003 $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
1004 while($attrs = $ldap->fetch()){
1005 $destination = preg_replace("/".preg_quote($dn, '/')."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
1006 $to_copy[$attrs['dn']] = $destination;
1007 }
1008 }
1010 /* At least create the menu objects object */
1011 $plug = new plugin($config);
1012 foreach($to_copy as $source => $destination){
1013 $ldap->cat($destination);
1014 if($ldap->count()){
1015 echo " <b>"._("Object").":</b> ";
1016 echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
1017 flush();
1018 }else{
1019 $plug->copy($source,$destination);
1020 echo " <b>"._("Object").":</b> ";
1021 echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
1022 flush();
1023 }
1024 }
1025 }
1028 /*! \brief Create a new FAI branch.
1029 * @param $sourcedn String The source release dn
1030 * @param $destinationdn String The destination dn
1031 * @param $destinationName String The name of the new release
1032 * @param $type String The release type (freeze/branch)
1033 * @param $is_first Boolean Use to identify the first func. call when recursivly called.
1034 * @param $depth Integer Current depth of recursion.
1035 */
1036 static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1037 {
1038 global $config;
1039 error_reporting(E_ALL | E_STRICT);
1040 $ldap = $config->get_ldap_link();
1041 $basedn = $config->current['BASE'];
1042 $delarray = array();
1044 /* The following code will output a status string
1045 * for each handled object, in a seperate iframe.
1046 */
1049 /* Display current action information.
1050 */
1051 if($is_first){
1052 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1053 }else{
1054 if(preg_match("/^ou=/",$sourcedn)){
1055 echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1056 }else{
1057 $tmp = split(",",$sourcedn);
1058 echo " <b>"._("Object").":</b> ";
1059 $deststr = LDAP::fix($destinationdn);
1060 if(strlen($deststr) > 96){
1061 $deststr = substr($deststr,0,96)."...";
1062 }
1063 echo $deststr."<br>";
1064 }
1065 }
1066 /* .. immediately display infos */
1067 flush();
1069 /* Check if destination entry already exists
1070 */
1071 $ldap->cat($destinationdn);
1072 if($ldap->count()){
1073 echo _("Could not create new release, the destination dn is already in use.");
1074 return;
1075 }else{
1077 $ldap->clearResult();
1079 /* Get source entry
1080 * if it does not exist, abort here.
1081 */
1082 $ldap->cd($basedn);
1083 $ldap->cat($sourcedn);
1084 $attr = $ldap->fetch();
1085 if((!$attr) || (count($attr)) ==0) {
1086 echo _("Error while fetching source dn - aborted!");
1087 return;
1088 }
1090 /* The current object we want to create is an department.
1091 * Create the department and add the FAIbranch tag.
1092 */
1093 if(in_array("organizationalUnit",$attr['objectClass'])){
1094 $attr['dn'] = LDAP::convert($destinationdn);
1095 $ldap->cd($basedn);
1096 $ldap->create_missing_trees($destinationdn);
1097 $ldap->cd($destinationdn);
1099 /* If is first entry, append FAIbranch to department entry */
1100 if($is_first){
1101 $ldap->cat($destinationdn);
1102 $attr= $ldap->fetch();
1103 /* Filter unneeded informations */
1104 foreach($attr as $key => $value){
1105 if(is_numeric($key)) unset($attr[$key]);
1106 if(isset($attr[$key]['count'])){
1107 if(is_array($attr[$key])){
1108 unset($attr[$key]['count']);
1109 }
1110 }
1111 }
1113 unset($attr['count']);
1114 unset($attr['dn']);
1116 /* Add marking attribute */
1117 $attr['objectClass'][] = "FAIbranch";
1118 $attr['FAIstate'] = $type;
1120 /* Add this entry */
1121 $ldap->modify($attr);
1122 }
1123 }else{
1125 /* Replicate all relevant FAI objects here.
1126 * FAI objects, Apps and Mimetypes.
1127 * Get all attributes as binary value, to ensure that Icon, File template aso
1128 * are created correctly.
1129 */
1130 foreach($attr as $key => $value){
1132 if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1133 $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1134 $ei= ldap_first_entry($ldap->cid, $sr);
1135 if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1136 $attr[$key] = $tmp;
1137 }
1138 }
1140 if(is_numeric($key)) unset($attr[$key]);
1141 if(isset($attr[$key]['count'])){
1142 if(is_array($attr[$key])){
1143 unset($attr[$key]['count']);
1144 }
1145 }
1146 }
1147 unset($attr['count']);
1148 unset($attr['dn']);
1149 if(!in_array("FAIobject",$attr['objectClass'])){
1150 $attr['objectClass'][] = "FAIobject";
1151 }
1152 $attr['FAIstate'] = $type;
1154 /* Add entry
1155 */
1156 $ldap->cd($destinationdn);
1157 $ldap->cat($destinationdn);
1159 $a = $ldap->fetch();
1160 if(!count($a)){
1161 $ldap->add($attr);
1162 }
1164 if(!$ldap->success()){
1166 /* Some error occurred */
1167 msg_dialog::display(_("Fatal error"),
1168 sprintf(_("Release creation failed due to ldap errors. Additional informations '%s'."),
1169 $ldap->get_error()."<br>".$sourcedn."<br>".$destinationdn."<br>"),FATAL_ERROR_DIALOG);
1170 exit();
1171 }
1172 }
1173 }
1175 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1177 /* Prepare for recursive copy.
1178 * Get all object within the source dn and
1179 * call the recursive copy for each.
1180 */
1181 $ldap->ls ("(objectClass=*)",$sourcedn);
1182 while ($ldap->fetch()){
1183 $deldn= $ldap->getDN();
1184 $delarray[$deldn]= strlen($deldn);
1185 }
1186 asort ($delarray);
1187 reset ($delarray);
1188 $depth ++;
1189 foreach($delarray as $dn => $bla){
1190 if($dn != $destinationdn){
1191 $ldap->cd($basedn);
1192 $item = $ldap->fetch($ldap->cat($dn));
1193 if(!in_array("FAIbranch",$item['objectClass'])){
1194 FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1195 }
1196 }
1197 }
1198 if($is_first){
1199 echo "<p class='seperator'> </p>";
1200 }
1201 }
1205 /* This function returns the dn of the object release */
1206 static function get_release_dn($Current_DN)
1207 {
1208 global $config;
1209 $ldap = $config->get_ldap_link();
1210 $ldap->cd($config->current['BASE']);
1212 /* Split dn into pices */
1213 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$Current_DN));
1215 if(!is_array($dns_to_check)){
1216 return;
1217 }
1219 /* Use dn pieces, to create sub dns like
1220 ou=test,ou=1,ou=0...
1221 ou=1,ou=0...
1222 ou=0...
1223 To check which dn is our release container.
1224 */
1225 unset($dns_to_check['count']);
1226 while(count($dns_to_check)){
1228 /* Create dn */
1229 $new_dn = "";
1230 foreach($dns_to_check as $part){
1231 $new_dn .= $part.",";
1232 }
1233 $new_dn .= $config->current['BASE'];
1235 /* Check if this dn is a release dn */
1236 if(FAI::is_release_department($new_dn)){
1237 return($new_dn);
1238 }
1240 /* Remove first element of dn pieces */
1241 reset($dns_to_check);
1242 unset($dns_to_check[key($dns_to_check)]);
1243 }
1244 return("");
1245 }
1246 }
1251 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1252 ?>