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 /* check which objects must be saved */
300 $FAI_objects_to_save = session::get('FAI_objects_to_save');
301 if(!is_array($FAI_objects_to_save)) {
302 print_a(array(session::get('FAI_objects_to_save')));
303 trigger_error("Can't save FAI objects, no array given.");
304 return;
305 }
307 foreach($FAI_objects_to_save as $Current_DN => $object){
308 if($object['diff']){
309 $sub_name = $Current_DN;
310 while(isset($FAI_objects_to_save[$sub_name])){
311 $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name];
312 unset($FAI_objects_to_save[$sub_name]);
313 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
314 }
315 }
316 }
317 session::set('FAI_objects_to_save',$FAI_objects_to_save);
319 /* Sort list of objects that must be saved, and ensure that
320 container objects are safed, before their childs are saved */
321 ksort($to_save);
322 $tmp = array();
323 foreach($to_save as $SubObjects){
324 foreach($SubObjects as $object){
325 $tmp[] = $object;
326 }
327 }
328 $to_save = $tmp;
331 /* Save objects and manage the correct release behavior*/
332 foreach($to_save as $save){
334 $Current_DN = $save['Current_DN'];
335 $removed = $save['removed'];
336 $objectAttrs= $save['objectAttrs'];
338 /* Get ldap object */
339 $ldap = $config->get_ldap_link();
340 $ldap->cd($config->current['BASE']);
342 /* Get some basic informations */
343 $base_release = FAI::get_release_dn($Current_DN);
344 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release,true);
345 $parent_obj = FAI::get_parent_release_object($Current_DN);
346 $following_releases = FAI:: get_sub_releases_of_this_release($base_release,true);
348 /* Check if given dn exists or if is a new entry */
349 $ldap->cat($Current_DN);
350 if(!$ldap->count()){
351 $is_new = true;
352 }else{
353 $is_new = false;
354 }
356 /* if parameter removed is true, we have to add FAIstate to the current attrs
357 FAIstate should end with ...|removed after this operation */
358 if($removed ){
359 $ldap->cat($Current_DN);
361 /* Get current object, because we must add the FAIstate ...|removed */
362 if((!$ldap->count()) && !empty($parent_obj)){
363 $ldap->cat($parent_obj);
364 }
366 /* Check if we have found a suiteable object */
367 if(!$ldap->count()){
368 echo "Error can't remove this object ".$Current_DN;
369 return;
370 }else{
372 /* Set FAIstate to current objectAttrs */
373 $objectAttrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
374 if(isset($objectAttrs['FAIstate'][0])){
375 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
376 $objectAttrs['FAIstate'][0] .= "|removed";
377 }
378 }else{
379 $objectAttrs['FAIstate'][0] = "|removed";
380 }
381 }
382 }
384 /* Check if this a leaf release or not */
385 if(count($following_releases) == 0 ){
387 /* This is a leaf object. It isn't inherited by any other object */
388 if(DEBUG_FAI_FUNC) {
389 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
390 print_a($objectAttrs);
391 }
392 FAI::save_FAI_object($Current_DN,$objectAttrs);
393 }else{
395 /* This object is inherited by some sub releases */
397 /* Get all releases, that inherit this object */
398 $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
400 /* Get parent object */
401 $ldap->cat($parent_obj);
402 $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
404 /* New objects require special handling */
405 if($is_new){
407 /* check if there is already an entry named like this,
408 in one of our parent releases */
409 if(!empty($parent_obj)){
410 if(DEBUG_FAI_FUNC) {
411 echo "There is already an entry named like this.</b><br>";
413 echo "<b>Saving main object</b>".$Current_DN;
414 print_a($objectAttrs);
415 }
416 FAI::save_FAI_object($Current_DN,$objectAttrs);
418 foreach($r as $key){
419 if(DEBUG_FAI_FUNC) {
420 echo "<b>Saving parent to following release</b> ".$key;
421 print_a($parent_attrs);
422 }
423 FAI::save_FAI_object($key,$parent_attrs);
424 }
425 }else{
427 if(DEBUG_FAI_FUNC) {
428 echo "<b>Saving main object</b>".$Current_DN;
429 print_a($objectAttrs);
430 }
431 FAI::save_FAI_object($Current_DN,$objectAttrs);
433 if(isset($objectAttrs['FAIstate'])){
434 $objectAttrs['FAIstate'] .= "|removed";
435 }else{
436 $objectAttrs['FAIstate'] = "|removed";
437 }
439 foreach($r as $key ){
440 if(DEBUG_FAI_FUNC) {
441 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
442 print_a($objectAttrs);
443 }
444 FAI::save_FAI_object($key,$objectAttrs);
445 }
446 }
447 }else{
449 /* check if we must patch the follwing release */
450 if(!empty($r)){
451 foreach($r as $key ){
452 if(DEBUG_FAI_FUNC) {
453 echo "<b>Copy current objects original attributes to next release</b> ".$key;
454 print_a($parent_attrs);
455 }
456 FAI::save_FAI_object($key,$parent_attrs);
457 }
458 }
460 if(DEBUG_FAI_FUNC) {
461 echo "<b>Saving current object</b>".$parent_obj;
462 print_a($objectAttrs);
463 }
464 FAI::save_FAI_object($parent_obj,$objectAttrs);
466 if(($parent_obj != $Current_DN)){
467 msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
468 }
469 }
470 }
471 }
473 /* Reload GOsa si FAI DB/cache
474 */
475 if(count($to_save)){
476 if(class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
477 $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);
478 if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
479 $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'];
480 $tmp = new $evt['CLASS_NAME']($config);
481 $tmp->set_type(TRIGGERED_EVENT);
482 $tmp->add_targets(array("GOsa"));
483 $o_queue = new gosaSupportDaemon();
484 if(!$o_queue->append($tmp)){
485 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
486 }
487 }
488 }
489 }
491 session::set('FAI_objects_to_save',array());
492 }
495 /* this function will remove all unused (deleted) objects,
496 that have no parent object */
497 static function clean_up_releases($Current_DN)
498 {
499 global $config;
500 $ldap = $config->get_ldap_link();
501 $ldap->cd($config->current['BASE']);
503 /* Collect some basic informations and initialize some variables */
504 $base_release = FAI::get_release_dn($Current_DN);
505 $previous_releases = array_reverse(FAI:: get_previous_releases_of_this_release($base_release,true));
506 $Kill = array();
507 $Skip = array();
509 /* We must also include the given release dn */
510 $previous_releases[] = $base_release;
512 /* Walk through all releases */
513 foreach($previous_releases as $release){
515 /* Get fai departments */
516 $deps_to_search = FAI::get_FAI_departments($release);
518 /* For every single department (ou=hoos,ou ..) */
519 foreach($deps_to_search as $fai_base){
521 /* Ldap search for fai classes specified in this release */
522 $ldap->cd($fai_base);
523 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
525 /* check the returned objects, and add/replace them in our return variable */
526 while($attr = $ldap->fetch()){
528 $buffer = array();
529 # $name = str_ireplace($release,"",$attr['dn']);
530 $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
532 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
534 /* Check if this object is required somehow */
535 if(!isset($Skip[$name])){
536 $Kill[$attr['dn']] = $attr['dn'];
537 }
538 }else{
540 /* This object is required (not removed), so do not
541 delete any following sub releases of this object */
542 $Skip[$name] = $attr['dn'];
543 }
544 }
545 }
546 }
547 return($Kill);
548 }
551 /* Remove numeric index and 'count' from ldap->fetch result */
552 static function prepare_ldap_fetch_to_be_saved($attrs)
553 {
554 foreach($attrs as $key => $value){
555 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
556 unset($attrs[$key]);
557 }
558 if(is_array($value) && isset($value['count'])){
559 unset($attrs[$key]['count']);
560 }
561 }
562 return($attrs);
563 }
566 /* Save given attrs to specified dn*/
567 static function save_FAI_object($dn,$attrs)
568 {
569 global $config;
570 $ldap = $config->get_ldap_link();
571 $ldap->cd($config->current['BASE']);
572 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
573 $ldap->cd($dn);
575 $ldap->cat($dn,array("dn"));
576 if($ldap->count()){
578 /* Remove FAIstate*/
579 if(!isset($attrs['FAIstate'])){
580 $attrs['FAIstate'] = array();
581 }
583 $ldap->modify($attrs);
584 }else{
586 /* Unset description if empty */
587 if(empty($attrs['description'])){
588 unset($attrs['description']);
589 }
591 $ldap->add($attrs);
592 }
593 if (!$ldap->success()){
594 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
595 }
596 }
599 /* Return FAIstate freeze branch or "" for specified release department */
600 static function get_release_tag($dn)
601 {
602 global $config;
603 $ldap = $config->get_ldap_link();
604 $ldap->cd($dn);
605 $ldap->cat($dn,array("FAIstate"));
607 if($ldap->count()){
609 $attr = $ldap->fetch();
610 if(isset($attr['FAIstate'][0])){
611 if(preg_match("/freeze/",$attr['FAIstate'][0])){
612 return("freeze");
613 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
614 return("branch");
615 }
616 }
617 }
618 return("");
619 }
622 static function get_following_releases_that_inherit_this_object($dn)
623 {
624 global $config;
625 $ldap = $config->get_ldap_link();
626 $ldap->cd($config->current['BASE']);
628 $ret = array();
630 /* Get base release */
631 $base_release = FAI::get_release_dn($dn);
633 /* Get previous release dns */
634 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release);
636 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
637 # $dn_suffix = str_ireplace($base_release,"",$dn);
638 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
640 /* Check if given object also exists whitin one of these releases */
641 foreach($sub_releases as $p_release => $name){
643 $check_dn = $dn_suffix.$p_release;
645 $ldap->cat($check_dn,array("dn","objectClass"));
647 if($ldap->count()){
648 //return($ret);
649 }else{
650 $ret[$check_dn]=$check_dn;
651 }
652 }
653 return($ret);
654 }
657 /* Get previous version of the object dn */
658 static function get_parent_release_object($dn,$include_myself=true)
659 {
660 global $config;
661 $ldap = $config->get_ldap_link();
662 $ldap->cd($config->current['BASE']);
663 $previous_releases= array();
665 /* Get base release */
666 $base_release = FAI::get_release_dn($dn);
667 if($include_myself){
668 $previous_releases[] = $base_release;
669 }
671 /* Get previous release dns */
672 $tmp = FAI:: get_previous_releases_of_this_release($base_release,true);
673 foreach($tmp as $release){
674 $previous_releases[] = $release;
675 }
677 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
678 # $dn_suffix = str_ireplace($base_release,"",$dn);
679 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
681 /* Check if given object also exists whitin one of these releases */
682 foreach($previous_releases as $p_release){
683 $check_dn = $dn_suffix.$p_release;
684 $ldap->cat($check_dn,array("dn","objectClass"));
686 if($ldap->count()){
687 return($check_dn);
688 }
689 }
690 return("");
691 }
694 /* return release names of all parent releases */
695 static function get_previous_releases_of_this_release($dn,$flat)
696 {
697 global $config;
698 $ldap = $config->get_ldap_link();
699 $ldap->cd($config->current['BASE']);
700 $ret = array();
702 /* Explode dns into pieces, to be able to build parent dns */
703 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
705 if(!is_array($dns_to_check)){
706 return;
707 }
709 /* Unset first entry which represents the given dn */
710 unset($dns_to_check['count']);
711 unset($dns_to_check[key($dns_to_check)]);
713 /* Create dns addresses and check if this dn is a release dn */
714 $id = 0;
715 while(count($dns_to_check)){
717 /* build parent dn */
718 $new_dn = "";
719 foreach($dns_to_check as $part){
720 $new_dn .= $part.",";
721 }
722 $new_dn .= $config->current['BASE'];
724 /* check if this dn is a release */
725 if(FAI::is_release_department($new_dn)){
726 if($flat){
727 $ret[$id] = $new_dn;
728 }else{
729 $ret = array($new_dn=>$ret);
730 }
731 $id ++;
732 }else{
733 return($ret);
734 }
735 reset($dns_to_check);
736 unset($dns_to_check[key($dns_to_check)]);
737 }
738 return($ret);
739 }
742 /* This function returns all sub release names, recursivly */
743 static function get_sub_releases_of_this_release($dn,$flat = false)
744 {
745 global $config;
746 $res = array();
747 $ldap = $config->get_ldap_link();
748 $ldap->cd($config->current['BASE']);
749 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
750 while($attr = $ldap->fetch()){
752 /* Append department name */
753 if($flat){
754 $res[$attr['dn']] = $attr['ou'][0];
755 }else{
756 $res[$attr['dn']] = array();
757 }
759 /* Get sub release departments of this department */
760 if(in_array("FAIbranch",$attr['objectClass'])) {
761 if($flat){
762 $tmp = FAI:: get_sub_releases_of_this_release($attr['dn'],$flat);
763 foreach($tmp as $dn => $value){
764 $res[$dn]=$value;
765 }
766 }else{
767 $res[$attr['dn']] = FAI:: get_sub_releases_of_this_release($attr['dn']);
768 }
769 }
770 }
771 return($res);
772 }
775 /* Check if the given department is a release department */
776 static function is_release_department($dn)
777 {
778 global $config;
779 $ldap = $config->get_ldap_link();
780 $ldap->cd($config->current['BASE']);
781 $ldap->cat($dn,array("objectClass","ou"));
783 /* Check objectClasses and name to check if this is a release department */
784 if($ldap->count()){
785 $attrs = $ldap->fetch();
787 $ou = "";
788 if(isset($attrs['ou'][0])){
789 $ou = $attrs['ou'][0];
790 }
792 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
793 return($attrs['dn']);
794 }
795 }
796 return(false);
797 }
800 static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
801 {
802 global $config;
803 $start = microtime(TRUE);
804 $source_release = trim($source_release,"/");
806 echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
808 $sub_releases = array();
809 $source_dn = "";
811 $tmp = split("\/",$source_release);
812 foreach($tmp as $part){
813 if(empty($part)){
814 continue;
815 }
816 $source_dn = "ou=".$part.",".$source_dn;
817 $sub_releases[$part] = $source_dn;
818 }
820 /* Get all groups */
821 $ldap =$config->get_ldap_link();
822 $ldap->cd($config->current['BASE']);
823 $ldap->search("(objectClass=posixGroup)",array("dn"));
824 $groups = array();
825 while($attrs = $ldap->fetch()){
826 $groups[$attrs['dn']] = $attrs;
827 }
829 /* Get all FAI releases, to be able to create missing group application releases
830 with the correct type of release (FAIstate=freeze/branch).
831 */
832 $f_releases = array();
833 $ldap->cd ($config->current['BASE']);
834 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
835 while($attrs = $ldap->fetch()){
836 foreach($sub_releases as $sub_rel){
837 if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
838 $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
839 }
840 }
841 }
843 /* Get all group releases */
844 $g_releases = array();
845 foreach($groups as $dn => $data){
846 $ldap->cd($dn);
847 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
848 while($attrs = $ldap->fetch()){
849 $g_releases[$attrs['dn']] = $attrs;
850 }
851 }
853 /* Check if base releases exists.
854 If they do not exist, create them and adapt FAIstate attribute from FAI releases.
855 */
856 foreach($sub_releases as $name => $sub_rel){
858 $FAIstate = "";
859 if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
860 $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
861 }
863 foreach($groups as $dn => $data){
864 if(!isset($g_releases[$sub_rel.$dn])){
865 $ldap->cd($dn);
866 $r_data = array();
867 $r_data['ou'] = $name;
868 $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
869 if(!empty($FAIstate)) {
870 $r_data['FAIstate'] = $FAIstate;
871 }
873 $ldap->cd($sub_rel.$dn) ;
874 $ldap->add($r_data);
875 echo " <b>"._("Object").":</b> ";
876 echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
877 flush();
878 }
879 }
880 }
882 /* Create new release container in each group.
883 */
884 $n_data = array();
885 $n_data = array();
886 $n_data['ou'] = $destination_name;
887 $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
888 if(!empty($type)){
889 $n_data['FAIstate'] = $type."/cow";
890 }
892 foreach($groups as $dn => $att){
893 $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
894 if(!isset($g_releases[$n_dn])){
895 $ldap->cd ($n_dn);
896 $ldap->add($n_data);
897 echo " <b>"._("Object").":</b> ";
898 echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
899 flush();
900 }
901 }
903 /* If the source release is empty, then create a new release by copying
904 all group application menus into a new ou=$destination_name release container.
906 If the source release is not empty.
907 We detect all releases which match the source release dn and copy the contents.
908 */
909 if(empty($source_release)){
910 $source_dns = $groups;
911 }else{
912 $source_dns = array();
913 foreach($g_releases as $dn => $data){
914 if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
915 $source_dns[$dn] = $data;
916 }
917 }
918 }
920 /* Detect all menu object we have to copy
921 */
922 $to_copy = array();
923 foreach($source_dns as $dn => $attrs){
924 $ldap->cd($dn);
925 $ldap->ls("(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry)",$dn,array("dn"));
926 while($attrs = $ldap->fetch()){
927 $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
928 $to_copy[$attrs['dn']] = $destination;
929 }
930 }
932 /* At least create the menu objects object */
933 $plug = new plugin($config);
934 foreach($to_copy as $source => $destination){
935 $ldap->cat($destination);
936 if($ldap->count()){
937 echo " <b>"._("Object").":</b> ";
938 echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
939 flush();
940 }else{
941 $plug->copy($source,$destination);
942 echo " <b>"._("Object").":</b> ";
943 echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
944 flush();
945 }
946 }
947 }
950 /*! \brief Create a new FAI branch.
951 * @param $sourcedn String The source release dn
952 * @param $destinationdn String The destination dn
953 * @param $destinationName String The name of the new release
954 * @param $type String The release type (freeze/branch)
955 * @param $is_first Boolean Use to identify the first func. call when recursivly called.
956 * @param $depth Integer Current depth of recursion.
957 */
958 function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
959 {
960 global $config;
961 error_reporting(E_ALL | E_STRICT);
962 $ldap = $config->get_ldap_link();
963 $basedn = $config->current['BASE'];
964 $delarray = array();
966 /* The following code will output a status string
967 * for each handled object, in a seperate iframe.
968 */
971 /* Display current action information.
972 */
973 if($is_first){
974 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
975 }else{
976 if(preg_match("/^ou=/",$sourcedn)){
977 echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
978 }else{
979 $tmp = split(",",$sourcedn);
980 echo " <b>"._("Object").":</b> ";
981 $deststr = LDAP::fix($destinationdn);
982 if(strlen($deststr) > 96){
983 $deststr = substr($deststr,0,96)."...";
984 }
985 echo $deststr."<br>";
986 }
987 }
988 /* .. immediately display infos */
989 flush();
991 /* Check if destination entry already exists
992 */
993 $ldap->cat($destinationdn);
994 if($ldap->count()){
995 echo _("Could not create new release, the destination dn is already in use.");
996 return;
997 }else{
999 $ldap->clearResult();
1001 /* Get source entry
1002 * if it does not exist, abort here.
1003 */
1004 $ldap->cd($basedn);
1005 $ldap->cat($sourcedn);
1006 $attr = $ldap->fetch();
1007 if((!$attr) || (count($attr)) ==0) {
1008 echo _("Error while fetching source dn - aborted!");
1009 return;
1010 }
1012 /* The current object we want to create is an department.
1013 * Create the department and add the FAIbranch tag.
1014 */
1015 if(in_array("organizationalUnit",$attr['objectClass'])){
1016 $attr['dn'] = LDAP::convert($destinationdn);
1017 $ldap->cd($basedn);
1018 $ldap->create_missing_trees($destinationdn);
1019 $ldap->cd($destinationdn);
1021 /* If is first entry, append FAIbranch to department entry */
1022 if($is_first){
1023 $ldap->cat($destinationdn);
1024 $attr= $ldap->fetch();
1025 /* Filter unneeded informations */
1026 foreach($attr as $key => $value){
1027 if(is_numeric($key)) unset($attr[$key]);
1028 if(isset($attr[$key]['count'])){
1029 if(is_array($attr[$key])){
1030 unset($attr[$key]['count']);
1031 }
1032 }
1033 }
1035 unset($attr['count']);
1036 unset($attr['dn']);
1038 /* Add marking attribute */
1039 $attr['objectClass'][] = "FAIbranch";
1041 /* Add this entry */
1042 $ldap->modify($attr);
1043 }
1044 }else{
1046 /* Replicate all relevant FAI objects here.
1047 * FAI objects, Apps and Mimetypes.
1048 * Get all attributes as binary value, to ensure that Icon, File template aso
1049 * are created correctly.
1050 */
1051 foreach($attr as $key => $value){
1053 if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1054 $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1055 $ei= ldap_first_entry($ldap->cid, $sr);
1056 if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1057 $attr[$key] = $tmp;
1058 }
1059 }
1061 if(is_numeric($key)) unset($attr[$key]);
1062 if(isset($attr[$key]['count'])){
1063 if(is_array($attr[$key])){
1064 unset($attr[$key]['count']);
1065 }
1066 }
1067 }
1068 unset($attr['count']);
1069 unset($attr['dn']);
1071 /* Add entry
1072 */
1073 $ldap->cd($destinationdn);
1074 $ldap->cat($destinationdn);
1076 $a = $ldap->fetch();
1077 if(!count($a)){
1078 $ldap->add($attr);
1079 }
1081 if(!$ldap->success()){
1083 /* Some error occurred */
1084 print "---------------------------------------------";
1085 print $ldap->get_error()."<br>";
1086 print $sourcedn."<br>";
1087 print $destinationdn."<br>";
1088 print_a( $attr);
1089 exit();
1090 }
1091 }
1092 }
1094 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1096 /* Prepare for recursive copy.
1097 * Get all object within the source dn and
1098 * call the recursive copy for each.
1099 */
1100 $ldap->ls ("(objectClass=*)",$sourcedn);
1101 while ($ldap->fetch()){
1102 $deldn= $ldap->getDN();
1103 $delarray[$deldn]= strlen($deldn);
1104 }
1105 asort ($delarray);
1106 reset ($delarray);
1107 $depth ++;
1108 foreach($delarray as $dn => $bla){
1109 if($dn != $destinationdn){
1110 $ldap->cd($basedn);
1111 $item = $ldap->fetch($ldap->cat($dn));
1112 if(!in_array("FAIbranch",$item['objectClass'])){
1113 FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1114 }
1115 }
1116 }
1117 if($is_first){
1118 echo "<p class='seperator'> </p>";
1119 }
1120 }
1124 /* This function returns the dn of the object release */
1125 static function get_release_dn($Current_DN)
1126 {
1127 global $config;
1128 $ldap = $config->get_ldap_link();
1129 $ldap->cd($config->current['BASE']);
1131 /* Split dn into pices */
1132 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1134 if(!is_array($dns_to_check)){
1135 return;
1136 }
1138 /* Use dn pieces, to create sub dns like
1139 ou=test,ou=1,ou=0...
1140 ou=1,ou=0...
1141 ou=0...
1142 To check which dn is our release container.
1143 */
1144 unset($dns_to_check['count']);
1145 while(count($dns_to_check)){
1147 /* Create dn */
1148 $new_dn = "";
1149 foreach($dns_to_check as $part){
1150 $new_dn .= $part.",";
1151 }
1152 $new_dn .= $config->current['BASE'];
1154 /* Check if this dn is a release dn */
1155 if(FAI::is_release_department($new_dn)){
1156 return($new_dn);
1157 }
1159 /* Remove first element of dn pieces */
1160 reset($dns_to_check);
1161 unset($dns_to_check[key($dns_to_check)]);
1162 }
1163 return("");
1164 }
1165 }
1170 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1171 ?>