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);
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'), '/')."/i",$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'), '/').".*$/i","",$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"), '/')."/i",$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 if(count($classes) == 1){
249 /* Get all FAI Profiles
250 */
251 $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
252 "(&(objectClass=FAIprofile)(FAIclass=*))");
254 /* Walk though all profiles and remove the source class name
255 */
256 foreach($profiles as $dn){
257 $ldap->cat($dn['dn']);
258 $attrs = $ldap->fetch();
260 $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
262 /* Check if this Profile uses the source class ($cn)
263 */
264 if(preg_match("/".preg_quote($cn, '/')."/",$attrs['FAIclass'])){
265 $attrs['FAIclass'] = preg_replace("/[ ]*".preg_quote($cn, '/')."[ ]*/i"," ",$attrs['FAIclass']);
266 if(empty($attrs['FAIclass'])){
267 $attrs['FAIclass'] = array();
268 }
269 $ldap->cd($dn['dn']);
270 $ldap->modify($attrs);
272 if (!$ldap->success()){
273 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
274 }
275 }
276 }
277 }
278 }
279 }
280 }
284 $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
285 $FAI_objects_to_save[$Current_DN] = $addObj;
286 session::set('FAI_objects_to_save',$FAI_objects_to_save);
287 }
290 /* Detect differences in attribute arrays */
291 static function array_diff_FAI($ar1,$ar2)
292 {
294 if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
295 $ar1['description'] = "";
296 }
297 if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
298 $ar2['description'] = "";
299 }
301 if(count($ar1) != count($ar2)) {
302 return (true);
303 }
305 foreach($ar1 as $key1 => $val1){
307 if((is_array($val1)) && (count($val1)==1)){
308 $ar1[$key1] = $val1[0];
309 }
311 if(isset($ar2[$key1])&& (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
312 $val1 = $val1[0];
313 $ar2[$key1] = $ar2[$key1][0];
314 }
315 }
316 ksort($ar1);
317 ksort($ar2);
318 if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
319 return(true);
320 }else{
321 return(false);
322 }
323 }
326 static function arr_diff($ar1,$ar2)
327 {
328 foreach($ar1 as $ak1 => $av1){
329 if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
330 return(TRUE);
331 }elseif(is_array($av1)){
332 $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
333 if($ret) {
334 return(TRUE);
335 }
336 }
337 }
338 return(FALSE);
339 }
344 /* check which objects must be saved, and save them */
345 static function save_release_changes_now()
346 {
347 global $config;
348 /* Variable init*/
349 $to_save = array();
351 $reload_fai_classes = FALSE;
353 /* check which objects must be saved */
354 if(!session::is_set('FAI_objects_to_save')){
355 return;
356 }
357 $FAI_objects_to_save = session::get('FAI_objects_to_save');
358 if(!is_array($FAI_objects_to_save)) {
359 print_a(array(session::get('FAI_objects_to_save')));
360 trigger_error("Can't save FAI objects, no array given.");
361 return;
362 }
364 foreach($FAI_objects_to_save as $Current_DN => $object){
365 if($object['diff']){
366 $sub_name = $Current_DN;
367 while(isset($FAI_objects_to_save[$sub_name])){
368 $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name];
369 unset($FAI_objects_to_save[$sub_name]);
370 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
371 }
372 }
373 }
374 session::set('FAI_objects_to_save',$FAI_objects_to_save);
376 /* Sort list of objects that must be saved, and ensure that
377 container objects are safed, before their childs are saved */
378 ksort($to_save);
379 $tmp = array();
380 foreach($to_save as $SubObjects){
381 foreach($SubObjects as $object){
382 $tmp[] = $object;
383 }
384 }
385 $to_save = $tmp;
388 /* Save objects and manage the correct release behavior*/
389 foreach($to_save as $save){
391 $Current_DN = $save['Current_DN'];
392 $removed = $save['removed'];
393 $objectAttrs= $save['objectAttrs'];
395 /* Get ldap object */
396 $ldap = $config->get_ldap_link();
397 $ldap->cd($config->current['BASE']);
399 /* Get some basic informations */
400 $base_release = FAI::get_release_dn($Current_DN);
401 $sub_releases = FAI::get_sub_releases_of_this_release($base_release,true);
402 $parent_obj = FAI::get_parent_release_object($Current_DN);
403 $following_releases = $sub_releases;
405 /* Check if given dn exists or if is a new entry */
406 $ldap->cat($Current_DN);
407 if(!$ldap->count()){
408 $is_new = true;
409 }else{
410 $is_new = false;
411 }
413 /* if parameter removed is true, we have to add FAIstate to the current attrs
414 FAIstate should end with ...|removed after this operation */
415 if($removed ){
416 $ldap->cat($Current_DN);
418 /* Get current object, because we must add the FAIstate ...|removed */
419 if((!$ldap->count()) && !empty($parent_obj)){
420 $ldap->cat($parent_obj);
421 }
423 /* Check if we have found a suiteable object */
424 if(!$ldap->count()){
425 echo "Error can't remove this object ".$Current_DN;
426 return;
427 }else{
429 /* Set FAIstate to current objectAttrs */
430 $objectAttrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
431 if(isset($objectAttrs['FAIstate'][0])){
432 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
433 $objectAttrs['FAIstate'][0] .= "|removed";
434 }
435 }else{
436 $objectAttrs['FAIstate'][0] = "|removed";
437 }
439 /* Force reload of FAI classes */
440 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
441 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
442 $reload_fai_classes = TRUE;
443 }
444 }
445 }
447 /* Check if this a leaf release or not */
448 if(count($following_releases) == 0 ){
450 /* This is a leaf object. It isn't inherited by any other object */
451 if(DEBUG_FAI_FUNC) {
452 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
453 print_a($objectAttrs);
454 }
455 FAI::save_FAI_object($Current_DN,$objectAttrs);
457 /* Force reload of FAI classes */
458 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
459 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
460 $reload_fai_classes = TRUE;
461 }
463 }else{
465 /* This object is inherited by some sub releases */
467 /* Get all releases, that inherit this object */
468 $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
470 /* Get parent object */
471 $ldap->cat($parent_obj);
472 $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
474 /* New objects require special handling */
475 if($is_new){
477 /* Force reload of FAI classes */
478 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
479 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
480 $reload_fai_classes = TRUE;
481 }
483 /* check if there is already an entry named like this,
484 in one of our parent releases */
485 if(!empty($parent_obj)){
486 if(DEBUG_FAI_FUNC) {
487 echo "There is already an entry named like this.</b><br>";
489 echo "<b>Saving main object</b>".$Current_DN;
490 print_a($objectAttrs);
491 }
492 FAI::save_FAI_object($Current_DN,$objectAttrs);
494 foreach($r as $key){
495 if(DEBUG_FAI_FUNC) {
496 echo "<b>Saving parent to following release</b> ".$key;
497 print_a($parent_attrs);
498 }
499 FAI::save_FAI_object($key,$parent_attrs);
500 }
501 }else{
503 if(DEBUG_FAI_FUNC) {
504 echo "<b>Saving main object</b>".$Current_DN;
505 print_a($objectAttrs);
506 }
507 FAI::save_FAI_object($Current_DN,$objectAttrs);
509 if(isset($objectAttrs['FAIstate'])){
510 $objectAttrs['FAIstate'] .= "|removed";
511 }else{
512 $objectAttrs['FAIstate'] = "|removed";
513 }
515 foreach($r as $key ){
516 if(DEBUG_FAI_FUNC) {
517 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
518 print_a($objectAttrs);
519 }
520 FAI::save_FAI_object($key,$objectAttrs);
521 }
522 }
523 }else{
525 /* check if we must patch the follwing release */
526 if(!empty($r)){
528 foreach($r as $key ){
529 if(DEBUG_FAI_FUNC) {
530 echo "<b>Copy current objects original attributes to next release</b> ".$key;
531 print_a($parent_attrs);
532 }
534 /* Append FAIstate tag to ensure that freezed objects stay freezed
535 */
536 $rTag = FAI::get_release_tag(FAI::get_release_dn($key));
537 $parent_attrs['FAIstate'] = $rTag;
539 /* FAItemplateFile can be binary, therefore it needs to be fetched with
540 * $ldap->get_attribute */
541 if (isset($parent_attrs['FAItemplateFile'])) {
542 $parent_attrs['FAItemplateFile'] = $ldap->get_attribute($parent_obj, 'FAItemplateFile');
543 }
545 FAI::save_FAI_object($key,$parent_attrs);
546 }
547 }
549 if(DEBUG_FAI_FUNC) {
550 echo "<b>Saving current object</b>".$parent_obj;
551 print_a($objectAttrs);
552 }
553 FAI::save_FAI_object($parent_obj,$objectAttrs);
555 if(($parent_obj != $Current_DN)){
556 msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
557 }
558 }
559 }
560 }
562 /* Reload GOsa si FAI DB/cache
563 */
564 if($reload_fai_classes){
565 if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
566 $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);
567 if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
568 $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'];
569 $tmp = new $evt['CLASS_NAME']($config);
570 $tmp->set_type(TRIGGERED_EVENT);
571 $tmp->add_targets(array("GOSA"));
572 $o_queue = new gosaSupportDaemon();
573 if(!$o_queue->append($tmp)){
574 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
575 }
576 }
577 }
578 }
580 session::set('FAI_objects_to_save',array());
581 }
584 /* this function will remove all unused (deleted) objects,
585 that have no parent object */
586 static function clean_up_releases($Current_DN)
587 {
588 global $config;
589 $ldap = $config->get_ldap_link();
590 $ldap->cd($config->current['BASE']);
592 /* Collect some basic informations and initialize some variables */
593 $base_release = FAI::get_release_dn($Current_DN);
594 $previous_releases = array_reverse(FAI:: get_previous_releases_of_this_release($base_release,true));
595 $Kill = array();
596 $Skip = array();
598 /* We must also include the given release dn */
599 $previous_releases[] = $base_release;
601 /* Walk through all releases */
602 foreach($previous_releases as $release){
604 /* Get fai departments */
605 $deps_to_search = FAI::get_FAI_departments($release);
607 /* For every single department (ou=hoos,ou ..) */
608 foreach($deps_to_search as $fai_base){
610 /* Ldap search for fai classes specified in this release */
611 $ldap->cd($fai_base);
612 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
614 /* check the returned objects, and add/replace them in our return variable */
615 while($attr = $ldap->fetch()){
617 $buffer = array();
618 # $name = str_ireplace($release,"",$attr['dn']);
619 $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
621 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
623 /* Check if this object is required somehow */
624 if(!isset($Skip[$name])){
625 $Kill[$attr['dn']] = $attr['dn'];
626 }
627 }else{
629 /* This object is required (not removed), so do not
630 delete any following sub releases of this object */
631 $Skip[$name] = $attr['dn'];
632 }
633 }
634 }
635 }
636 return($Kill);
637 }
640 /* Remove numeric index and 'count' from ldap->fetch result */
641 static function prepare_ldap_fetch_to_be_saved($attrs)
642 {
643 foreach($attrs as $key => $value){
644 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
645 unset($attrs[$key]);
646 }
647 if(is_array($value) && isset($value['count'])){
648 unset($attrs[$key]['count']);
649 }
650 }
651 return($attrs);
652 }
655 /* Save given attrs to specified dn*/
656 static function save_FAI_object($dn,$attrs)
657 {
658 global $config;
659 $ldap = $config->get_ldap_link();
660 $ldap->cd($config->current['BASE']);
661 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
662 $ldap->cd($dn);
664 $ldap->cat($dn,array("dn"));
665 if($ldap->count()){
667 /* Remove FAIstate*/
668 if(!isset($attrs['FAIstate'])){
669 $attrs['FAIstate'] = array();
670 }
672 $ldap->modify($attrs);
673 }else{
675 /* Unset description if empty */
676 if(empty($attrs['description'])){
677 unset($attrs['description']);
678 }
680 $ldap->add($attrs);
681 }
682 if (!$ldap->success()){
683 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
684 }
685 }
688 /* Return FAIstate freeze branch or "" for specified release department */
689 static function get_release_tag($dn)
690 {
691 global $config;
692 $ldap = $config->get_ldap_link();
693 $ldap->cd($dn);
694 $ldap->cat($dn,array("FAIstate"));
696 if($ldap->count()){
698 $attr = $ldap->fetch();
699 if(isset($attr['FAIstate'][0])){
700 if(preg_match("/freeze/",$attr['FAIstate'][0])){
701 return("freeze");
702 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
703 return("branch");
704 }
705 }
706 }
707 return("");
708 }
711 static function get_following_releases_that_inherit_this_object($dn)
712 {
713 global $config;
714 $ldap = $config->get_ldap_link();
715 $ldap->cd($config->current['BASE']);
717 $ret = array();
719 /* Get base release */
720 $base_release = FAI::get_release_dn($dn);
722 /* Get previous release dns */
723 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release);
725 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
726 # $dn_suffix = str_ireplace($base_release,"",$dn);
727 $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
729 /* Check if given object also exists whitin one of these releases */
730 foreach($sub_releases as $p_release => $name){
732 $check_dn = $dn_suffix.$p_release;
734 $ldap->cat($check_dn,array("dn","objectClass"));
736 if($ldap->count()){
737 //return($ret);
738 }else{
739 $ret[$check_dn]=$check_dn;
740 }
741 }
742 return($ret);
743 }
746 /* Get previous version of the object dn */
747 static function get_parent_release_object($dn,$include_myself=true)
748 {
749 global $config;
750 $ldap = $config->get_ldap_link();
751 $ldap->cd($config->current['BASE']);
752 $previous_releases= array();
754 /* Get base release */
755 $base_release = FAI::get_release_dn($dn);
756 if($include_myself){
757 $previous_releases[] = $base_release;
758 }
760 /* Get previous release dns */
761 $tmp = FAI:: get_previous_releases_of_this_release($base_release,true);
762 foreach($tmp as $release){
763 $previous_releases[] = $release;
764 }
766 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
767 # $dn_suffix = str_ireplace($base_release,"",$dn);
768 $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
770 /* Check if given object also exists whitin one of these releases */
771 foreach($previous_releases as $p_release){
772 $check_dn = $dn_suffix.$p_release;
773 $ldap->cat($check_dn,array("dn","objectClass"));
775 if($ldap->count()){
776 return($check_dn);
777 }
778 }
779 return("");
780 }
783 /* return release names of all parent releases */
784 static function get_previous_releases_of_this_release($dn,$flat)
785 {
786 global $config;
787 $ldap = $config->get_ldap_link();
788 $ldap->cd($config->current['BASE']);
789 $ret = array();
791 /* Explode dns into pieces, to be able to build parent dns */
792 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$dn));
794 if(!is_array($dns_to_check)){
795 return;
796 }
798 /* Unset first entry which represents the given dn */
799 unset($dns_to_check['count']);
800 unset($dns_to_check[key($dns_to_check)]);
802 /* Create dns addresses and check if this dn is a release dn */
803 $id = 0;
804 while(count($dns_to_check)){
806 /* build parent dn */
807 $new_dn = "";
808 foreach($dns_to_check as $part){
809 $new_dn .= $part.",";
810 }
811 $new_dn .= $config->current['BASE'];
813 /* check if this dn is a release */
814 if(FAI::is_release_department($new_dn)){
815 if($flat){
816 $ret[$id] = $new_dn;
817 }else{
818 $ret = array($new_dn=>$ret);
819 }
820 $id ++;
821 }else{
822 return($ret);
823 }
824 reset($dns_to_check);
825 unset($dns_to_check[key($dns_to_check)]);
826 }
827 return($ret);
828 }
831 /* This function returns all sub release names, recursivly */
832 static function get_sub_releases_of_this_release($dn,$flat = false)
833 {
834 global $config;
835 $res = array();
836 $ldap = $config->get_ldap_link();
837 $ldap->cd($config->current['BASE']);
838 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
839 while($attr = $ldap->fetch()){
841 /* Append department name */
842 if($flat){
843 $res[$attr['dn']] = $attr['ou'][0];
844 }else{
845 $res[$attr['dn']] = array();
846 }
848 /* Get sub release departments of this department */
849 if(in_array("FAIbranch",$attr['objectClass'])) {
850 if($flat){
851 $tmp = FAI:: get_sub_releases_of_this_release($attr['dn'],$flat);
852 foreach($tmp as $dn => $value){
853 $res[$dn]=$value;
854 }
855 }else{
856 $res[$attr['dn']] = FAI:: get_sub_releases_of_this_release($attr['dn']);
857 }
858 }
859 }
860 return($res);
861 }
864 /* Check if the given department is a release department */
865 static function is_release_department($dn)
866 {
867 global $config;
868 $ldap = $config->get_ldap_link();
869 $ldap->cd($config->current['BASE']);
870 $ldap->cat($dn,array("objectClass","ou"));
872 /* Check objectClasses and name to check if this is a release department */
873 if($ldap->count()){
874 $attrs = $ldap->fetch();
876 $ou = "";
877 if(isset($attrs['ou'][0])){
878 $ou = $attrs['ou'][0];
879 }
881 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
882 return($attrs['dn']);
883 }
884 }
885 return(false);
886 }
889 static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
890 {
891 global $config;
892 $start = microtime(TRUE);
893 $source_release = trim($source_release,"/");
895 echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
897 $sub_releases = array();
898 $source_dn = "";
900 $tmp = split("\/",$source_release);
901 foreach($tmp as $part){
902 if(empty($part)){
903 continue;
904 }
905 $source_dn = "ou=".$part.",".$source_dn;
906 $sub_releases[$part] = $source_dn;
907 }
909 /* Get all groups */
910 $ldap =$config->get_ldap_link();
911 $ldap->cd($config->current['BASE']);
912 $ldap->search("(objectClass=posixGroup)",array("dn"));
913 $groups = array();
914 while($attrs = $ldap->fetch()){
915 $groups[$attrs['dn']] = $attrs;
916 }
918 /* Get all FAI releases, to be able to create missing group application releases
919 with the correct type of release (FAIstate=freeze/branch).
920 */
921 $f_releases = array();
922 $ldap->cd ($config->current['BASE']);
923 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
924 while($attrs = $ldap->fetch()){
925 foreach($sub_releases as $sub_rel){
926 if(preg_match("/^".preg_quote($sub_rel.get_ou('faiBaseRDN'), '/')."/i",$attrs['dn'])){
927 $f_releases[$sub_rel.get_ou('faiBaseRDN')] = $attrs;
928 }
929 }
930 }
932 /* Get all group releases */
933 $g_releases = array();
934 foreach($groups as $dn => $data){
935 $ldap->cd($dn);
936 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
937 while($attrs = $ldap->fetch()){
938 $g_releases[$attrs['dn']] = $attrs;
939 }
940 }
942 /* Check if base releases exists.
943 If they do not exist, create them and adapt FAIstate attribute from FAI releases.
944 */
945 foreach($sub_releases as $name => $sub_rel){
947 $FAIstate = "";
948 if(isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]) && isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'])){
949 $FAIstate = $f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'][0];
950 }
952 foreach($groups as $dn => $data){
953 if(!isset($g_releases[$sub_rel.$dn])){
954 $ldap->cd($dn);
955 $r_data = array();
956 $r_data['ou'] = $name;
957 $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
958 if(!empty($FAIstate)) {
959 $r_data['FAIstate'] = $FAIstate;
960 }
962 $ldap->cd($sub_rel.$dn) ;
963 $ldap->add($r_data);
964 echo " <b>"._("Object").":</b> ";
965 echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
966 flush();
967 }
968 }
969 }
971 /* Create new release container in each group.
972 */
973 $n_data = array();
974 $n_data = array();
975 $n_data['ou'] = $destination_name;
976 $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
977 if(!empty($type)){
978 $n_data['FAIstate'] = $type."/cow";
979 }
981 foreach($groups as $dn => $att){
982 $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
983 if(!isset($g_releases[$n_dn])){
984 $ldap->cd ($n_dn);
985 $ldap->add($n_data);
986 echo " <b>"._("Object").":</b> ";
987 echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
988 flush();
989 }
990 }
992 /* If the source release is empty, then create a new release by copying
993 all group application menus into a new ou=$destination_name release container.
995 If the source release is not empty.
996 We detect all releases which match the source release dn and copy the contents.
997 */
998 if(empty($source_release)){
999 $source_dns = $groups;
1000 }else{
1001 $source_dns = array();
1002 foreach($g_releases as $dn => $data){
1003 if(preg_match("/^".preg_quote($source_dn, '/')."/",$dn)){
1004 $source_dns[$dn] = $data;
1005 }
1006 }
1007 }
1009 /* Detect all menu object we have to copy
1010 */
1011 $to_copy = array();
1012 foreach($source_dns as $dn => $attrs){
1013 $ldap->cd($dn);
1014 $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
1015 while($attrs = $ldap->fetch()){
1016 $destination = preg_replace("/".preg_quote($dn, '/')."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
1017 $to_copy[$attrs['dn']] = $destination;
1018 }
1019 }
1021 /* At least create the menu objects object */
1022 $plug = new plugin($config);
1023 foreach($to_copy as $source => $destination){
1024 $ldap->cat($destination);
1025 if($ldap->count()){
1026 echo " <b>"._("Object").":</b> ";
1027 echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
1028 flush();
1029 }else{
1030 $plug->copy($source,$destination);
1031 echo " <b>"._("Object").":</b> ";
1032 echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
1033 flush();
1034 }
1035 }
1036 }
1039 /*! \brief Create a new FAI branch.
1040 * @param $sourcedn String The source release dn
1041 * @param $destinationdn String The destination dn
1042 * @param $destinationName String The name of the new release
1043 * @param $type String The release type (freeze/branch)
1044 * @param $is_first Boolean Use to identify the first func. call when recursivly called.
1045 * @param $depth Integer Current depth of recursion.
1046 */
1047 static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1048 {
1049 global $config;
1050 error_reporting(E_ALL | E_STRICT);
1051 $ldap = $config->get_ldap_link();
1052 $basedn = $config->current['BASE'];
1053 $delarray = array();
1055 /* The following code will output a status string
1056 * for each handled object, in a seperate iframe.
1057 */
1060 /* Display current action information.
1061 */
1062 if($is_first){
1063 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1064 }else{
1065 if(preg_match("/^ou=/",$sourcedn)){
1066 echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1067 }else{
1068 $tmp = split(",",$sourcedn);
1069 echo " <b>"._("Object").":</b> ";
1070 $deststr = LDAP::fix($destinationdn);
1071 if(strlen($deststr) > 96){
1072 $deststr = substr($deststr,0,96)."...";
1073 }
1074 echo $deststr."<br>";
1075 }
1076 }
1077 /* .. immediately display infos */
1078 flush();
1080 /* Check if destination entry already exists
1081 */
1082 $ldap->cat($destinationdn);
1083 if($ldap->count()){
1084 echo _("Could not create new release, the destination dn is already in use.");
1085 return;
1086 }else{
1088 $ldap->clearResult();
1090 /* Get source entry
1091 * if it does not exist, abort here.
1092 */
1093 $ldap->cd($basedn);
1094 $ldap->cat($sourcedn);
1095 $attr = $ldap->fetch();
1096 if((!$attr) || (count($attr)) ==0) {
1097 echo _("Error while fetching source dn - aborted!");
1098 return;
1099 }
1101 /* The current object we want to create is an department.
1102 * Create the department and add the FAIbranch tag.
1103 */
1104 if(in_array("organizationalUnit",$attr['objectClass'])){
1105 $attr['dn'] = LDAP::convert($destinationdn);
1106 $ldap->cd($basedn);
1107 $ldap->create_missing_trees($destinationdn);
1108 $ldap->cd($destinationdn);
1110 /* If is first entry, append FAIbranch to department entry */
1111 if($is_first){
1112 $ldap->cat($destinationdn);
1113 $attr= $ldap->fetch();
1114 /* Filter unneeded informations */
1115 foreach($attr as $key => $value){
1116 if(is_numeric($key)) unset($attr[$key]);
1117 if(isset($attr[$key]['count'])){
1118 if(is_array($attr[$key])){
1119 unset($attr[$key]['count']);
1120 }
1121 }
1122 }
1124 unset($attr['count']);
1125 unset($attr['dn']);
1127 /* Add marking attribute */
1128 $attr['objectClass'][] = "FAIbranch";
1129 $attr['FAIstate'] = $type;
1131 /* Add this entry */
1132 $ldap->modify($attr);
1133 }
1134 }else{
1136 /* Replicate all relevant FAI objects here.
1137 * FAI objects, Apps and Mimetypes.
1138 * Get all attributes as binary value, to ensure that Icon, File template aso
1139 * are created correctly.
1140 */
1141 foreach($attr as $key => $value){
1143 if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1144 $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1145 $ei= ldap_first_entry($ldap->cid, $sr);
1146 if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1147 $attr[$key] = $tmp;
1148 }
1149 }
1151 if(is_numeric($key)) unset($attr[$key]);
1152 if(isset($attr[$key]['count'])){
1153 if(is_array($attr[$key])){
1154 unset($attr[$key]['count']);
1155 }
1156 }
1157 }
1158 unset($attr['count']);
1159 unset($attr['dn']);
1160 if(!in_array("FAIobject",$attr['objectClass'])){
1161 $attr['objectClass'][] = "FAIobject";
1162 }
1163 $attr['FAIstate'] = $type;
1165 /* Add entry
1166 */
1167 $ldap->cd($destinationdn);
1168 $ldap->cat($destinationdn);
1170 $a = $ldap->fetch();
1171 if(!count($a)){
1172 $ldap->add($attr);
1173 }
1175 if(!$ldap->success()){
1177 /* Some error occurred */
1178 msg_dialog::display(_("Fatal error"),
1179 sprintf(_("Release creation failed due to ldap errors. Additional informations '%s'."),
1180 $ldap->get_error()."<br>".$sourcedn."<br>".$destinationdn."<br>"),FATAL_ERROR_DIALOG);
1181 exit();
1182 }
1183 }
1184 }
1186 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1188 /* Prepare for recursive copy.
1189 * Get all object within the source dn and
1190 * call the recursive copy for each.
1191 */
1192 $ldap->ls ("(objectClass=*)",$sourcedn);
1193 while ($ldap->fetch()){
1194 $deldn= $ldap->getDN();
1195 $delarray[$deldn]= strlen($deldn);
1196 }
1197 asort ($delarray);
1198 reset ($delarray);
1199 $depth ++;
1200 foreach($delarray as $dn => $bla){
1201 if($dn != $destinationdn){
1202 $ldap->cd($basedn);
1203 $item = $ldap->fetch($ldap->cat($dn));
1204 if(!in_array("FAIbranch",$item['objectClass'])){
1205 FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1206 }
1207 }
1208 }
1209 if($is_first){
1210 echo "<p class='seperator'> </p>";
1211 }
1212 }
1216 /* This function returns the dn of the object release */
1217 static function get_release_dn($Current_DN)
1218 {
1219 global $config;
1220 $ldap = $config->get_ldap_link();
1221 $ldap->cd($config->current['BASE']);
1223 /* Split dn into pices */
1224 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$Current_DN));
1226 if(!is_array($dns_to_check)){
1227 return;
1228 }
1230 /* Use dn pieces, to create sub dns like
1231 ou=test,ou=1,ou=0...
1232 ou=1,ou=0...
1233 ou=0...
1234 To check which dn is our release container.
1235 */
1236 unset($dns_to_check['count']);
1237 while(count($dns_to_check)){
1239 /* Create dn */
1240 $new_dn = "";
1241 foreach($dns_to_check as $part){
1242 $new_dn .= $part.",";
1243 }
1244 $new_dn .= $config->current['BASE'];
1246 /* Check if this dn is a release dn */
1247 if(FAI::is_release_department($new_dn)){
1248 return($new_dn);
1249 }
1251 /* Remove first element of dn pieces */
1252 reset($dns_to_check);
1253 unset($dns_to_check[key($dns_to_check)]);
1254 }
1255 return("");
1256 }
1257 }
1262 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1263 ?>