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