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;
540 /* FAItemplateFile can be binary, therefore it needs to be fetched with
541 * $ldap->get_attribute */
542 if (isset($parent_attrs['FAItemplateFile'])) {
543 $parent_attrs['FAItemplateFile'] = $ldap->get_attribute($parent_obj, 'FAItemplateFile');
544 }
546 FAI::save_FAI_object($key,$parent_attrs);
547 }
548 }
550 if(DEBUG_FAI_FUNC) {
551 echo "<b>Saving current object</b>".$parent_obj;
552 print_a($objectAttrs);
553 }
554 FAI::save_FAI_object($parent_obj,$objectAttrs);
556 if(($parent_obj != $Current_DN)){
557 msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
558 }
559 }
560 }
561 }
563 /* Reload GOsa si FAI DB/cache
564 */
565 if($reload_fai_classes){
566 if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
567 $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);
568 if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
569 $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'];
570 $tmp = new $evt['CLASS_NAME']($config);
571 $tmp->set_type(TRIGGERED_EVENT);
572 $tmp->add_targets(array("GOSA"));
573 $o_queue = new gosaSupportDaemon();
574 if(!$o_queue->append($tmp)){
575 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
576 }
577 }
578 }
579 }
581 session::set('FAI_objects_to_save',array());
582 }
585 /* this function will remove all unused (deleted) objects,
586 that have no parent object */
587 static function clean_up_releases($Current_DN)
588 {
589 global $config;
590 $ldap = $config->get_ldap_link();
591 $ldap->cd($config->current['BASE']);
593 /* Collect some basic informations and initialize some variables */
594 $base_release = FAI::get_release_dn($Current_DN);
595 $previous_releases = array_reverse(FAI:: get_previous_releases_of_this_release($base_release,true));
596 $Kill = array();
597 $Skip = array();
599 /* We must also include the given release dn */
600 $previous_releases[] = $base_release;
602 /* Walk through all releases */
603 foreach($previous_releases as $release){
605 /* Get fai departments */
606 $deps_to_search = FAI::get_FAI_departments($release);
608 /* For every single department (ou=hoos,ou ..) */
609 foreach($deps_to_search as $fai_base){
611 /* Ldap search for fai classes specified in this release */
612 $ldap->cd($fai_base);
613 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
615 /* check the returned objects, and add/replace them in our return variable */
616 while($attr = $ldap->fetch()){
618 $buffer = array();
619 # $name = str_ireplace($release,"",$attr['dn']);
620 $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
622 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
624 /* Check if this object is required somehow */
625 if(!isset($Skip[$name])){
626 $Kill[$attr['dn']] = $attr['dn'];
627 }
628 }else{
630 /* This object is required (not removed), so do not
631 delete any following sub releases of this object */
632 $Skip[$name] = $attr['dn'];
633 }
634 }
635 }
636 }
637 return($Kill);
638 }
641 /* Remove numeric index and 'count' from ldap->fetch result */
642 static function prepare_ldap_fetch_to_be_saved($attrs)
643 {
644 foreach($attrs as $key => $value){
645 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
646 unset($attrs[$key]);
647 }
648 if(is_array($value) && isset($value['count'])){
649 unset($attrs[$key]['count']);
650 }
651 }
652 return($attrs);
653 }
656 /* Save given attrs to specified dn*/
657 static function save_FAI_object($dn,$attrs)
658 {
659 global $config;
660 $ldap = $config->get_ldap_link();
661 $ldap->cd($config->current['BASE']);
662 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
663 $ldap->cd($dn);
665 $ldap->cat($dn,array("dn"));
666 if($ldap->count()){
668 /* Remove FAIstate*/
669 if(!isset($attrs['FAIstate'])){
670 $attrs['FAIstate'] = array();
671 }
673 $ldap->modify($attrs);
674 }else{
676 /* Unset description if empty */
677 if(empty($attrs['description'])){
678 unset($attrs['description']);
679 }
681 $ldap->add($attrs);
682 }
683 if (!$ldap->success()){
684 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
685 }
686 }
689 /* Return FAIstate freeze branch or "" for specified release department */
690 static function get_release_tag($dn)
691 {
692 global $config;
693 $ldap = $config->get_ldap_link();
694 $ldap->cd($dn);
695 $ldap->cat($dn,array("FAIstate"));
697 if($ldap->count()){
699 $attr = $ldap->fetch();
700 if(isset($attr['FAIstate'][0])){
701 if(preg_match("/freeze/",$attr['FAIstate'][0])){
702 return("freeze");
703 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
704 return("branch");
705 }
706 }
707 }
708 return("");
709 }
712 static function get_following_releases_that_inherit_this_object($dn)
713 {
714 global $config;
715 $ldap = $config->get_ldap_link();
716 $ldap->cd($config->current['BASE']);
718 $ret = array();
720 /* Get base release */
721 $base_release = FAI::get_release_dn($dn);
723 /* Get previous release dns */
724 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release);
726 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
727 # $dn_suffix = str_ireplace($base_release,"",$dn);
728 $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
730 /* Check if given object also exists whitin one of these releases */
731 foreach($sub_releases as $p_release => $name){
733 $check_dn = $dn_suffix.$p_release;
735 $ldap->cat($check_dn,array("dn","objectClass"));
737 if($ldap->count()){
738 //return($ret);
739 }else{
740 $ret[$check_dn]=$check_dn;
741 }
742 }
743 return($ret);
744 }
747 /* Get previous version of the object dn */
748 static function get_parent_release_object($dn,$include_myself=true)
749 {
750 global $config;
751 $ldap = $config->get_ldap_link();
752 $ldap->cd($config->current['BASE']);
753 $previous_releases= array();
755 /* Get base release */
756 $base_release = FAI::get_release_dn($dn);
757 if($include_myself){
758 $previous_releases[] = $base_release;
759 }
761 /* Get previous release dns */
762 $tmp = FAI:: get_previous_releases_of_this_release($base_release,true);
763 foreach($tmp as $release){
764 $previous_releases[] = $release;
765 }
767 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
768 # $dn_suffix = str_ireplace($base_release,"",$dn);
769 $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
771 /* Check if given object also exists whitin one of these releases */
772 foreach($previous_releases as $p_release){
773 $check_dn = $dn_suffix.$p_release;
774 $ldap->cat($check_dn,array("dn","objectClass"));
776 if($ldap->count()){
777 return($check_dn);
778 }
779 }
780 return("");
781 }
784 /* return release names of all parent releases */
785 static function get_previous_releases_of_this_release($dn,$flat)
786 {
787 global $config;
788 $ldap = $config->get_ldap_link();
789 $ldap->cd($config->current['BASE']);
790 $ret = array();
792 /* Explode dns into pieces, to be able to build parent dns */
793 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$dn));
795 if(!is_array($dns_to_check)){
796 return;
797 }
799 /* Unset first entry which represents the given dn */
800 unset($dns_to_check['count']);
801 unset($dns_to_check[key($dns_to_check)]);
803 /* Create dns addresses and check if this dn is a release dn */
804 $id = 0;
805 while(count($dns_to_check)){
807 /* build parent dn */
808 $new_dn = "";
809 foreach($dns_to_check as $part){
810 $new_dn .= $part.",";
811 }
812 $new_dn .= $config->current['BASE'];
814 /* check if this dn is a release */
815 if(FAI::is_release_department($new_dn)){
816 if($flat){
817 $ret[$id] = $new_dn;
818 }else{
819 $ret = array($new_dn=>$ret);
820 }
821 $id ++;
822 }else{
823 return($ret);
824 }
825 reset($dns_to_check);
826 unset($dns_to_check[key($dns_to_check)]);
827 }
828 return($ret);
829 }
832 /* This function returns all sub release names, recursivly */
833 static function get_sub_releases_of_this_release($dn,$flat = false)
834 {
835 global $config;
836 $res = array();
837 $ldap = $config->get_ldap_link();
838 $ldap->cd($config->current['BASE']);
839 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
840 while($attr = $ldap->fetch()){
842 /* Append department name */
843 if($flat){
844 $res[$attr['dn']] = $attr['ou'][0];
845 }else{
846 $res[$attr['dn']] = array();
847 }
849 /* Get sub release departments of this department */
850 if(in_array("FAIbranch",$attr['objectClass'])) {
851 if($flat){
852 $tmp = FAI:: get_sub_releases_of_this_release($attr['dn'],$flat);
853 foreach($tmp as $dn => $value){
854 $res[$dn]=$value;
855 }
856 }else{
857 $res[$attr['dn']] = FAI:: get_sub_releases_of_this_release($attr['dn']);
858 }
859 }
860 }
861 return($res);
862 }
865 /* Check if the given department is a release department */
866 static function is_release_department($dn)
867 {
868 global $config;
869 $ldap = $config->get_ldap_link();
870 $ldap->cd($config->current['BASE']);
871 $ldap->cat($dn,array("objectClass","ou"));
873 /* Check objectClasses and name to check if this is a release department */
874 if($ldap->count()){
875 $attrs = $ldap->fetch();
877 $ou = "";
878 if(isset($attrs['ou'][0])){
879 $ou = $attrs['ou'][0];
880 }
882 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
883 return($attrs['dn']);
884 }
885 }
886 return(false);
887 }
890 static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
891 {
892 global $config;
893 $start = microtime(TRUE);
894 $source_release = trim($source_release,"/");
896 echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
898 $sub_releases = array();
899 $source_dn = "";
901 $tmp = split("\/",$source_release);
902 foreach($tmp as $part){
903 if(empty($part)){
904 continue;
905 }
906 $source_dn = "ou=".$part.",".$source_dn;
907 $sub_releases[$part] = $source_dn;
908 }
910 /* Get all groups */
911 $ldap =$config->get_ldap_link();
912 $ldap->cd($config->current['BASE']);
913 $ldap->search("(objectClass=posixGroup)",array("dn"));
914 $groups = array();
915 while($attrs = $ldap->fetch()){
916 $groups[$attrs['dn']] = $attrs;
917 }
919 /* Get all FAI releases, to be able to create missing group application releases
920 with the correct type of release (FAIstate=freeze/branch).
921 */
922 $f_releases = array();
923 $ldap->cd ($config->current['BASE']);
924 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
925 while($attrs = $ldap->fetch()){
926 foreach($sub_releases as $sub_rel){
927 if(preg_match("/^".preg_quote($sub_rel.get_ou('faiBaseRDN'), '/')."/",$attrs['dn'])){
928 $f_releases[$sub_rel.get_ou('faiBaseRDN')] = $attrs;
929 }
930 }
931 }
933 /* Get all group releases */
934 $g_releases = array();
935 foreach($groups as $dn => $data){
936 $ldap->cd($dn);
937 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
938 while($attrs = $ldap->fetch()){
939 $g_releases[$attrs['dn']] = $attrs;
940 }
941 }
943 /* Check if base releases exists.
944 If they do not exist, create them and adapt FAIstate attribute from FAI releases.
945 */
946 foreach($sub_releases as $name => $sub_rel){
948 $FAIstate = "";
949 if(isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]) && isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'])){
950 $FAIstate = $f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'][0];
951 }
953 foreach($groups as $dn => $data){
954 if(!isset($g_releases[$sub_rel.$dn])){
955 $ldap->cd($dn);
956 $r_data = array();
957 $r_data['ou'] = $name;
958 $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
959 if(!empty($FAIstate)) {
960 $r_data['FAIstate'] = $FAIstate;
961 }
963 $ldap->cd($sub_rel.$dn) ;
964 $ldap->add($r_data);
965 echo " <b>"._("Object").":</b> ";
966 echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
967 flush();
968 }
969 }
970 }
972 /* Create new release container in each group.
973 */
974 $n_data = array();
975 $n_data = array();
976 $n_data['ou'] = $destination_name;
977 $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
978 if(!empty($type)){
979 $n_data['FAIstate'] = $type."/cow";
980 }
982 foreach($groups as $dn => $att){
983 $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
984 if(!isset($g_releases[$n_dn])){
985 $ldap->cd ($n_dn);
986 $ldap->add($n_data);
987 echo " <b>"._("Object").":</b> ";
988 echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
989 flush();
990 }
991 }
993 /* If the source release is empty, then create a new release by copying
994 all group application menus into a new ou=$destination_name release container.
996 If the source release is not empty.
997 We detect all releases which match the source release dn and copy the contents.
998 */
999 if(empty($source_release)){
1000 $source_dns = $groups;
1001 }else{
1002 $source_dns = array();
1003 foreach($g_releases as $dn => $data){
1004 if(preg_match("/^".preg_quote($source_dn, '/')."/",$dn)){
1005 $source_dns[$dn] = $data;
1006 }
1007 }
1008 }
1010 /* Detect all menu object we have to copy
1011 */
1012 $to_copy = array();
1013 foreach($source_dns as $dn => $attrs){
1014 $ldap->cd($dn);
1015 $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
1016 while($attrs = $ldap->fetch()){
1017 $destination = preg_replace("/".preg_quote($dn, '/')."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
1018 $to_copy[$attrs['dn']] = $destination;
1019 }
1020 }
1022 /* At least create the menu objects object */
1023 $plug = new plugin($config);
1024 foreach($to_copy as $source => $destination){
1025 $ldap->cat($destination);
1026 if($ldap->count()){
1027 echo " <b>"._("Object").":</b> ";
1028 echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
1029 flush();
1030 }else{
1031 $plug->copy($source,$destination);
1032 echo " <b>"._("Object").":</b> ";
1033 echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
1034 flush();
1035 }
1036 }
1037 }
1040 /*! \brief Create a new FAI branch.
1041 * @param $sourcedn String The source release dn
1042 * @param $destinationdn String The destination dn
1043 * @param $destinationName String The name of the new release
1044 * @param $type String The release type (freeze/branch)
1045 * @param $is_first Boolean Use to identify the first func. call when recursivly called.
1046 * @param $depth Integer Current depth of recursion.
1047 */
1048 static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1049 {
1050 global $config;
1051 error_reporting(E_ALL | E_STRICT);
1052 $ldap = $config->get_ldap_link();
1053 $basedn = $config->current['BASE'];
1054 $delarray = array();
1056 /* The following code will output a status string
1057 * for each handled object, in a seperate iframe.
1058 */
1061 /* Display current action information.
1062 */
1063 if($is_first){
1064 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1065 }else{
1066 if(preg_match("/^ou=/",$sourcedn)){
1067 echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1068 }else{
1069 $tmp = split(",",$sourcedn);
1070 echo " <b>"._("Object").":</b> ";
1071 $deststr = LDAP::fix($destinationdn);
1072 if(strlen($deststr) > 96){
1073 $deststr = substr($deststr,0,96)."...";
1074 }
1075 echo $deststr."<br>";
1076 }
1077 }
1078 /* .. immediately display infos */
1079 flush();
1081 /* Check if destination entry already exists
1082 */
1083 $ldap->cat($destinationdn);
1084 if($ldap->count()){
1085 echo _("Could not create new release, the destination dn is already in use.");
1086 return;
1087 }else{
1089 $ldap->clearResult();
1091 /* Get source entry
1092 * if it does not exist, abort here.
1093 */
1094 $ldap->cd($basedn);
1095 $ldap->cat($sourcedn);
1096 $attr = $ldap->fetch();
1097 if((!$attr) || (count($attr)) ==0) {
1098 echo _("Error while fetching source dn - aborted!");
1099 return;
1100 }
1102 /* The current object we want to create is an department.
1103 * Create the department and add the FAIbranch tag.
1104 */
1105 if(in_array("organizationalUnit",$attr['objectClass'])){
1106 $attr['dn'] = LDAP::convert($destinationdn);
1107 $ldap->cd($basedn);
1108 $ldap->create_missing_trees($destinationdn);
1109 $ldap->cd($destinationdn);
1111 /* If is first entry, append FAIbranch to department entry */
1112 if($is_first){
1113 $ldap->cat($destinationdn);
1114 $attr= $ldap->fetch();
1115 /* Filter unneeded informations */
1116 foreach($attr as $key => $value){
1117 if(is_numeric($key)) unset($attr[$key]);
1118 if(isset($attr[$key]['count'])){
1119 if(is_array($attr[$key])){
1120 unset($attr[$key]['count']);
1121 }
1122 }
1123 }
1125 unset($attr['count']);
1126 unset($attr['dn']);
1128 /* Add marking attribute */
1129 $attr['objectClass'][] = "FAIbranch";
1130 $attr['FAIstate'] = $type;
1132 /* Add this entry */
1133 $ldap->modify($attr);
1134 }
1135 }else{
1137 /* Replicate all relevant FAI objects here.
1138 * FAI objects, Apps and Mimetypes.
1139 * Get all attributes as binary value, to ensure that Icon, File template aso
1140 * are created correctly.
1141 */
1142 foreach($attr as $key => $value){
1144 if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1145 $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1146 $ei= ldap_first_entry($ldap->cid, $sr);
1147 if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1148 $attr[$key] = $tmp;
1149 }
1150 }
1152 if(is_numeric($key)) unset($attr[$key]);
1153 if(isset($attr[$key]['count'])){
1154 if(is_array($attr[$key])){
1155 unset($attr[$key]['count']);
1156 }
1157 }
1158 }
1159 unset($attr['count']);
1160 unset($attr['dn']);
1161 if(!in_array("FAIobject",$attr['objectClass'])){
1162 $attr['objectClass'][] = "FAIobject";
1163 }
1164 $attr['FAIstate'] = $type;
1166 /* Add entry
1167 */
1168 $ldap->cd($destinationdn);
1169 $ldap->cat($destinationdn);
1171 $a = $ldap->fetch();
1172 if(!count($a)){
1173 $ldap->add($attr);
1174 }
1176 if(!$ldap->success()){
1178 /* Some error occurred */
1179 msg_dialog::display(_("Fatal error"),
1180 sprintf(_("Release creation failed due to ldap errors. Additional informations '%s'."),
1181 $ldap->get_error()."<br>".$sourcedn."<br>".$destinationdn."<br>"),FATAL_ERROR_DIALOG);
1182 exit();
1183 }
1184 }
1185 }
1187 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1189 /* Prepare for recursive copy.
1190 * Get all object within the source dn and
1191 * call the recursive copy for each.
1192 */
1193 $ldap->ls ("(objectClass=*)",$sourcedn);
1194 while ($ldap->fetch()){
1195 $deldn= $ldap->getDN();
1196 $delarray[$deldn]= strlen($deldn);
1197 }
1198 asort ($delarray);
1199 reset ($delarray);
1200 $depth ++;
1201 foreach($delarray as $dn => $bla){
1202 if($dn != $destinationdn){
1203 $ldap->cd($basedn);
1204 $item = $ldap->fetch($ldap->cat($dn));
1205 if(!in_array("FAIbranch",$item['objectClass'])){
1206 FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1207 }
1208 }
1209 }
1210 if($is_first){
1211 echo "<p class='seperator'> </p>";
1212 }
1213 }
1217 /* This function returns the dn of the object release */
1218 static function get_release_dn($Current_DN)
1219 {
1220 global $config;
1221 $ldap = $config->get_ldap_link();
1222 $ldap->cd($config->current['BASE']);
1224 /* Split dn into pices */
1225 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$Current_DN));
1227 if(!is_array($dns_to_check)){
1228 return;
1229 }
1231 /* Use dn pieces, to create sub dns like
1232 ou=test,ou=1,ou=0...
1233 ou=1,ou=0...
1234 ou=0...
1235 To check which dn is our release container.
1236 */
1237 unset($dns_to_check['count']);
1238 while(count($dns_to_check)){
1240 /* Create dn */
1241 $new_dn = "";
1242 foreach($dns_to_check as $part){
1243 $new_dn .= $part.",";
1244 }
1245 $new_dn .= $config->current['BASE'];
1247 /* Check if this dn is a release dn */
1248 if(FAI::is_release_department($new_dn)){
1249 return($new_dn);
1250 }
1252 /* Remove first element of dn pieces */
1253 reset($dns_to_check);
1254 unset($dns_to_check[key($dns_to_check)]);
1255 }
1256 return("");
1257 }
1258 }
1263 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1264 ?>