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 $ldap->cat($base_release);
32 $attrs = $ldap->fetch();
33 $FAIstate = "branch";
34 if(isset($attrs['FAIstate'][0])){
35 $FAIstate = $attrs['FAIstate'][0];
36 }
38 /* We must also include the given release dn */
39 $previous_releases[] = $base_release;
41 /* Walk through all releases */
42 foreach($previous_releases as $release){
44 /* Get fai departments */
45 $deps_to_search = FAI::get_FAI_departments($release);
47 /* For every single department (ou=hoos,ou ..) */
48 foreach($deps_to_search as $fai_base){
50 /* Ldap search for fai classes specified in this release */
51 $attributes = array("dn","objectClass","FAIstate","cn");
52 $res_tmp = get_list($filter,"fai",$fai_base,$attributes,GL_SUBSEARCH | GL_SIZELIMIT);
54 /* check the returned objects, and add/replace them in our return variable */
55 foreach($res_tmp as $attr){
57 $buffer = array();
58 $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
60 if(isset($attr['FAIstate'][0])){
61 if(preg_match("/removed$/",$attr['FAIstate'][0])){
62 if(isset($res[$name])){
63 unset($res[$name]);
64 }
65 continue;
66 }
67 }
69 /* Seems to be an inherited class, apply current FAIstate to this classes
70 */
71 if(!preg_match("/".normalizePreg($base_release)."$/i",$attr['dn'])){
72 $buffer['FAIstate'] = $FAIstate;
73 }else{
75 /* Seems to be created within this release department.
76 This indicates - it can't be of state "freeze"
77 */
78 $buffer['FAIstate'] = "branch";
79 }
81 /* In detailed mode are some additonal informations visible */
82 if($detailed){
84 /* Create list of parents */
85 if(isset($res[$name])){
86 $buffer = $res[$name];
87 $buffer['parents'][] = $res[$name]['dn'];
88 }else{
89 $buffer['parents'] = array();
90 }
92 /* Append objectClass to resulsts */
93 foreach($attributes as $val){
94 if(isset($attr[$val])){
95 $buffer[$val] = $attr[$val];
96 }
97 }
98 unset($buffer['objectClass']['count']);
99 }
101 /* Add this object to our list */
102 $buffer['dn'] = $attr['dn'];
103 $res[$name] = $buffer;
104 }
105 }
106 }
107 return($res);
108 }
111 /* Return all relevant FAI departments */
112 static function get_FAI_departments($suffix = "")
113 {
114 $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
115 $tmp = array();
116 if(preg_match("/^,/",$suffix)){
117 $suffix = preg_replace("/^,/","",$suffix);
118 }
119 foreach($arr as $name){
120 if(empty($suffix)){
121 $tmp[$name] = "ou=".$name;
122 }else{
123 $tmp[$name] = "ou=".$name.",".$suffix;
124 }
125 }
126 return($tmp);
127 }
130 /* Return all releases within the given base */
131 static function get_all_releases_from_base($dn,$appendedName=false)
132 {
133 global $config;
135 if(!preg_match("/".normalizePreg(get_ou('faiou'))."/",$dn)){
136 $base = get_ou('faiou').$dn;
137 }else{
138 $base = $dn;
139 }
140 $res = array();
142 $ldap = $config->get_ldap_link();
143 $ldap->cd($base);
144 $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
145 while($attrs = $ldap->fetch()){
146 if($appendedName){
147 $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".normalizePreg(get_ou('faiou')).".*$/","",$attrs['dn']));
148 }else{
149 $res[$attrs['dn']] = $attrs['ou'][0];
150 }
151 }
152 return($res);
153 }
156 /* Add this object to list of objects, that must be checked for release saving */
157 static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
158 {
159 /* Get ldap object */
160 global $config;
161 $addObj['Current_DN'] = $Current_DN;
162 $addObj['objectAttrs']= $objectAttrs;
163 $addObj['removed'] = $removed;
164 $addObj['diff'] = TRUE;
166 if(!$removed){
167 $ldap = $config->get_ldap_link();
168 $ldap->cd($config->current['BASE']);
170 /* Get some basic informations */
171 $parent_obj = FAI::get_parent_release_object($Current_DN);
172 if(!empty($parent_obj)){
173 $ldap->cat($parent_obj,array("*"));
174 $attrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
176 if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
177 $addObj['diff'] = FALSE;
178 }
179 }
180 }else{
182 /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
183 we have to remove this name from all profiles in this release.
184 */
185 $ldap = $config->get_ldap_link();
186 $ldap->cd($config->current['BASE']);
187 $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
189 /* Dont't try to modify non FAIclasses
190 */
191 if(!preg_match("/[^,]+,".normalizePreg(get_ou("faiou"))."/",$obj_dn)){
192 trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);
193 echo "<br>-->".$Current_DN."<br>";
194 echo "<br>-->".$obj_dn."<br>";
195 }else{
197 /* Get source object and check if it is a base FAIclass
198 */
199 $ldap->cat($obj_dn);
200 $attrs = $ldap->fetch();
201 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
202 if(count(array_intersect($classes,$attrs['objectClass']))){
203 $cn = $attrs['cn'][0];
205 /* Check if this is the last with this name in the current release.
206 In this case we have to remove the package name
207 from all profiles in this release.
208 */
209 $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
210 "(&(objectClass=FAIclass)(cn=".$cn."))");
212 /* Check if this is the last class with this name.
213 */
214 if(count($classes) == 1){
216 /* Get all FAI Profiles
217 */
218 $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
219 "(&(objectClass=FAIprofile)(FAIclass=*))");
221 /* Walk though all profiles and remove the source class name
222 */
223 foreach($profiles as $dn){
224 $ldap->cat($dn['dn']);
225 $attrs = $ldap->fetch();
227 $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
229 /* Check if this Profile uses the source class ($cn)
230 */
231 if(preg_match("/".normalizePreg($cn)."/",$attrs['FAIclass'])){
232 $attrs['FAIclass'] = preg_replace("/[ ]*".normalizePreg($cn)."[ ]*/i"," ",$attrs['FAIclass']);
233 if(empty($attrs['FAIclass'])){
234 $attrs['FAIclass'] = array();
235 }
236 $ldap->cd($dn['dn']);
237 $ldap->modify($attrs);
239 if (!$ldap->success()){
240 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
241 }
242 }
243 }
244 }
245 }
246 }
247 }
251 $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
252 $FAI_objects_to_save[$Current_DN] = $addObj;
253 session::set('FAI_objects_to_save',$FAI_objects_to_save);
254 }
257 /* Detect differences in attribute arrays */
258 static function array_diff_FAI($ar1,$ar2)
259 {
261 if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
262 $ar1['description'] = "";
263 }
264 if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
265 $ar2['description'] = "";
266 }
268 if(count($ar1) != count($ar2)) {
269 return (true);
270 }
272 foreach($ar1 as $key1 => $val1){
274 if((is_array($val1)) && (count($val1)==1)){
275 $ar1[$key1] = $val1[0];
276 }
278 if(isset($ar2[$key1])&& (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
279 $val1 = $val1[0];
280 $ar2[$key1] = $ar2[$key1][0];
281 }
282 }
283 ksort($ar1);
284 ksort($ar2);
285 if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
286 return(true);
287 }else{
288 return(false);
289 }
290 }
293 static function arr_diff($ar1,$ar2)
294 {
295 foreach($ar1 as $ak1 => $av1){
296 if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
297 return(TRUE);
298 }elseif(is_array($av1)){
299 $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
300 if($ret) {
301 return(TRUE);
302 }
303 }
304 }
305 return(FALSE);
306 }
311 /* check which objects must be saved, and save them */
312 static function save_release_changes_now()
313 {
314 global $config;
315 /* Variable init*/
316 $to_save = array();
318 $reload_fai_classes = FALSE;
320 /* check which objects must be saved */
321 if(!session::is_set('FAI_objects_to_save')){
322 return;
323 }
324 $FAI_objects_to_save = session::get('FAI_objects_to_save');
325 if(!is_array($FAI_objects_to_save)) {
326 print_a(array(session::get('FAI_objects_to_save')));
327 trigger_error("Can't save FAI objects, no array given.");
328 return;
329 }
331 foreach($FAI_objects_to_save as $Current_DN => $object){
332 if($object['diff']){
333 $sub_name = $Current_DN;
334 while(isset($FAI_objects_to_save[$sub_name])){
335 $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name];
336 unset($FAI_objects_to_save[$sub_name]);
337 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
338 }
339 }
340 }
341 session::set('FAI_objects_to_save',$FAI_objects_to_save);
343 /* Sort list of objects that must be saved, and ensure that
344 container objects are safed, before their childs are saved */
345 ksort($to_save);
346 $tmp = array();
347 foreach($to_save as $SubObjects){
348 foreach($SubObjects as $object){
349 $tmp[] = $object;
350 }
351 }
352 $to_save = $tmp;
355 /* Save objects and manage the correct release behavior*/
356 foreach($to_save as $save){
358 $Current_DN = $save['Current_DN'];
359 $removed = $save['removed'];
360 $objectAttrs= $save['objectAttrs'];
362 /* Get ldap object */
363 $ldap = $config->get_ldap_link();
364 $ldap->cd($config->current['BASE']);
366 /* Get some basic informations */
367 $base_release = FAI::get_release_dn($Current_DN);
368 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release,true);
369 $parent_obj = FAI::get_parent_release_object($Current_DN);
370 $following_releases = FAI:: get_sub_releases_of_this_release($base_release,true);
372 /* Check if given dn exists or if is a new entry */
373 $ldap->cat($Current_DN);
374 if(!$ldap->count()){
375 $is_new = true;
376 }else{
377 $is_new = false;
378 }
380 /* if parameter removed is true, we have to add FAIstate to the current attrs
381 FAIstate should end with ...|removed after this operation */
382 if($removed ){
383 $ldap->cat($Current_DN);
385 /* Get current object, because we must add the FAIstate ...|removed */
386 if((!$ldap->count()) && !empty($parent_obj)){
387 $ldap->cat($parent_obj);
388 }
390 /* Check if we have found a suiteable object */
391 if(!$ldap->count()){
392 echo "Error can't remove this object ".$Current_DN;
393 return;
394 }else{
396 /* Set FAIstate to current objectAttrs */
397 $objectAttrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
398 if(isset($objectAttrs['FAIstate'][0])){
399 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
400 $objectAttrs['FAIstate'][0] .= "|removed";
401 }
402 }else{
403 $objectAttrs['FAIstate'][0] = "|removed";
404 }
406 /* Force reload of FAI classes */
407 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
408 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
409 $reload_fai_classes = TRUE;
410 }
411 }
412 }
414 /* Check if this a leaf release or not */
415 if(count($following_releases) == 0 ){
417 /* This is a leaf object. It isn't inherited by any other object */
418 if(DEBUG_FAI_FUNC) {
419 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
420 print_a($objectAttrs);
421 }
422 FAI::save_FAI_object($Current_DN,$objectAttrs);
424 /* Force reload of FAI classes */
425 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
426 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
427 $reload_fai_classes = TRUE;
428 }
430 }else{
432 /* This object is inherited by some sub releases */
434 /* Get all releases, that inherit this object */
435 $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
437 /* Get parent object */
438 $ldap->cat($parent_obj);
439 $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
441 /* New objects require special handling */
442 if($is_new){
444 /* Force reload of FAI classes */
445 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
446 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
447 $reload_fai_classes = TRUE;
448 }
450 /* check if there is already an entry named like this,
451 in one of our parent releases */
452 if(!empty($parent_obj)){
453 if(DEBUG_FAI_FUNC) {
454 echo "There is already an entry named like this.</b><br>";
456 echo "<b>Saving main object</b>".$Current_DN;
457 print_a($objectAttrs);
458 }
459 FAI::save_FAI_object($Current_DN,$objectAttrs);
461 foreach($r as $key){
462 if(DEBUG_FAI_FUNC) {
463 echo "<b>Saving parent to following release</b> ".$key;
464 print_a($parent_attrs);
465 }
466 FAI::save_FAI_object($key,$parent_attrs);
467 }
468 }else{
470 if(DEBUG_FAI_FUNC) {
471 echo "<b>Saving main object</b>".$Current_DN;
472 print_a($objectAttrs);
473 }
474 FAI::save_FAI_object($Current_DN,$objectAttrs);
476 if(isset($objectAttrs['FAIstate'])){
477 $objectAttrs['FAIstate'] .= "|removed";
478 }else{
479 $objectAttrs['FAIstate'] = "|removed";
480 }
482 foreach($r as $key ){
483 if(DEBUG_FAI_FUNC) {
484 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
485 print_a($objectAttrs);
486 }
487 FAI::save_FAI_object($key,$objectAttrs);
488 }
489 }
490 }else{
492 /* check if we must patch the follwing release */
493 if(!empty($r)){
494 foreach($r as $key ){
495 if(DEBUG_FAI_FUNC) {
496 echo "<b>Copy current objects original attributes to next release</b> ".$key;
497 print_a($parent_attrs);
498 }
499 FAI::save_FAI_object($key,$parent_attrs);
500 }
501 }
503 if(DEBUG_FAI_FUNC) {
504 echo "<b>Saving current object</b>".$parent_obj;
505 print_a($objectAttrs);
506 }
507 FAI::save_FAI_object($parent_obj,$objectAttrs);
509 if(($parent_obj != $Current_DN)){
510 msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
511 }
512 }
513 }
514 }
516 /* Reload GOsa si FAI DB/cache
517 */
518 if($reload_fai_classes){
519 if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
520 $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);
521 if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
522 $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'];
523 $tmp = new $evt['CLASS_NAME']($config);
524 $tmp->set_type(TRIGGERED_EVENT);
525 $tmp->add_targets(array("GOsa"));
526 $o_queue = new gosaSupportDaemon();
527 if(!$o_queue->append($tmp)){
528 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
529 }
530 }
531 }
532 }
534 session::set('FAI_objects_to_save',array());
535 }
538 /* this function will remove all unused (deleted) objects,
539 that have no parent object */
540 static function clean_up_releases($Current_DN)
541 {
542 global $config;
543 $ldap = $config->get_ldap_link();
544 $ldap->cd($config->current['BASE']);
546 /* Collect some basic informations and initialize some variables */
547 $base_release = FAI::get_release_dn($Current_DN);
548 $previous_releases = array_reverse(FAI:: get_previous_releases_of_this_release($base_release,true));
549 $Kill = array();
550 $Skip = array();
552 /* We must also include the given release dn */
553 $previous_releases[] = $base_release;
555 /* Walk through all releases */
556 foreach($previous_releases as $release){
558 /* Get fai departments */
559 $deps_to_search = FAI::get_FAI_departments($release);
561 /* For every single department (ou=hoos,ou ..) */
562 foreach($deps_to_search as $fai_base){
564 /* Ldap search for fai classes specified in this release */
565 $ldap->cd($fai_base);
566 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
568 /* check the returned objects, and add/replace them in our return variable */
569 while($attr = $ldap->fetch()){
571 $buffer = array();
572 # $name = str_ireplace($release,"",$attr['dn']);
573 $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
575 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
577 /* Check if this object is required somehow */
578 if(!isset($Skip[$name])){
579 $Kill[$attr['dn']] = $attr['dn'];
580 }
581 }else{
583 /* This object is required (not removed), so do not
584 delete any following sub releases of this object */
585 $Skip[$name] = $attr['dn'];
586 }
587 }
588 }
589 }
590 return($Kill);
591 }
594 /* Remove numeric index and 'count' from ldap->fetch result */
595 static function prepare_ldap_fetch_to_be_saved($attrs)
596 {
597 foreach($attrs as $key => $value){
598 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
599 unset($attrs[$key]);
600 }
601 if(is_array($value) && isset($value['count'])){
602 unset($attrs[$key]['count']);
603 }
604 }
605 return($attrs);
606 }
609 /* Save given attrs to specified dn*/
610 static function save_FAI_object($dn,$attrs)
611 {
612 global $config;
613 $ldap = $config->get_ldap_link();
614 $ldap->cd($config->current['BASE']);
615 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
616 $ldap->cd($dn);
618 $ldap->cat($dn,array("dn"));
619 if($ldap->count()){
621 /* Remove FAIstate*/
622 if(!isset($attrs['FAIstate'])){
623 $attrs['FAIstate'] = array();
624 }
626 $ldap->modify($attrs);
627 }else{
629 /* Unset description if empty */
630 if(empty($attrs['description'])){
631 unset($attrs['description']);
632 }
634 $ldap->add($attrs);
635 }
636 if (!$ldap->success()){
637 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
638 }
639 }
642 /* Return FAIstate freeze branch or "" for specified release department */
643 static function get_release_tag($dn)
644 {
645 global $config;
646 $ldap = $config->get_ldap_link();
647 $ldap->cd($dn);
648 $ldap->cat($dn,array("FAIstate"));
650 if($ldap->count()){
652 $attr = $ldap->fetch();
653 if(isset($attr['FAIstate'][0])){
654 if(preg_match("/freeze/",$attr['FAIstate'][0])){
655 return("freeze");
656 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
657 return("branch");
658 }
659 }
660 }
661 return("");
662 }
665 static function get_following_releases_that_inherit_this_object($dn)
666 {
667 global $config;
668 $ldap = $config->get_ldap_link();
669 $ldap->cd($config->current['BASE']);
671 $ret = array();
673 /* Get base release */
674 $base_release = FAI::get_release_dn($dn);
676 /* Get previous release dns */
677 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release);
679 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
680 # $dn_suffix = str_ireplace($base_release,"",$dn);
681 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
683 /* Check if given object also exists whitin one of these releases */
684 foreach($sub_releases as $p_release => $name){
686 $check_dn = $dn_suffix.$p_release;
688 $ldap->cat($check_dn,array("dn","objectClass"));
690 if($ldap->count()){
691 //return($ret);
692 }else{
693 $ret[$check_dn]=$check_dn;
694 }
695 }
696 return($ret);
697 }
700 /* Get previous version of the object dn */
701 static function get_parent_release_object($dn,$include_myself=true)
702 {
703 global $config;
704 $ldap = $config->get_ldap_link();
705 $ldap->cd($config->current['BASE']);
706 $previous_releases= array();
708 /* Get base release */
709 $base_release = FAI::get_release_dn($dn);
710 if($include_myself){
711 $previous_releases[] = $base_release;
712 }
714 /* Get previous release dns */
715 $tmp = FAI:: get_previous_releases_of_this_release($base_release,true);
716 foreach($tmp as $release){
717 $previous_releases[] = $release;
718 }
720 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
721 # $dn_suffix = str_ireplace($base_release,"",$dn);
722 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
724 /* Check if given object also exists whitin one of these releases */
725 foreach($previous_releases as $p_release){
726 $check_dn = $dn_suffix.$p_release;
727 $ldap->cat($check_dn,array("dn","objectClass"));
729 if($ldap->count()){
730 return($check_dn);
731 }
732 }
733 return("");
734 }
737 /* return release names of all parent releases */
738 static function get_previous_releases_of_this_release($dn,$flat)
739 {
740 global $config;
741 $ldap = $config->get_ldap_link();
742 $ldap->cd($config->current['BASE']);
743 $ret = array();
745 /* Explode dns into pieces, to be able to build parent dns */
746 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
748 if(!is_array($dns_to_check)){
749 return;
750 }
752 /* Unset first entry which represents the given dn */
753 unset($dns_to_check['count']);
754 unset($dns_to_check[key($dns_to_check)]);
756 /* Create dns addresses and check if this dn is a release dn */
757 $id = 0;
758 while(count($dns_to_check)){
760 /* build parent dn */
761 $new_dn = "";
762 foreach($dns_to_check as $part){
763 $new_dn .= $part.",";
764 }
765 $new_dn .= $config->current['BASE'];
767 /* check if this dn is a release */
768 if(FAI::is_release_department($new_dn)){
769 if($flat){
770 $ret[$id] = $new_dn;
771 }else{
772 $ret = array($new_dn=>$ret);
773 }
774 $id ++;
775 }else{
776 return($ret);
777 }
778 reset($dns_to_check);
779 unset($dns_to_check[key($dns_to_check)]);
780 }
781 return($ret);
782 }
785 /* This function returns all sub release names, recursivly */
786 static function get_sub_releases_of_this_release($dn,$flat = false)
787 {
788 global $config;
789 $res = array();
790 $ldap = $config->get_ldap_link();
791 $ldap->cd($config->current['BASE']);
792 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
793 while($attr = $ldap->fetch()){
795 /* Append department name */
796 if($flat){
797 $res[$attr['dn']] = $attr['ou'][0];
798 }else{
799 $res[$attr['dn']] = array();
800 }
802 /* Get sub release departments of this department */
803 if(in_array("FAIbranch",$attr['objectClass'])) {
804 if($flat){
805 $tmp = FAI:: get_sub_releases_of_this_release($attr['dn'],$flat);
806 foreach($tmp as $dn => $value){
807 $res[$dn]=$value;
808 }
809 }else{
810 $res[$attr['dn']] = FAI:: get_sub_releases_of_this_release($attr['dn']);
811 }
812 }
813 }
814 return($res);
815 }
818 /* Check if the given department is a release department */
819 static function is_release_department($dn)
820 {
821 global $config;
822 $ldap = $config->get_ldap_link();
823 $ldap->cd($config->current['BASE']);
824 $ldap->cat($dn,array("objectClass","ou"));
826 /* Check objectClasses and name to check if this is a release department */
827 if($ldap->count()){
828 $attrs = $ldap->fetch();
830 $ou = "";
831 if(isset($attrs['ou'][0])){
832 $ou = $attrs['ou'][0];
833 }
835 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
836 return($attrs['dn']);
837 }
838 }
839 return(false);
840 }
843 static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
844 {
845 global $config;
846 $start = microtime(TRUE);
847 $source_release = trim($source_release,"/");
849 echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
851 $sub_releases = array();
852 $source_dn = "";
854 $tmp = split("\/",$source_release);
855 foreach($tmp as $part){
856 if(empty($part)){
857 continue;
858 }
859 $source_dn = "ou=".$part.",".$source_dn;
860 $sub_releases[$part] = $source_dn;
861 }
863 /* Get all groups */
864 $ldap =$config->get_ldap_link();
865 $ldap->cd($config->current['BASE']);
866 $ldap->search("(objectClass=posixGroup)",array("dn"));
867 $groups = array();
868 while($attrs = $ldap->fetch()){
869 $groups[$attrs['dn']] = $attrs;
870 }
872 /* Get all FAI releases, to be able to create missing group application releases
873 with the correct type of release (FAIstate=freeze/branch).
874 */
875 $f_releases = array();
876 $ldap->cd ($config->current['BASE']);
877 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
878 while($attrs = $ldap->fetch()){
879 foreach($sub_releases as $sub_rel){
880 if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
881 $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
882 }
883 }
884 }
886 /* Get all group releases */
887 $g_releases = array();
888 foreach($groups as $dn => $data){
889 $ldap->cd($dn);
890 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
891 while($attrs = $ldap->fetch()){
892 $g_releases[$attrs['dn']] = $attrs;
893 }
894 }
896 /* Check if base releases exists.
897 If they do not exist, create them and adapt FAIstate attribute from FAI releases.
898 */
899 foreach($sub_releases as $name => $sub_rel){
901 $FAIstate = "";
902 if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
903 $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
904 }
906 foreach($groups as $dn => $data){
907 if(!isset($g_releases[$sub_rel.$dn])){
908 $ldap->cd($dn);
909 $r_data = array();
910 $r_data['ou'] = $name;
911 $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
912 if(!empty($FAIstate)) {
913 $r_data['FAIstate'] = $FAIstate;
914 }
916 $ldap->cd($sub_rel.$dn) ;
917 $ldap->add($r_data);
918 echo " <b>"._("Object").":</b> ";
919 echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
920 flush();
921 }
922 }
923 }
925 /* Create new release container in each group.
926 */
927 $n_data = array();
928 $n_data = array();
929 $n_data['ou'] = $destination_name;
930 $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
931 if(!empty($type)){
932 $n_data['FAIstate'] = $type."/cow";
933 }
935 foreach($groups as $dn => $att){
936 $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
937 if(!isset($g_releases[$n_dn])){
938 $ldap->cd ($n_dn);
939 $ldap->add($n_data);
940 echo " <b>"._("Object").":</b> ";
941 echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
942 flush();
943 }
944 }
946 /* If the source release is empty, then create a new release by copying
947 all group application menus into a new ou=$destination_name release container.
949 If the source release is not empty.
950 We detect all releases which match the source release dn and copy the contents.
951 */
952 if(empty($source_release)){
953 $source_dns = $groups;
954 }else{
955 $source_dns = array();
956 foreach($g_releases as $dn => $data){
957 if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
958 $source_dns[$dn] = $data;
959 }
960 }
961 }
963 /* Detect all menu object we have to copy
964 */
965 $to_copy = array();
966 foreach($source_dns as $dn => $attrs){
967 $ldap->cd($dn);
968 $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
969 while($attrs = $ldap->fetch()){
970 $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
971 $to_copy[$attrs['dn']] = $destination;
972 }
973 }
975 /* At least create the menu objects object */
976 $plug = new plugin($config);
977 foreach($to_copy as $source => $destination){
978 $ldap->cat($destination);
979 if($ldap->count()){
980 echo " <b>"._("Object").":</b> ";
981 echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
982 flush();
983 }else{
984 $plug->copy($source,$destination);
985 echo " <b>"._("Object").":</b> ";
986 echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
987 flush();
988 }
989 }
990 }
993 /*! \brief Create a new FAI branch.
994 * @param $sourcedn String The source release dn
995 * @param $destinationdn String The destination dn
996 * @param $destinationName String The name of the new release
997 * @param $type String The release type (freeze/branch)
998 * @param $is_first Boolean Use to identify the first func. call when recursivly called.
999 * @param $depth Integer Current depth of recursion.
1000 */
1001 static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1002 {
1003 global $config;
1004 error_reporting(E_ALL | E_STRICT);
1005 $ldap = $config->get_ldap_link();
1006 $basedn = $config->current['BASE'];
1007 $delarray = array();
1009 /* The following code will output a status string
1010 * for each handled object, in a seperate iframe.
1011 */
1014 /* Display current action information.
1015 */
1016 if($is_first){
1017 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1018 }else{
1019 if(preg_match("/^ou=/",$sourcedn)){
1020 echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1021 }else{
1022 $tmp = split(",",$sourcedn);
1023 echo " <b>"._("Object").":</b> ";
1024 $deststr = LDAP::fix($destinationdn);
1025 if(strlen($deststr) > 96){
1026 $deststr = substr($deststr,0,96)."...";
1027 }
1028 echo $deststr."<br>";
1029 }
1030 }
1031 /* .. immediately display infos */
1032 flush();
1034 /* Check if destination entry already exists
1035 */
1036 $ldap->cat($destinationdn);
1037 if($ldap->count()){
1038 echo _("Could not create new release, the destination dn is already in use.");
1039 return;
1040 }else{
1042 $ldap->clearResult();
1044 /* Get source entry
1045 * if it does not exist, abort here.
1046 */
1047 $ldap->cd($basedn);
1048 $ldap->cat($sourcedn);
1049 $attr = $ldap->fetch();
1050 if((!$attr) || (count($attr)) ==0) {
1051 echo _("Error while fetching source dn - aborted!");
1052 return;
1053 }
1055 /* The current object we want to create is an department.
1056 * Create the department and add the FAIbranch tag.
1057 */
1058 if(in_array("organizationalUnit",$attr['objectClass'])){
1059 $attr['dn'] = LDAP::convert($destinationdn);
1060 $ldap->cd($basedn);
1061 $ldap->create_missing_trees($destinationdn);
1062 $ldap->cd($destinationdn);
1064 /* If is first entry, append FAIbranch to department entry */
1065 if($is_first){
1066 $ldap->cat($destinationdn);
1067 $attr= $ldap->fetch();
1068 /* Filter unneeded informations */
1069 foreach($attr as $key => $value){
1070 if(is_numeric($key)) unset($attr[$key]);
1071 if(isset($attr[$key]['count'])){
1072 if(is_array($attr[$key])){
1073 unset($attr[$key]['count']);
1074 }
1075 }
1076 }
1078 unset($attr['count']);
1079 unset($attr['dn']);
1081 /* Add marking attribute */
1082 $attr['objectClass'][] = "FAIbranch";
1084 /* Add this entry */
1085 $ldap->modify($attr);
1086 }
1087 }else{
1089 /* Replicate all relevant FAI objects here.
1090 * FAI objects, Apps and Mimetypes.
1091 * Get all attributes as binary value, to ensure that Icon, File template aso
1092 * are created correctly.
1093 */
1094 foreach($attr as $key => $value){
1096 if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1097 $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1098 $ei= ldap_first_entry($ldap->cid, $sr);
1099 if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1100 $attr[$key] = $tmp;
1101 }
1102 }
1104 if(is_numeric($key)) unset($attr[$key]);
1105 if(isset($attr[$key]['count'])){
1106 if(is_array($attr[$key])){
1107 unset($attr[$key]['count']);
1108 }
1109 }
1110 }
1111 unset($attr['count']);
1112 unset($attr['dn']);
1114 /* Add entry
1115 */
1116 $ldap->cd($destinationdn);
1117 $ldap->cat($destinationdn);
1119 $a = $ldap->fetch();
1120 if(!count($a)){
1121 $ldap->add($attr);
1122 }
1124 if(!$ldap->success()){
1126 /* Some error occurred */
1127 print "---------------------------------------------";
1128 print $ldap->get_error()."<br>";
1129 print $sourcedn."<br>";
1130 print $destinationdn."<br>";
1131 print_a( $attr);
1132 exit();
1133 }
1134 }
1135 }
1137 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1139 /* Prepare for recursive copy.
1140 * Get all object within the source dn and
1141 * call the recursive copy for each.
1142 */
1143 $ldap->ls ("(objectClass=*)",$sourcedn);
1144 while ($ldap->fetch()){
1145 $deldn= $ldap->getDN();
1146 $delarray[$deldn]= strlen($deldn);
1147 }
1148 asort ($delarray);
1149 reset ($delarray);
1150 $depth ++;
1151 foreach($delarray as $dn => $bla){
1152 if($dn != $destinationdn){
1153 $ldap->cd($basedn);
1154 $item = $ldap->fetch($ldap->cat($dn));
1155 if(!in_array("FAIbranch",$item['objectClass'])){
1156 FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1157 }
1158 }
1159 }
1160 if($is_first){
1161 echo "<p class='seperator'> </p>";
1162 }
1163 }
1167 /* This function returns the dn of the object release */
1168 static function get_release_dn($Current_DN)
1169 {
1170 global $config;
1171 $ldap = $config->get_ldap_link();
1172 $ldap->cd($config->current['BASE']);
1174 /* Split dn into pices */
1175 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1177 if(!is_array($dns_to_check)){
1178 return;
1179 }
1181 /* Use dn pieces, to create sub dns like
1182 ou=test,ou=1,ou=0...
1183 ou=1,ou=0...
1184 ou=0...
1185 To check which dn is our release container.
1186 */
1187 unset($dns_to_check['count']);
1188 while(count($dns_to_check)){
1190 /* Create dn */
1191 $new_dn = "";
1192 foreach($dns_to_check as $part){
1193 $new_dn .= $part.",";
1194 }
1195 $new_dn .= $config->current['BASE'];
1197 /* Check if this dn is a release dn */
1198 if(FAI::is_release_department($new_dn)){
1199 return($new_dn);
1200 }
1202 /* Remove first element of dn pieces */
1203 reset($dns_to_check);
1204 unset($dns_to_check[key($dns_to_check)]);
1205 }
1206 return("");
1207 }
1208 }
1213 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1214 ?>