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 $sub_releases = array_keys(FAI::get_sub_releases_of_this_release($base_release,false));
575 $Kill = array();
576 $Skip = array();
578 /* We must also include the given release dn */
579 $previous_releases[] = $base_release;
581 /* Merge parent, current and child releases into one big release to
582 iterate over */
583 $all_releases = $previous_releases;
584 foreach($sub_releases as $sub_release){
585 $all_releases[] = $sub_release;
586 }
588 /* Walk through all releases */
589 foreach($all_releases as $release){
591 /* Get fai departments */
592 $deps_to_search = FAI::get_FAI_departments($release);
594 /* For every single department (ou=hoos,ou ..) */
595 foreach($deps_to_search as $fai_base){
597 /* Ldap search for fai classes specified in this release */
598 $ldap->cd($fai_base);
599 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
601 /* check the returned objects, and add/replace them in our return variable */
602 while($attr = $ldap->fetch()){
604 $buffer = array();
605 # $name = str_ireplace($release,"",$attr['dn']);
606 $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
608 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
610 /* Check if this object is required somehow */
611 if(!isset($Skip[$name])){
612 $Kill[$attr['dn']] = $attr['dn'];
613 }
614 }else{
616 /* This object is required (not removed), so do not
617 delete any following sub releases of this object */
618 $Skip[$name] = $attr['dn'];
619 }
620 }
621 }
622 }
623 return($Kill);
624 }
627 /* Remove numeric index and 'count' from ldap->fetch result */
628 static function prepare_ldap_fetch_to_be_saved($attrs)
629 {
630 foreach($attrs as $key => $value){
631 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
632 unset($attrs[$key]);
633 }
634 if(is_array($value) && isset($value['count'])){
635 unset($attrs[$key]['count']);
636 }
637 }
638 return($attrs);
639 }
642 /* Save given attrs to specified dn*/
643 static function save_FAI_object($dn,$attrs)
644 {
645 global $config;
646 $ldap = $config->get_ldap_link();
647 $ldap->cd($config->current['BASE']);
648 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
649 $ldap->cd($dn);
651 $ui= get_userinfo();
652 FAI::tag_attrs($attrs, $dn, $ui->gosaUnitTag);
654 $ldap->cat($dn,array("dn"));
655 if($ldap->count()){
657 /* Remove FAIstate*/
658 if(!isset($attrs['FAIstate'])){
659 $attrs['FAIstate'] = array();
660 }
662 $ldap->modify($attrs);
663 }else{
665 /* Unset description if empty */
666 if(empty($attrs['description'])){
667 unset($attrs['description']);
668 }
670 $ldap->add($attrs);
671 }
672 if (!$ldap->success()){
673 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
674 }
675 }
678 /* Return FAIstate freeze branch or "" for specified release department */
679 static function get_release_tag($dn)
680 {
681 global $config;
682 $ldap = $config->get_ldap_link();
683 $ldap->cd($dn);
684 $ldap->cat($dn,array("FAIstate"));
686 if($ldap->count()){
688 $attr = $ldap->fetch();
689 if(isset($attr['FAIstate'][0])){
690 if(preg_match("/freeze/",$attr['FAIstate'][0])){
691 return("freeze");
692 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
693 return("branch");
694 }
695 }
696 }
697 return("");
698 }
701 static function get_following_releases_that_inherit_this_object($dn)
702 {
703 global $config;
704 $ldap = $config->get_ldap_link();
705 $ldap->cd($config->current['BASE']);
707 $ret = array();
709 /* Get base release */
710 $base_release = FAI::get_release_dn($dn);
712 /* Get previous release dns */
713 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release);
715 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
716 # $dn_suffix = str_ireplace($base_release,"",$dn);
717 $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
719 /* Check if given object also exists whitin one of these releases */
720 foreach($sub_releases as $p_release => $name){
722 $check_dn = $dn_suffix.$p_release;
724 $ldap->cat($check_dn,array("dn","objectClass"));
726 if($ldap->count()){
727 //return($ret);
728 }else{
729 $ret[$check_dn]=$check_dn;
730 }
731 }
732 return($ret);
733 }
736 /* Get previous version of the object dn */
737 static function get_parent_release_object($dn,$include_myself=true)
738 {
739 global $config;
740 $ldap = $config->get_ldap_link();
741 $ldap->cd($config->current['BASE']);
742 $previous_releases= array();
744 /* Get base release */
745 $base_release = FAI::get_release_dn($dn);
746 if($include_myself){
747 $previous_releases[] = $base_release;
748 }
750 /* Get previous release dns */
751 $tmp = FAI:: get_previous_releases_of_this_release($base_release,true);
752 foreach($tmp as $release){
753 $previous_releases[] = $release;
754 }
756 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
757 # $dn_suffix = str_ireplace($base_release,"",$dn);
758 $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
760 /* Check if given object also exists whitin one of these releases */
761 foreach($previous_releases as $p_release){
762 $check_dn = $dn_suffix.$p_release;
763 $ldap->cat($check_dn,array("dn","objectClass"));
765 if($ldap->count()){
766 return($check_dn);
767 }
768 }
769 return("");
770 }
773 /* return release names of all parent releases */
774 static function get_previous_releases_of_this_release($dn,$flat)
775 {
776 global $config;
777 $ldap = $config->get_ldap_link();
778 $ldap->cd($config->current['BASE']);
779 $ret = array();
781 /* Explode dns into pieces, to be able to build parent dns */
782 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$dn));
784 if(!is_array($dns_to_check)){
785 return;
786 }
788 /* Unset first entry which represents the given dn */
789 unset($dns_to_check['count']);
790 unset($dns_to_check[key($dns_to_check)]);
792 /* Create dns addresses and check if this dn is a release dn */
793 $id = 0;
794 while(count($dns_to_check)){
796 /* build parent dn */
797 $new_dn = "";
798 foreach($dns_to_check as $part){
799 $new_dn .= $part.",";
800 }
801 $new_dn .= $config->current['BASE'];
803 /* check if this dn is a release */
804 if(FAI::is_release_department($new_dn)){
805 if($flat){
806 $ret[$id] = $new_dn;
807 }else{
808 $ret = array($new_dn=>$ret);
809 }
810 $id ++;
811 }else{
812 return($ret);
813 }
814 reset($dns_to_check);
815 unset($dns_to_check[key($dns_to_check)]);
816 }
817 return($ret);
818 }
821 /* This function returns all sub release names, recursivly */
822 static function get_sub_releases_of_this_release($dn,$flat = false)
823 {
824 global $config;
825 $res = array();
826 $ldap = $config->get_ldap_link();
827 $ldap->cd($config->current['BASE']);
828 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
829 while($attr = $ldap->fetch()){
831 /* Append department name */
832 if($flat){
833 $res[$attr['dn']] = $attr['ou'][0];
834 }else{
835 $res[$attr['dn']] = array();
836 }
838 /* Get sub release departments of this department */
839 if(in_array("FAIbranch",$attr['objectClass'])) {
840 if($flat){
841 $tmp = FAI:: get_sub_releases_of_this_release($attr['dn'],$flat);
842 foreach($tmp as $dn => $value){
843 $res[$dn]=$value;
844 }
845 }else{
846 $res[$attr['dn']] = FAI:: get_sub_releases_of_this_release($attr['dn']);
847 }
848 }
849 }
850 return($res);
851 }
854 /* Check if the given department is a release department */
855 static function is_release_department($dn)
856 {
857 global $config;
858 $ldap = $config->get_ldap_link();
859 $ldap->cd($config->current['BASE']);
860 $ldap->cat($dn,array("objectClass","ou"));
862 /* Check objectClasses and name to check if this is a release department */
863 if($ldap->count()){
864 $attrs = $ldap->fetch();
866 $ou = "";
867 if(isset($attrs['ou'][0])){
868 $ou = $attrs['ou'][0];
869 }
871 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
872 return($attrs['dn']);
873 }
874 }
875 return(false);
876 }
879 static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
880 {
881 global $config;
882 $start = microtime(TRUE);
883 $source_release = trim($source_release,"/");
885 echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
887 $sub_releases = array();
888 $source_dn = "";
890 $tmp = split("\/",$source_release);
891 foreach($tmp as $part){
892 if(empty($part)){
893 continue;
894 }
895 $source_dn = "ou=".$part.",".$source_dn;
896 $sub_releases[$part] = $source_dn;
897 }
899 /* Get all groups */
900 $ldap =$config->get_ldap_link();
901 $ldap->cd($config->current['BASE']);
902 $ldap->search("(objectClass=posixGroup)",array("dn"));
903 $groups = array();
904 while($attrs = $ldap->fetch()){
905 $groups[$attrs['dn']] = $attrs;
906 }
908 /* Get all FAI releases, to be able to create missing group application releases
909 with the correct type of release (FAIstate=freeze/branch).
910 */
911 $f_releases = array();
912 $ldap->cd ($config->current['BASE']);
913 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
914 while($attrs = $ldap->fetch()){
915 foreach($sub_releases as $sub_rel){
916 if(preg_match("/^".preg_quote($sub_rel.get_ou('faiBaseRDN'), '/')."/",$attrs['dn'])){
917 $f_releases[$sub_rel.get_ou('faiBaseRDN')] = $attrs;
918 }
919 }
920 }
922 /* Get all group releases */
923 $g_releases = array();
924 foreach($groups as $dn => $data){
925 $ldap->cd($dn);
926 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
927 while($attrs = $ldap->fetch()){
928 $g_releases[$attrs['dn']] = $attrs;
929 }
930 }
932 /* Check if base releases exists.
933 If they do not exist, create them and adapt FAIstate attribute from FAI releases.
934 */
935 foreach($sub_releases as $name => $sub_rel){
937 $FAIstate = "";
938 if(isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]) && isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'])){
939 $FAIstate = $f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'][0];
940 }
942 foreach($groups as $dn => $data){
943 if(!isset($g_releases[$sub_rel.$dn])){
944 $ldap->cd($dn);
945 $r_data = array();
946 $r_data['ou'] = $name;
947 $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
948 if(!empty($FAIstate)) {
949 $r_data['FAIstate'] = $FAIstate;
950 }
952 $ldap->cd($sub_rel.$dn) ;
953 $ldap->add($r_data);
954 echo " <b>"._("Object").":</b> ";
955 echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
956 flush();
957 }
958 }
959 }
961 /* Create new release container in each group.
962 */
963 $n_data = array();
964 $n_data = array();
965 $n_data['ou'] = $destination_name;
966 $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
967 if(!empty($type)){
968 $n_data['FAIstate'] = $type."/cow";
969 }
971 foreach($groups as $dn => $att){
972 $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
973 if(!isset($g_releases[$n_dn])){
974 $ldap->cd ($n_dn);
975 $ldap->add($n_data);
976 echo " <b>"._("Object").":</b> ";
977 echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
978 flush();
979 }
980 }
982 /* If the source release is empty, then create a new release by copying
983 all group application menus into a new ou=$destination_name release container.
985 If the source release is not empty.
986 We detect all releases which match the source release dn and copy the contents.
987 */
988 if(empty($source_release)){
989 $source_dns = $groups;
990 }else{
991 $source_dns = array();
992 foreach($g_releases as $dn => $data){
993 if(preg_match("/^".preg_quote($source_dn, '/')."/",$dn)){
994 $source_dns[$dn] = $data;
995 }
996 }
997 }
999 /* Detect all menu object we have to copy
1000 */
1001 $to_copy = array();
1002 foreach($source_dns as $dn => $attrs){
1003 $ldap->cd($dn);
1004 $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
1005 while($attrs = $ldap->fetch()){
1006 $destination = preg_replace("/".preg_quote($dn, '/')."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
1007 $to_copy[$attrs['dn']] = $destination;
1008 }
1009 }
1011 /* At least create the menu objects object */
1012 $plug = new plugin($config);
1013 foreach($to_copy as $source => $destination){
1014 $ldap->cat($destination);
1015 if($ldap->count()){
1016 echo " <b>"._("Object").":</b> ";
1017 echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
1018 flush();
1019 }else{
1020 $plug->copy($source,$destination);
1021 echo " <b>"._("Object").":</b> ";
1022 echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
1023 flush();
1024 }
1025 }
1026 }
1029 /*! \brief Create a new FAI branch.
1030 * @param $sourcedn String The source release dn
1031 * @param $destinationdn String The destination dn
1032 * @param $destinationName String The name of the new release
1033 * @param $type String The release type (freeze/branch)
1034 * @param $is_first Boolean Use to identify the first func. call when recursivly called.
1035 * @param $depth Integer Current depth of recursion.
1036 */
1037 static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1038 {
1039 global $config;
1040 error_reporting(E_ALL | E_STRICT);
1041 $ldap = $config->get_ldap_link();
1042 $basedn = $config->current['BASE'];
1043 $delarray = array();
1045 /* The following code will output a status string
1046 * for each handled object, in a seperate iframe.
1047 */
1050 /* Display current action information.
1051 */
1052 if($is_first){
1053 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1054 }else{
1055 if(preg_match("/^ou=/",$sourcedn)){
1056 echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1057 }else{
1058 $tmp = split(",",$sourcedn);
1059 echo " <b>"._("Object").":</b> ";
1060 $deststr = LDAP::fix($destinationdn);
1061 if(strlen($deststr) > 96){
1062 $deststr = substr($deststr,0,96)."...";
1063 }
1064 echo $deststr."<br>";
1065 }
1066 }
1067 /* .. immediately display infos */
1068 flush();
1070 /* Check if destination entry already exists
1071 */
1072 $ldap->cat($destinationdn);
1073 if($ldap->count()){
1074 echo _("Could not create new release, the destination dn is already in use.");
1075 return;
1076 }else{
1078 $ldap->clearResult();
1080 /* Get source entry
1081 * if it does not exist, abort here.
1082 */
1083 $ldap->cd($basedn);
1084 $ldap->cat($sourcedn);
1085 $attr = $ldap->fetch();
1086 if((!$attr) || (count($attr)) ==0) {
1087 echo _("Error while fetching source dn - aborted!");
1088 return;
1089 }
1091 /* The current object we want to create is an department.
1092 * Create the department and add the FAIbranch tag.
1093 */
1094 if(in_array("organizationalUnit",$attr['objectClass'])){
1095 $attr['dn'] = LDAP::convert($destinationdn);
1096 $ldap->cd($basedn);
1097 $ldap->create_missing_trees($destinationdn);
1098 $ldap->cd($destinationdn);
1100 /* If is first entry, append FAIbranch to department entry */
1101 if($is_first){
1102 $ldap->cat($destinationdn);
1103 $attr= $ldap->fetch();
1104 /* Filter unneeded informations */
1105 foreach($attr as $key => $value){
1106 if(is_numeric($key)) unset($attr[$key]);
1107 if(isset($attr[$key]['count'])){
1108 if(is_array($attr[$key])){
1109 unset($attr[$key]['count']);
1110 }
1111 }
1112 }
1114 unset($attr['count']);
1115 unset($attr['dn']);
1117 /* Add marking attribute */
1118 $attr['objectClass'][] = "FAIbranch";
1119 $attr['FAIstate'] = $type;
1121 /* Add this entry */
1122 $ldap->modify($attr);
1123 }
1124 }else{
1126 /* Replicate all relevant FAI objects here.
1127 * FAI objects, Apps and Mimetypes.
1128 * Get all attributes as binary value, to ensure that Icon, File template aso
1129 * are created correctly.
1130 */
1131 foreach($attr as $key => $value){
1133 if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1134 $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1135 $ei= ldap_first_entry($ldap->cid, $sr);
1136 if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1137 $attr[$key] = $tmp;
1138 }
1139 }
1141 if(is_numeric($key)) unset($attr[$key]);
1142 if(isset($attr[$key]['count'])){
1143 if(is_array($attr[$key])){
1144 unset($attr[$key]['count']);
1145 }
1146 }
1147 }
1148 unset($attr['count']);
1149 unset($attr['dn']);
1150 if(!in_array("FAIobject",$attr['objectClass'])){
1151 $attr['objectClass'][] = "FAIobject";
1152 }
1153 $attr['FAIstate'] = $type;
1155 /* Add entry
1156 */
1157 $ldap->cd($destinationdn);
1158 $ldap->cat($destinationdn);
1160 $a = $ldap->fetch();
1161 if(!count($a)){
1162 $ldap->add($attr);
1163 }
1165 if(!$ldap->success()){
1167 /* Some error occurred */
1168 msg_dialog::display(_("Fatal error"),
1169 sprintf(_("Release creation failed due to ldap errors. Additional informations '%s'."),
1170 $ldap->get_error()."<br>".$sourcedn."<br>".$destinationdn."<br>"),FATAL_ERROR_DIALOG);
1171 exit();
1172 }
1173 }
1174 }
1176 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1178 /* Prepare for recursive copy.
1179 * Get all object within the source dn and
1180 * call the recursive copy for each.
1181 */
1182 $ldap->ls ("(objectClass=*)",$sourcedn);
1183 while ($ldap->fetch()){
1184 $deldn= $ldap->getDN();
1185 $delarray[$deldn]= strlen($deldn);
1186 }
1187 asort ($delarray);
1188 reset ($delarray);
1189 $depth ++;
1190 foreach($delarray as $dn => $bla){
1191 if($dn != $destinationdn){
1192 $ldap->cd($basedn);
1193 $item = $ldap->fetch($ldap->cat($dn));
1194 if(!in_array("FAIbranch",$item['objectClass'])){
1195 FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1196 }
1197 }
1198 }
1199 if($is_first){
1200 echo "<p class='seperator'> </p>";
1201 }
1202 }
1206 /* This function returns the dn of the object release */
1207 static function get_release_dn($Current_DN)
1208 {
1209 global $config;
1210 $ldap = $config->get_ldap_link();
1211 $ldap->cd($config->current['BASE']);
1213 /* Split dn into pices */
1214 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$Current_DN));
1216 if(!is_array($dns_to_check)){
1217 return;
1218 }
1220 /* Use dn pieces, to create sub dns like
1221 ou=test,ou=1,ou=0...
1222 ou=1,ou=0...
1223 ou=0...
1224 To check which dn is our release container.
1225 */
1226 unset($dns_to_check['count']);
1227 while(count($dns_to_check)){
1229 /* Create dn */
1230 $new_dn = "";
1231 foreach($dns_to_check as $part){
1232 $new_dn .= $part.",";
1233 }
1234 $new_dn .= $config->current['BASE'];
1236 /* Check if this dn is a release dn */
1237 if(FAI::is_release_department($new_dn)){
1238 return($new_dn);
1239 }
1241 /* Remove first element of dn pieces */
1242 reset($dns_to_check);
1243 unset($dns_to_check[key($dns_to_check)]);
1244 }
1245 return("");
1246 }
1249 static function tag_attrs(&$at, $dn= "", $tag= "", $show= false)
1250 {
1251 /* Remove tags that may already be here... */
1252 remove_objectClass("gosaAdministrativeUnitTag", $at);
1253 if (isset($at['gosaUnitTag'])){
1254 unset($at['gosaUnitTag']);
1255 }
1257 /* Set tag? */
1258 if ($tag != ""){
1259 add_objectClass("gosaAdministrativeUnitTag", $at);
1260 $at['gosaUnitTag']= $tag;
1261 }
1263 /* Initially this object was tagged.
1264 - But now, it is no longer inside a tagged department.
1265 So force the remove of the tag.
1266 (objectClass was already removed obove)
1267 */
1268 if($tag == ""){
1269 $at['gosaUnitTag'] = array();
1270 }
1271 }
1274 }
1279 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1280 ?>