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