1 <?php
3 define("DEBUG_FAI_FUNC",FALSE);
6 class FAI
7 {
9 /* TEST PHASE .... */
11 /* Returns all object for the given release.
12 This function resolves the releases
13 from base up to the given dn.
14 */
15 static function get_all_objects_for_given_base($Current_DN,$filter,$detailed = false)
16 {
17 global $config;
18 $ldap = $config->get_ldap_link();
19 $ldap->cd($config->current['BASE']);
20 $res = array();
21 $tmp = array();
23 if(!FAI::is_release_department($Current_DN)) {
24 return($res);
25 }
27 /* Collect some basic informations and initialize some variables */
28 $base_release = FAI::get_release_dn($Current_DN);
29 $previous_releases = array_reverse(FAI:: get_previous_releases_of_this_release($base_release,true));
31 /* We must also include the given release dn */
32 $previous_releases[] = $base_release;
34 /* Walk through all releases */
35 foreach($previous_releases as $release){
37 /* Get fai departments */
38 $deps_to_search = FAI::get_FAI_departments($release);
40 /* For every single department (ou=hoos,ou ..) */
41 foreach($deps_to_search as $fai_base){
43 /* Ldap search for fai classes specified in this release */
44 $attributes = array("dn","objectClass","FAIstate","cn");
45 $res_tmp = get_list($filter,"fai",$fai_base,$attributes,GL_SUBSEARCH | GL_SIZELIMIT);
47 /* check the returned objects, and add/replace them in our return variable */
48 foreach($res_tmp as $attr){
50 $buffer = array();
51 $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
53 if(isset($attr['FAIstate'][0])){
54 if(preg_match("/removed$/",$attr['FAIstate'][0])){
55 if(isset($res[$name])){
56 unset($res[$name]);
57 }
58 continue;
59 }
60 }
62 /* In detailed mode are some additonal informations visible */
63 if($detailed){
65 /* Create list of parents */
66 if(isset($res[$name])){
67 $buffer = $res[$name];
68 $buffer['parents'][] = $res[$name]['dn'];
69 }else{
70 $buffer['parents'] = array();
71 }
73 /* Append objectClass to resulsts */
74 foreach($attributes as $val){
75 if(isset($attr[$val])){
76 $buffer[$val] = $attr[$val];
77 }
78 }
79 unset($buffer['objectClass']['count']);
80 }
82 /* Add this object to our list */
83 $buffer['dn'] = $attr['dn'];
84 $res[$name] = $buffer;
85 }
86 }
87 }
88 return($res);
89 }
92 /* Return all relevant FAI departments */
93 static function get_FAI_departments($suffix = "")
94 {
95 $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
96 $tmp = array();
97 if(preg_match("/^,/",$suffix)){
98 $suffix = preg_replace("/^,/","",$suffix);
99 }
100 foreach($arr as $name){
101 if(empty($suffix)){
102 $tmp[$name] = "ou=".$name;
103 }else{
104 $tmp[$name] = "ou=".$name.",".$suffix;
105 }
106 }
107 return($tmp);
108 }
111 /* Return all releases within the given base */
112 static function get_all_releases_from_base($dn,$appendedName=false)
113 {
114 global $config;
116 if(!preg_match("/".normalizePreg(get_ou('faiou'))."/",$dn)){
117 $base = get_ou('faiou').$dn;
118 }else{
119 $base = $dn;
120 }
121 $res = array();
123 $ldap = $config->get_ldap_link();
124 $ldap->cd($base);
125 $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
126 while($attrs = $ldap->fetch()){
127 if($appendedName){
128 $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".normalizePreg(get_ou('faiou')).".*$/","",$attrs['dn']));
129 }else{
130 $res[$attrs['dn']] = $attrs['ou'][0];
131 }
132 }
133 return($res);
134 }
137 /* Add this object to list of objects, that must be checked for release saving */
138 static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
139 {
140 /* Get ldap object */
141 global $config;
142 $addObj['Current_DN'] = $Current_DN;
143 $addObj['objectAttrs']= $objectAttrs;
144 $addObj['removed'] = $removed;
145 $addObj['diff'] = TRUE;
147 if(!$removed){
148 $ldap = $config->get_ldap_link();
149 $ldap->cd($config->current['BASE']);
151 /* Get some basic informations */
152 $parent_obj = FAI::get_parent_release_object($Current_DN);
153 if(!empty($parent_obj)){
154 $ldap->cat($parent_obj,array("*"));
155 $attrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
157 if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
158 $addObj['diff'] = FALSE;
159 }
160 }
161 }else{
163 /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
164 we have to remove this name from all profiles in this release.
165 */
166 $ldap = $config->get_ldap_link();
167 $ldap->cd($config->current['BASE']);
168 $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
170 /* Dont't try to modify non FAIclasses
171 */
172 if(!preg_match("/[^,]+,".normalizePreg(get_ou("faiou"))."/",$obj_dn)){
173 trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);
174 echo "<br>-->".$Current_DN."<br>";
175 echo "<br>-->".$obj_dn."<br>";
176 }else{
178 /* Get source object and check if it is a base FAIclass
179 */
180 $ldap->cat($obj_dn);
181 $attrs = $ldap->fetch();
182 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
183 if(count(array_intersect($classes,$attrs['objectClass']))){
184 $cn = $attrs['cn'][0];
186 /* Check if this is the last with this name in the current release.
187 In this case we have to remove the package name
188 from all profiles in this release.
189 */
190 $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
191 "(&(objectClass=FAIclass)(cn=".$cn."))");
193 /* Check if this is the last class with this name.
194 */
195 if(count($classes) == 1){
197 /* Get all FAI Profiles
198 */
199 $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
200 "(&(objectClass=FAIprofile)(FAIclass=*))");
202 /* Walk though all profiles and remove the source class name
203 */
204 foreach($profiles as $dn){
205 $ldap->cat($dn['dn']);
206 $attrs = $ldap->fetch();
208 $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
210 /* Check if this Profile uses the source class ($cn)
211 */
212 if(preg_match("/".normalizePreg($cn)."/",$attrs['FAIclass'])){
213 $attrs['FAIclass'] = preg_replace("/[ ]*".normalizePreg($cn)."[ ]*/i"," ",$attrs['FAIclass']);
214 if(empty($attrs['FAIclass'])){
215 $attrs['FAIclass'] = array();
216 }
217 $ldap->cd($dn['dn']);
218 $ldap->modify($attrs);
220 if (!$ldap->success()){
221 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
222 }
223 }
224 }
225 }
226 }
227 }
228 }
232 $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
233 $FAI_objects_to_save[$Current_DN] = $addObj;
234 session::set('FAI_objects_to_save',$FAI_objects_to_save);
235 }
238 /* Detect differences in attribute arrays */
239 static function array_diff_FAI($ar1,$ar2)
240 {
242 if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
243 $ar1['description'] = "";
244 }
245 if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
246 $ar2['description'] = "";
247 }
249 if(count($ar1) != count($ar2)) {
250 return (true);
251 }
253 foreach($ar1 as $key1 => $val1){
255 if((is_array($val1)) && (count($val1)==1)){
256 $ar1[$key1] = $val1[0];
257 }
259 if(isset($ar2[$key1])&& (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
260 $val1 = $val1[0];
261 $ar2[$key1] = $ar2[$key1][0];
262 }
263 }
264 ksort($ar1);
265 ksort($ar2);
266 if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
267 return(true);
268 }else{
269 return(false);
270 }
271 }
274 static function arr_diff($ar1,$ar2)
275 {
276 foreach($ar1 as $ak1 => $av1){
277 if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
278 return(TRUE);
279 }elseif(is_array($av1)){
280 $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
281 if($ret) {
282 return(TRUE);
283 }
284 }
285 }
286 return(FALSE);
287 }
292 /* check which objects must be saved, and save them */
293 static function save_release_changes_now()
294 {
295 global $config;
296 /* Variable init*/
297 $to_save = array();
299 $reload_fai_classes = FALSE;
301 /* check which objects must be saved */
302 if(!session::is_set('FAI_objects_to_save')){
303 return;
304 }
305 $FAI_objects_to_save = session::get('FAI_objects_to_save');
306 if(!is_array($FAI_objects_to_save)) {
307 print_a(array(session::get('FAI_objects_to_save')));
308 trigger_error("Can't save FAI objects, no array given.");
309 return;
310 }
312 foreach($FAI_objects_to_save as $Current_DN => $object){
313 if($object['diff']){
314 $sub_name = $Current_DN;
315 while(isset($FAI_objects_to_save[$sub_name])){
316 $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name];
317 unset($FAI_objects_to_save[$sub_name]);
318 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
319 }
320 }
321 }
322 session::set('FAI_objects_to_save',$FAI_objects_to_save);
324 /* Sort list of objects that must be saved, and ensure that
325 container objects are safed, before their childs are saved */
326 ksort($to_save);
327 $tmp = array();
328 foreach($to_save as $SubObjects){
329 foreach($SubObjects as $object){
330 $tmp[] = $object;
331 }
332 }
333 $to_save = $tmp;
336 /* Save objects and manage the correct release behavior*/
337 foreach($to_save as $save){
339 $Current_DN = $save['Current_DN'];
340 $removed = $save['removed'];
341 $objectAttrs= $save['objectAttrs'];
343 /* Get ldap object */
344 $ldap = $config->get_ldap_link();
345 $ldap->cd($config->current['BASE']);
347 /* Get some basic informations */
348 $base_release = FAI::get_release_dn($Current_DN);
349 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release,true);
350 $parent_obj = FAI::get_parent_release_object($Current_DN);
351 $following_releases = FAI:: get_sub_releases_of_this_release($base_release,true);
353 /* Check if given dn exists or if is a new entry */
354 $ldap->cat($Current_DN);
355 if(!$ldap->count()){
356 $is_new = true;
357 }else{
358 $is_new = false;
359 }
361 /* if parameter removed is true, we have to add FAIstate to the current attrs
362 FAIstate should end with ...|removed after this operation */
363 if($removed ){
364 $ldap->cat($Current_DN);
366 /* Get current object, because we must add the FAIstate ...|removed */
367 if((!$ldap->count()) && !empty($parent_obj)){
368 $ldap->cat($parent_obj);
369 }
371 /* Check if we have found a suiteable object */
372 if(!$ldap->count()){
373 echo "Error can't remove this object ".$Current_DN;
374 return;
375 }else{
377 /* Set FAIstate to current objectAttrs */
378 $objectAttrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
379 if(isset($objectAttrs['FAIstate'][0])){
380 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
381 $objectAttrs['FAIstate'][0] .= "|removed";
382 }
383 }else{
384 $objectAttrs['FAIstate'][0] = "|removed";
385 }
387 /* Force reload of FAI classes */
388 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
389 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
390 $reload_fai_classes = TRUE;
391 }
392 }
393 }
395 /* Check if this a leaf release or not */
396 if(count($following_releases) == 0 ){
398 /* This is a leaf object. It isn't inherited by any other object */
399 if(DEBUG_FAI_FUNC) {
400 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
401 print_a($objectAttrs);
402 }
403 FAI::save_FAI_object($Current_DN,$objectAttrs);
405 /* Force reload of FAI classes */
406 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
407 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
408 $reload_fai_classes = TRUE;
409 }
411 }else{
413 /* This object is inherited by some sub releases */
415 /* Get all releases, that inherit this object */
416 $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
418 /* Get parent object */
419 $ldap->cat($parent_obj);
420 $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
422 /* New objects require special handling */
423 if($is_new){
425 /* Force reload of FAI classes */
426 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
427 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
428 $reload_fai_classes = TRUE;
429 }
431 /* check if there is already an entry named like this,
432 in one of our parent releases */
433 if(!empty($parent_obj)){
434 if(DEBUG_FAI_FUNC) {
435 echo "There is already an entry named like this.</b><br>";
437 echo "<b>Saving main object</b>".$Current_DN;
438 print_a($objectAttrs);
439 }
440 FAI::save_FAI_object($Current_DN,$objectAttrs);
442 foreach($r as $key){
443 if(DEBUG_FAI_FUNC) {
444 echo "<b>Saving parent to following release</b> ".$key;
445 print_a($parent_attrs);
446 }
447 FAI::save_FAI_object($key,$parent_attrs);
448 }
449 }else{
451 if(DEBUG_FAI_FUNC) {
452 echo "<b>Saving main object</b>".$Current_DN;
453 print_a($objectAttrs);
454 }
455 FAI::save_FAI_object($Current_DN,$objectAttrs);
457 if(isset($objectAttrs['FAIstate'])){
458 $objectAttrs['FAIstate'] .= "|removed";
459 }else{
460 $objectAttrs['FAIstate'] = "|removed";
461 }
463 foreach($r as $key ){
464 if(DEBUG_FAI_FUNC) {
465 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
466 print_a($objectAttrs);
467 }
468 FAI::save_FAI_object($key,$objectAttrs);
469 }
470 }
471 }else{
473 /* check if we must patch the follwing release */
474 if(!empty($r)){
475 foreach($r as $key ){
476 if(DEBUG_FAI_FUNC) {
477 echo "<b>Copy current objects original attributes to next release</b> ".$key;
478 print_a($parent_attrs);
479 }
480 FAI::save_FAI_object($key,$parent_attrs);
481 }
482 }
484 if(DEBUG_FAI_FUNC) {
485 echo "<b>Saving current object</b>".$parent_obj;
486 print_a($objectAttrs);
487 }
488 FAI::save_FAI_object($parent_obj,$objectAttrs);
490 if(($parent_obj != $Current_DN)){
491 msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
492 }
493 }
494 }
495 }
497 /* Reload GOsa si FAI DB/cache
498 */
499 if($reload_fai_classes){
500 if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
501 $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);
502 if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
503 $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'];
504 $tmp = new $evt['CLASS_NAME']($config);
505 $tmp->set_type(TRIGGERED_EVENT);
506 $tmp->add_targets(array("GOsa"));
507 $o_queue = new gosaSupportDaemon();
508 if(!$o_queue->append($tmp)){
509 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
510 }
511 }
512 }
513 }
515 session::set('FAI_objects_to_save',array());
516 }
519 /* this function will remove all unused (deleted) objects,
520 that have no parent object */
521 static function clean_up_releases($Current_DN)
522 {
523 global $config;
524 $ldap = $config->get_ldap_link();
525 $ldap->cd($config->current['BASE']);
527 /* Collect some basic informations and initialize some variables */
528 $base_release = FAI::get_release_dn($Current_DN);
529 $previous_releases = array_reverse(FAI:: get_previous_releases_of_this_release($base_release,true));
530 $Kill = array();
531 $Skip = array();
533 /* We must also include the given release dn */
534 $previous_releases[] = $base_release;
536 /* Walk through all releases */
537 foreach($previous_releases as $release){
539 /* Get fai departments */
540 $deps_to_search = FAI::get_FAI_departments($release);
542 /* For every single department (ou=hoos,ou ..) */
543 foreach($deps_to_search as $fai_base){
545 /* Ldap search for fai classes specified in this release */
546 $ldap->cd($fai_base);
547 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
549 /* check the returned objects, and add/replace them in our return variable */
550 while($attr = $ldap->fetch()){
552 $buffer = array();
553 # $name = str_ireplace($release,"",$attr['dn']);
554 $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
556 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
558 /* Check if this object is required somehow */
559 if(!isset($Skip[$name])){
560 $Kill[$attr['dn']] = $attr['dn'];
561 }
562 }else{
564 /* This object is required (not removed), so do not
565 delete any following sub releases of this object */
566 $Skip[$name] = $attr['dn'];
567 }
568 }
569 }
570 }
571 return($Kill);
572 }
575 /* Remove numeric index and 'count' from ldap->fetch result */
576 static function prepare_ldap_fetch_to_be_saved($attrs)
577 {
578 foreach($attrs as $key => $value){
579 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
580 unset($attrs[$key]);
581 }
582 if(is_array($value) && isset($value['count'])){
583 unset($attrs[$key]['count']);
584 }
585 }
586 return($attrs);
587 }
590 /* Save given attrs to specified dn*/
591 static function save_FAI_object($dn,$attrs)
592 {
593 global $config;
594 $ldap = $config->get_ldap_link();
595 $ldap->cd($config->current['BASE']);
596 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
597 $ldap->cd($dn);
599 $ldap->cat($dn,array("dn"));
600 if($ldap->count()){
602 /* Remove FAIstate*/
603 if(!isset($attrs['FAIstate'])){
604 $attrs['FAIstate'] = array();
605 }
607 $ldap->modify($attrs);
608 }else{
610 /* Unset description if empty */
611 if(empty($attrs['description'])){
612 unset($attrs['description']);
613 }
615 $ldap->add($attrs);
616 }
617 if (!$ldap->success()){
618 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
619 }
620 }
623 /* Return FAIstate freeze branch or "" for specified release department */
624 static function get_release_tag($dn)
625 {
626 global $config;
627 $ldap = $config->get_ldap_link();
628 $ldap->cd($dn);
629 $ldap->cat($dn,array("FAIstate"));
631 if($ldap->count()){
633 $attr = $ldap->fetch();
634 if(isset($attr['FAIstate'][0])){
635 if(preg_match("/freeze/",$attr['FAIstate'][0])){
636 return("freeze");
637 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
638 return("branch");
639 }
640 }
641 }
642 return("");
643 }
646 static function get_following_releases_that_inherit_this_object($dn)
647 {
648 global $config;
649 $ldap = $config->get_ldap_link();
650 $ldap->cd($config->current['BASE']);
652 $ret = array();
654 /* Get base release */
655 $base_release = FAI::get_release_dn($dn);
657 /* Get previous release dns */
658 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release);
660 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
661 # $dn_suffix = str_ireplace($base_release,"",$dn);
662 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
664 /* Check if given object also exists whitin one of these releases */
665 foreach($sub_releases as $p_release => $name){
667 $check_dn = $dn_suffix.$p_release;
669 $ldap->cat($check_dn,array("dn","objectClass"));
671 if($ldap->count()){
672 //return($ret);
673 }else{
674 $ret[$check_dn]=$check_dn;
675 }
676 }
677 return($ret);
678 }
681 /* Get previous version of the object dn */
682 static function get_parent_release_object($dn,$include_myself=true)
683 {
684 global $config;
685 $ldap = $config->get_ldap_link();
686 $ldap->cd($config->current['BASE']);
687 $previous_releases= array();
689 /* Get base release */
690 $base_release = FAI::get_release_dn($dn);
691 if($include_myself){
692 $previous_releases[] = $base_release;
693 }
695 /* Get previous release dns */
696 $tmp = FAI:: get_previous_releases_of_this_release($base_release,true);
697 foreach($tmp as $release){
698 $previous_releases[] = $release;
699 }
701 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
702 # $dn_suffix = str_ireplace($base_release,"",$dn);
703 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
705 /* Check if given object also exists whitin one of these releases */
706 foreach($previous_releases as $p_release){
707 $check_dn = $dn_suffix.$p_release;
708 $ldap->cat($check_dn,array("dn","objectClass"));
710 if($ldap->count()){
711 return($check_dn);
712 }
713 }
714 return("");
715 }
718 /* return release names of all parent releases */
719 static function get_previous_releases_of_this_release($dn,$flat)
720 {
721 global $config;
722 $ldap = $config->get_ldap_link();
723 $ldap->cd($config->current['BASE']);
724 $ret = array();
726 /* Explode dns into pieces, to be able to build parent dns */
727 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
729 if(!is_array($dns_to_check)){
730 return;
731 }
733 /* Unset first entry which represents the given dn */
734 unset($dns_to_check['count']);
735 unset($dns_to_check[key($dns_to_check)]);
737 /* Create dns addresses and check if this dn is a release dn */
738 $id = 0;
739 while(count($dns_to_check)){
741 /* build parent dn */
742 $new_dn = "";
743 foreach($dns_to_check as $part){
744 $new_dn .= $part.",";
745 }
746 $new_dn .= $config->current['BASE'];
748 /* check if this dn is a release */
749 if(FAI::is_release_department($new_dn)){
750 if($flat){
751 $ret[$id] = $new_dn;
752 }else{
753 $ret = array($new_dn=>$ret);
754 }
755 $id ++;
756 }else{
757 return($ret);
758 }
759 reset($dns_to_check);
760 unset($dns_to_check[key($dns_to_check)]);
761 }
762 return($ret);
763 }
766 /* This function returns all sub release names, recursivly */
767 static function get_sub_releases_of_this_release($dn,$flat = false)
768 {
769 global $config;
770 $res = array();
771 $ldap = $config->get_ldap_link();
772 $ldap->cd($config->current['BASE']);
773 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
774 while($attr = $ldap->fetch()){
776 /* Append department name */
777 if($flat){
778 $res[$attr['dn']] = $attr['ou'][0];
779 }else{
780 $res[$attr['dn']] = array();
781 }
783 /* Get sub release departments of this department */
784 if(in_array("FAIbranch",$attr['objectClass'])) {
785 if($flat){
786 $tmp = FAI:: get_sub_releases_of_this_release($attr['dn'],$flat);
787 foreach($tmp as $dn => $value){
788 $res[$dn]=$value;
789 }
790 }else{
791 $res[$attr['dn']] = FAI:: get_sub_releases_of_this_release($attr['dn']);
792 }
793 }
794 }
795 return($res);
796 }
799 /* Check if the given department is a release department */
800 static function is_release_department($dn)
801 {
802 global $config;
803 $ldap = $config->get_ldap_link();
804 $ldap->cd($config->current['BASE']);
805 $ldap->cat($dn,array("objectClass","ou"));
807 /* Check objectClasses and name to check if this is a release department */
808 if($ldap->count()){
809 $attrs = $ldap->fetch();
811 $ou = "";
812 if(isset($attrs['ou'][0])){
813 $ou = $attrs['ou'][0];
814 }
816 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
817 return($attrs['dn']);
818 }
819 }
820 return(false);
821 }
824 static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
825 {
826 global $config;
827 $start = microtime(TRUE);
828 $source_release = trim($source_release,"/");
830 echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
832 $sub_releases = array();
833 $source_dn = "";
835 $tmp = split("\/",$source_release);
836 foreach($tmp as $part){
837 if(empty($part)){
838 continue;
839 }
840 $source_dn = "ou=".$part.",".$source_dn;
841 $sub_releases[$part] = $source_dn;
842 }
844 /* Get all groups */
845 $ldap =$config->get_ldap_link();
846 $ldap->cd($config->current['BASE']);
847 $ldap->search("(objectClass=posixGroup)",array("dn"));
848 $groups = array();
849 while($attrs = $ldap->fetch()){
850 $groups[$attrs['dn']] = $attrs;
851 }
853 /* Get all FAI releases, to be able to create missing group application releases
854 with the correct type of release (FAIstate=freeze/branch).
855 */
856 $f_releases = array();
857 $ldap->cd ($config->current['BASE']);
858 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
859 while($attrs = $ldap->fetch()){
860 foreach($sub_releases as $sub_rel){
861 if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
862 $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
863 }
864 }
865 }
867 /* Get all group releases */
868 $g_releases = array();
869 foreach($groups as $dn => $data){
870 $ldap->cd($dn);
871 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
872 while($attrs = $ldap->fetch()){
873 $g_releases[$attrs['dn']] = $attrs;
874 }
875 }
877 /* Check if base releases exists.
878 If they do not exist, create them and adapt FAIstate attribute from FAI releases.
879 */
880 foreach($sub_releases as $name => $sub_rel){
882 $FAIstate = "";
883 if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
884 $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
885 }
887 foreach($groups as $dn => $data){
888 if(!isset($g_releases[$sub_rel.$dn])){
889 $ldap->cd($dn);
890 $r_data = array();
891 $r_data['ou'] = $name;
892 $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
893 if(!empty($FAIstate)) {
894 $r_data['FAIstate'] = $FAIstate;
895 }
897 $ldap->cd($sub_rel.$dn) ;
898 $ldap->add($r_data);
899 echo " <b>"._("Object").":</b> ";
900 echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
901 flush();
902 }
903 }
904 }
906 /* Create new release container in each group.
907 */
908 $n_data = array();
909 $n_data = array();
910 $n_data['ou'] = $destination_name;
911 $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
912 if(!empty($type)){
913 $n_data['FAIstate'] = $type."/cow";
914 }
916 foreach($groups as $dn => $att){
917 $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
918 if(!isset($g_releases[$n_dn])){
919 $ldap->cd ($n_dn);
920 $ldap->add($n_data);
921 echo " <b>"._("Object").":</b> ";
922 echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
923 flush();
924 }
925 }
927 /* If the source release is empty, then create a new release by copying
928 all group application menus into a new ou=$destination_name release container.
930 If the source release is not empty.
931 We detect all releases which match the source release dn and copy the contents.
932 */
933 if(empty($source_release)){
934 $source_dns = $groups;
935 }else{
936 $source_dns = array();
937 foreach($g_releases as $dn => $data){
938 if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
939 $source_dns[$dn] = $data;
940 }
941 }
942 }
944 /* Detect all menu object we have to copy
945 */
946 $to_copy = array();
947 foreach($source_dns as $dn => $attrs){
948 $ldap->cd($dn);
949 $ldap->ls("(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry)",$dn,array("dn"));
950 while($attrs = $ldap->fetch()){
951 $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
952 $to_copy[$attrs['dn']] = $destination;
953 }
954 }
956 /* At least create the menu objects object */
957 $plug = new plugin($config);
958 foreach($to_copy as $source => $destination){
959 $ldap->cat($destination);
960 if($ldap->count()){
961 echo " <b>"._("Object").":</b> ";
962 echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
963 flush();
964 }else{
965 $plug->copy($source,$destination);
966 echo " <b>"._("Object").":</b> ";
967 echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
968 flush();
969 }
970 }
971 }
974 /*! \brief Create a new FAI branch.
975 * @param $sourcedn String The source release dn
976 * @param $destinationdn String The destination dn
977 * @param $destinationName String The name of the new release
978 * @param $type String The release type (freeze/branch)
979 * @param $is_first Boolean Use to identify the first func. call when recursivly called.
980 * @param $depth Integer Current depth of recursion.
981 */
982 function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
983 {
984 global $config;
985 error_reporting(E_ALL | E_STRICT);
986 $ldap = $config->get_ldap_link();
987 $basedn = $config->current['BASE'];
988 $delarray = array();
990 /* The following code will output a status string
991 * for each handled object, in a seperate iframe.
992 */
995 /* Display current action information.
996 */
997 if($is_first){
998 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
999 }else{
1000 if(preg_match("/^ou=/",$sourcedn)){
1001 echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1002 }else{
1003 $tmp = split(",",$sourcedn);
1004 echo " <b>"._("Object").":</b> ";
1005 $deststr = LDAP::fix($destinationdn);
1006 if(strlen($deststr) > 96){
1007 $deststr = substr($deststr,0,96)."...";
1008 }
1009 echo $deststr."<br>";
1010 }
1011 }
1012 /* .. immediately display infos */
1013 flush();
1015 /* Check if destination entry already exists
1016 */
1017 $ldap->cat($destinationdn);
1018 if($ldap->count()){
1019 echo _("Could not create new release, the destination dn is already in use.");
1020 return;
1021 }else{
1023 $ldap->clearResult();
1025 /* Get source entry
1026 * if it does not exist, abort here.
1027 */
1028 $ldap->cd($basedn);
1029 $ldap->cat($sourcedn);
1030 $attr = $ldap->fetch();
1031 if((!$attr) || (count($attr)) ==0) {
1032 echo _("Error while fetching source dn - aborted!");
1033 return;
1034 }
1036 /* The current object we want to create is an department.
1037 * Create the department and add the FAIbranch tag.
1038 */
1039 if(in_array("organizationalUnit",$attr['objectClass'])){
1040 $attr['dn'] = LDAP::convert($destinationdn);
1041 $ldap->cd($basedn);
1042 $ldap->create_missing_trees($destinationdn);
1043 $ldap->cd($destinationdn);
1045 /* If is first entry, append FAIbranch to department entry */
1046 if($is_first){
1047 $ldap->cat($destinationdn);
1048 $attr= $ldap->fetch();
1049 /* Filter unneeded informations */
1050 foreach($attr as $key => $value){
1051 if(is_numeric($key)) unset($attr[$key]);
1052 if(isset($attr[$key]['count'])){
1053 if(is_array($attr[$key])){
1054 unset($attr[$key]['count']);
1055 }
1056 }
1057 }
1059 unset($attr['count']);
1060 unset($attr['dn']);
1062 /* Add marking attribute */
1063 $attr['objectClass'][] = "FAIbranch";
1065 /* Add this entry */
1066 $ldap->modify($attr);
1067 }
1068 }else{
1070 /* Replicate all relevant FAI objects here.
1071 * FAI objects, Apps and Mimetypes.
1072 * Get all attributes as binary value, to ensure that Icon, File template aso
1073 * are created correctly.
1074 */
1075 foreach($attr as $key => $value){
1077 if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1078 $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1079 $ei= ldap_first_entry($ldap->cid, $sr);
1080 if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1081 $attr[$key] = $tmp;
1082 }
1083 }
1085 if(is_numeric($key)) unset($attr[$key]);
1086 if(isset($attr[$key]['count'])){
1087 if(is_array($attr[$key])){
1088 unset($attr[$key]['count']);
1089 }
1090 }
1091 }
1092 unset($attr['count']);
1093 unset($attr['dn']);
1095 /* Add entry
1096 */
1097 $ldap->cd($destinationdn);
1098 $ldap->cat($destinationdn);
1100 $a = $ldap->fetch();
1101 if(!count($a)){
1102 $ldap->add($attr);
1103 }
1105 if(!$ldap->success()){
1107 /* Some error occurred */
1108 print "---------------------------------------------";
1109 print $ldap->get_error()."<br>";
1110 print $sourcedn."<br>";
1111 print $destinationdn."<br>";
1112 print_a( $attr);
1113 exit();
1114 }
1115 }
1116 }
1118 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1120 /* Prepare for recursive copy.
1121 * Get all object within the source dn and
1122 * call the recursive copy for each.
1123 */
1124 $ldap->ls ("(objectClass=*)",$sourcedn);
1125 while ($ldap->fetch()){
1126 $deldn= $ldap->getDN();
1127 $delarray[$deldn]= strlen($deldn);
1128 }
1129 asort ($delarray);
1130 reset ($delarray);
1131 $depth ++;
1132 foreach($delarray as $dn => $bla){
1133 if($dn != $destinationdn){
1134 $ldap->cd($basedn);
1135 $item = $ldap->fetch($ldap->cat($dn));
1136 if(!in_array("FAIbranch",$item['objectClass'])){
1137 FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1138 }
1139 }
1140 }
1141 if($is_first){
1142 echo "<p class='seperator'> </p>";
1143 }
1144 }
1148 /* This function returns the dn of the object release */
1149 static function get_release_dn($Current_DN)
1150 {
1151 global $config;
1152 $ldap = $config->get_ldap_link();
1153 $ldap->cd($config->current['BASE']);
1155 /* Split dn into pices */
1156 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1158 if(!is_array($dns_to_check)){
1159 return;
1160 }
1162 /* Use dn pieces, to create sub dns like
1163 ou=test,ou=1,ou=0...
1164 ou=1,ou=0...
1165 ou=0...
1166 To check which dn is our release container.
1167 */
1168 unset($dns_to_check['count']);
1169 while(count($dns_to_check)){
1171 /* Create dn */
1172 $new_dn = "";
1173 foreach($dns_to_check as $part){
1174 $new_dn .= $part.",";
1175 }
1176 $new_dn .= $config->current['BASE'];
1178 /* Check if this dn is a release dn */
1179 if(FAI::is_release_department($new_dn)){
1180 return($new_dn);
1181 }
1183 /* Remove first element of dn pieces */
1184 reset($dns_to_check);
1185 unset($dns_to_check[key($dns_to_check)]);
1186 }
1187 return("");
1188 }
1189 }
1194 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1195 ?>