1 <?php
2 class appgroup extends plugin
3 {
4 var $config;
5 var $curbase;
7 /* Contains the menu structure in an array.
8 */
9 var $a_Structure= array();
10 var $a_Structure_on_load = array();
11 var $Releases;
12 var $FAIrelease = 0;
13 var $apps = array();
14 var $_cache = array();
16 var $app_parameter = array();
17 var $edit_entry = array();
18 var $enableReleaseManagement = FALSE;
21 public function __construct(&$config, $dn= NULL, $parent= NULL)
22 {
23 plugin::plugin($config,$dn,$parent);
24 $this->dn = $dn;
25 $this->_load_menu_structure();
26 $this->a_Structure_on_load = $this->a_Structure;
28 /* Check if we have relase mangement enabled and prepare group application for release management */
29 $tmp = $config->search("faiManagement", "CLASS",array('menu','tabs'));
30 if(!empty($tmp)){
31 $this->enableReleaseManagement = true;
32 }
34 $this->Releases = $this->getReleases();
35 $this->FAIrelease = "/";
36 $this->curbase = $this->config->current['BASE'];
37 $this->reload();
39 /* If we have at least one assigned application-
40 Enable this account.
41 */
42 $this->is_account = FALSE;
43 if(count($this->_get_all_entries()) > 1){
44 $this->is_account= TRUE;
45 }
46 $this->initially_was_account = $this->is_account;
47 }
50 /*! \brief Reload the list of applications for the currently selected release.
51 If necessary, maybe the list is already cached.
52 */
53 function reload()
54 {
55 $ret = array();
56 $release_info = $this->Releases[$this->FAIrelease];
58 /* Check if the available application were already been fetched.
59 If not, build up a list of available applications.
60 */
61 if(!isset($this->_cache['ReleaseApps'][$release_info['suffix']])){
63 /* First of all, get all application departments to search in.
64 */
65 $ldap = $this->config->get_ldap_link();
66 $ldap->cd($this->config->current['BASE']);
67 $ldap->search("ou=apps",array("dn"));
68 $app_deps = array();
69 while($attrs = $ldap->fetch()){
70 $app_deps[] = $attrs['dn'];
71 }
73 /* Search all release departments for the above fetched application departments
74 */
75 foreach($app_deps as $dep){
76 $ldap->cd($dep);
77 $ldap->search("objectClass=FAIbranch",array("dn"));
78 while($attrs = $ldap->fetch()){
79 $app_deps[] = $attrs['dn'];
80 }
81 }
83 /* Filter out those releases that match the currently selected release,
84 and fetch all applications from those departments.
85 */
86 foreach($app_deps as $dep){
87 if(preg_match("/^".normalizePreg($release_info['suffix'])."/",$dep)){
88 $ret = array_merge($ret,get_list("(objectClass=gosaApplication)","application",$dep,array("*"),GL_NONE));
89 }
90 }
92 /* Create a new array containing all fetch apps for the currently selected release,
93 sort it and store results in cache.
94 */
95 $tmp = array();
96 foreach($ret as $key => $app){
97 $tmp[$key] = $app['cn'][0];
98 }
99 natcasesort($tmp);
100 $res = array();
101 foreach($tmp as $key => $app){
102 $res[] = $ret[$key];
103 }
105 $this->_cache['ReleaseApps'][$release_info['suffix']] = $res;
106 }
107 $this->apps = $this->_cache['ReleaseApps'][$release_info['suffix']];
108 }
112 /*! \brief generate a list of available releases
113 @return return an array with all available releases.
115 e.g.
117 / "name" /
118 "found" 1
119 "parts" Array (empty)
120 "suffix" ou=apps,
122 halut "name" halut
123 "found" 1
124 "FAIstate"
125 "dn" ou=halut,ou=apps,ou=Direktorium,o=Landeshauptstadt München,c=de
126 "parts" 0 halut
127 "suffix" ou=halut,ou=apps,
129 This will be used as base for the application menu structure.
130 If there is a menu assigned for a release, this menu will be
131 appended with the index 'ENTRIES';
132 */
133 function getReleases()
134 {
135 $ret =array("/" => array("name" => "/", "found" => TRUE , "parts" => array(),"suffix" => get_ou('applicationou')));
136 if($this->enableReleaseManagement){
138 /* Only display those releases that we are able to read
139 */
140 $dn = get_ou("applicationou").$this->config->current['BASE'];
141 $filter = "(&(objectClass=organizationalUnit)(objectClass=FAIbranch))";
142 $res = get_sub_list($filter,array("application","fai"),
143 array(get_ou("applicationou"),get_ou("faiou")),$dn, array("ou","FAIstate"), GL_SUBSEARCH);
145 /* Go through all departments and check which department is a valid
146 department release.
147 */
148 foreach($res as $attrs){
149 if(preg_match("/".get_ou('applicationou')."/",$attrs['dn'])){
151 /* Parse all returned departments dns into a useable type.
152 (ou=1.0.0,ou=halut,ou=apps ==> halue/1.0.0)
153 */
154 $bb = preg_replace("/".get_ou('applicationou').".*/","",$attrs['dn']);
155 $parts = array_reverse(split("ou=",$bb));
157 $str ="";
158 foreach($parts as $key => $part){
159 if(empty($part)) {
160 unset($parts[$key]);
161 continue;
162 }
163 $part = str_replace(",","",$part);
164 $str .= $part."/";
165 $parts[$key] = $part;
166 }
167 $name = preg_replace("/\/$/","",$str);
168 if(empty($name)) {
169 $name ="/";
170 }
172 $FAIstate = "";
173 if(isset($attrs['FAIstate'])){
174 $FAIstate = $attrs['FAIstate'][0];
175 }
177 /* Check if this department has a menu structure assigned
178 */
179 $all = $this->_get_all_entries();
180 $found = FALSE;
181 foreach($all as $entry){
182 if(isset($entry['DN']) && preg_match("/^".normalizePreg($bb)."/",$entry['DN'])){
183 $found =TRUE;
184 break;
185 }
186 }
188 $ret[$name] = array("name" => $name,
189 "found" => $found,
190 "FAIstate" => $FAIstate,
191 "dn" => $attrs['dn'],
192 "parts" => $parts,"suffix" => $bb.get_ou('applicationou'));
193 }
194 }
195 }
196 ksort($ret);
197 return($ret);
198 }
201 /*! \brief Load the menu structure from ldap and create a multi dimensional array.
203 This will create a multidimensional array.
204 e.g.:
206 $this->a_Structure =
208 [0]['TYPE'] = "BASE"
209 [0]['ENTRIES'] [0]['TYPE'] = "RELEASE"
210 [0]['NAME'] = "halut"
211 [0]['ENTRIES']= array()
212 ...
213 [0]['ENTRIES'] [1]['TYPE'] = "RELEASE"
214 [1]['NAME'] = "halut/1.0.0"
215 [1]['ENTRIES'] [0]['TYPE'] = "TYPE"
216 [0]['NAME'] = "Programme"
217 [0]['ENTRIES'][0]['TYPE'] = "ENTRY"
218 [0]['NAME'] = "konqueror"
219 [1]['TYPE'] = "ENTRY"
220 [1]['NAME'] = "firefox"
221 */
222 function _load_menu_structure()
223 {
224 /* Create the base object
225 */
226 $base = array();
227 $base['UNIQID'] = uniqid();
228 $base['PARENT'] = 0;
229 $base['NAME'] = "";
230 $base['TYPE'] = "BASE";
231 $base['ENTRIES']= array();
232 $base['STATUS'] = "LOADED";
234 $this->a_Structure = array();
235 $this->a_Structure[0] = $base;
237 /* Search for all Releases/Menu Folders and Menu Entries,
238 to append them to our structure array.
239 */
240 $ldap = $this->config->get_ldap_link();
241 $ldap->cd($this->dn);
242 $ldap->search("(|(objectClass=gotoSubmenuEntry)(objectClass=FAIbranch)(objectClass=gotoMenuEntry))",array("*"));
243 while($attrs = $ldap->fetch()){
245 /* Find the correct position where to add this entry.
246 e.g. If we have cn=firefox,cn=Programme,ou=halut...
248 1. get a pointer to the halut array ($this->a_Structure['0'][ENTRIES''][]['halut'])
249 2. then get a pointer to the halut['ENTRIES'][]['Programme'] array.
250 3. append 'firefox' to the 'ENTRIES' of our "Programme" pointer.
251 */
252 $cur = &$this->a_Structure[0]['ENTRIES'];
253 $parent_id = $base['UNIQID'];
254 $sub_dn = preg_replace("/,".normalizePreg($this->dn)."$/","",$attrs['dn']);
255 $sub_dn_array = split("\,",$sub_dn);
257 /* Walk through our menu structure array while we have found
258 the correct position where to add this object.
259 */
260 $found = true;
261 for($i = (count($sub_dn_array)-1) ; $i >= 0 ; $i--){
262 $name = preg_replace("/^[^=]*+=/","",$sub_dn_array[$i]);
264 /* We haven't found the end node where this object has to be added
265 */
266 if($i > 0){
267 $found =FALSE;
268 foreach($cur as $key => $entry){
269 if($entry['NAME'] == $name){
270 $cur = &$cur[$key]['ENTRIES'];
271 $parent_id = $entry['UNIQID'];
272 $found =true;
273 break;
274 }
275 }
276 }else{
278 if(!$found){
279 break;
280 }
282 /* Get application priority.
283 And ensure that each priority exists once.
284 */
285 $priority = 1;
286 if(isset($attrs['gosaApplicationPriority'])){
287 $priority= $attrs['gosaApplicationPriority'][0];
288 }
289 while(isset($cur[$priority])){
290 $priority ++;
291 }
293 /* Create the data object that should be added
294 * Folder
295 * Entry
296 * Release
297 */
298 $data = array();
300 /* Add a menu folder
301 */
302 if(in_array("gotoSubmenuEntry",$attrs['objectClass'])){
303 $type = "FOLDER";
305 $data['ICON'] = "";
306 if(isset($attrs['gosaApplicationIcon'])){
307 $data['ICON'] = $ldap->get_attribute($attrs['dn'],"gosaApplicationIcon");
308 }
310 /* Add a menu entry
311 */
312 }elseif(in_array("gotoMenuEntry",$attrs['objectClass'])){
314 $type = "ENTRY";
315 $data['INFO'] = "";
316 $data['PARAMETER'] = array();
317 if(isset($attrs['gosaApplicationParameter'])){
318 for($p = 0 ; $p < $attrs['gosaApplicationParameter']['count'] ; $p ++){
319 if(preg_match("/:/",$attrs['gosaApplicationParameter'][$p])){
320 $tmp = split(":",$attrs['gosaApplicationParameter'][$p]);
321 $data['PARAMETER'][$tmp[0]] = $tmp[1];
322 }elseif($attrs['gosaApplicationParameter'][$p] == "*separator*"){
323 $type = "SEPERATOR";
324 $data['PARAMETER'] = array();
325 break;
326 }
327 }
328 }
330 /* Add a release
331 */
332 }elseif(in_array("FAIbranch",$attrs['objectClass'])){
333 $type = "RELEASE";
334 if(isset($attrs['FAIstate'][0])){
335 $data['FAIstate'] = $attrs['FAIstate'][0];
336 }else{
337 $data['FAIstate'] = "";
338 }
339 }
341 /* Create object and append it to the current structure pointer
342 */
343 $data['LDAP_ATTRS'] = $attrs;
344 $data['DN'] = $attrs['dn'];
345 $data['NAME'] = $name;
346 $data['TYPE'] = $type;
347 $data['PRIORITY'] = $priority;
348 $data['ENTRIES'] = array();
349 $data['UNIQID'] = uniqid();
350 $data['PARENT'] = $parent_id;
351 $data['STATUS'] = "LOADED";
352 $cur[$priority] = $data;
353 ksort($cur);
354 }
355 }
356 }
357 }
360 function execute()
361 {
362 /* Call parent execute */
363 plugin::execute();
365 if(isset($_GET['r'])) $this->__construct($this->config,$this->dn);
367 if (isset($_POST['modify_state'])){
368 $this->is_account = !$this->is_account;
369 }
371 /* Do we represent a valid account? */
372 if (!$this->is_account){
373 $display= $this->show_disable_header(msgPool::addFeaturesButton(_("Menu")), msgPool::featuresDisabled(_("Menu")));
374 return ($display);
375 }
377 $display= $this->show_disable_header(msgPool::removeFeaturesButton(_("Menu")), msgPool::featuresEnabled(_("Menu")));
379 if(isset($_GET['send'])){
380 $id = $_GET['send'];
381 $all = $this->_get_all_entries();
382 if(isset($all[$id])){
383 send_binary_content($all[$id]['ICON'],$id.".jpg","image/jpeg");
384 exit;
385 }
386 }
388 if(isset($_GET['r']))
389 $this->__construct($this->config,$this->dn);
391 if(count($this->edit_entry)){
392 if($this->edit_entry['TYPE'] == "ENTRY"){
393 $smarty = get_smarty();
394 $smarty->assign("type", "ENTRY");
395 $smarty->assign("entry",$this->edit_entry);
396 $smarty->assign("paras",$this->app_parameter);
397 $display= $smarty->fetch (get_template_path('edit_entry.tpl', TRUE, dirname(__FILE__)));
398 return($display);
399 }
400 if($this->edit_entry['TYPE'] == "FOLDER"){
401 $smarty = get_smarty();
403 session::set("binarytype" , "image/jpeg");
404 session::set("binary" , $this->edit_entry['ICON']);
406 $smarty->assign("rand", microtime(TRUE));
407 $smarty->assign("image_set" , strlen($this->edit_entry['ICON']) > 0);
408 $smarty->assign("type", "FOLDER");
409 $smarty->assign("entry",$this->edit_entry);
410 $display= $smarty->fetch (get_template_path('edit_entry.tpl', TRUE, dirname(__FILE__)));
411 return($display);
412 }
413 }
415 $smarty = get_smarty();
416 $smarty->assign("plug_id" , $_GET['plug']);
418 /* Create application list */
419 $div = new divSelectBox("appgroup");
420 $div->SetHeight(300);
421 $departments = array();
422 $res = get_list("(objectClass=gosaDepartment)", "application", $this->curbase,array("description","cn","ou"),GL_SIZELIMIT);
423 foreach($res as $value){
424 $fdn = $value['dn'];
425 $fdn = preg_replace("/".normalizePreg($this->curbase)."/","",$fdn);
426 $fdn= @LDAP::fix($fdn);
427 if($value["description"][0]!=".."){
428 $departments[$value['dn']]= convert_department_dn($fdn)." - [".$value["description"][0]."]";
429 }else{
430 $departments[$value['dn']]=convert_department_dn($fdn)." ["._("Back")."]";
431 }
432 }
434 $linkopen = "<a href='?plug=".$_GET['plug']."&act=depopen&depid=%s'>%s</a>";
436 /* Create base back entry */
437 $base_back = preg_replace("/^[^,]+,/","",$this->curbase);
438 if((strlen($base_back)>= strlen($this->config->current['BASE']))&&($this->curbase!=$this->config->current['BASE'])){
439 $div->AddEntry(array(
440 array("string"=>sprintf($linkopen,base64_encode($base_back),".. ["._("back")."]"),
441 "attach"=>"style='border:0px;'")
442 ));
443 }
445 /* Append departments for current base */
446 foreach($departments as $key => $app){
447 $div->AddEntry(array(
448 array("string"=>"<img class='center' src='images/lists/folder.png' alt='"._("department")."'> ".sprintf($linkopen,
449 base64_encode($key),$app),
450 "attach"=>"style='border:0px;'")
451 ));
452 }
455 /* Add applications found on this base */
456 $used_apps = $this->_get_used_entry_name();
457 foreach($this->apps as $key => $app){
458 if(in_array($app['cn'][0],$used_apps)){
459 continue;
460 }
461 if(!preg_match("/".get_ou('applicationou').normalizePreg($this->curbase)."$/",$app['dn'])){
462 continue;
463 }
465 $name = $app['cn'][0];
466 if(isset($app['description'])){
467 $name .= " [".$app['description'][0]."]";
468 }
469 $div->AddEntry(array(
470 array("string"=>sprintf("<input class='center' type='checkbox' value='1' name='AddApp_%s'>",$key).
471 "<img class='center' src='images/select_application.png' alt='"._("application")."'> ".$name,
472 "attach"=>"style='border:0px;'")
473 ));
474 }
477 $smarty->assign("enableReleaseManagement",$this->enableReleaseManagement);
478 $smarty->assign("FAIrelease",$this->FAIrelease);
479 $smarty->assign("app_list",$div->DrawList());
480 $smarty->assign("i",0);
481 $smarty->assign("releases",$this->Releases);
482 $smarty->assign("folders" , $this->_get_folder_names());
483 $entries = $this->_get_entries_for_release($this->FAIrelease);
484 $smarty->assign("entries",$entries);
485 $display.= $smarty->fetch (get_template_path('app_list.tpl', TRUE, dirname(__FILE__)));
486 return($display);
487 }
490 /*! \brief Returns all used folder names
491 @return Array All used folder names.
492 */
493 function _get_folder_names()
494 {
495 $data = $this->_get_entries_for_release($this->FAIrelease);
496 $all = $this->_get_all_entries();
497 $ret = array("BASE" => ".");
498 foreach($data as $entry){
500 if($entry['TYPE'] == "FOLDER"){
501 $str = $entry['NAME'];
502 $parent = $entry['PARENT'];
503 $i = 10;
504 while(isset($all[$parent]) && $i){
505 $i --;
506 $parent_o = $all[$parent];
507 $str = $parent_o['NAME']."/".$str;
508 $parent = $all[$parent_o['UNIQID']]['PARENT'];
509 }
510 $ret[$entry['UNIQID']] = $str;
511 }
512 }
513 return($ret);
514 }
517 /*! \brief return all used applications
518 @return Array All used applications.
519 */
520 function _get_used_entry_name()
521 {
522 $data = $this->_get_entries_for_release($this->FAIrelease);
523 $ret = array();
524 foreach($data as $entry){
525 if($entry['TYPE'] == "ENTRY"){
526 $ret[] = $entry['NAME'];
527 }
528 }
529 return($ret);
530 }
533 /*! \brief Returns all folder an entries for the selected release
534 @return Array Returns the complete menu structure for the given array.
535 */
536 function _get_entries_for_release($release,$cur = NULL)
537 {
538 $all = $this->_get_all_entries();
539 $key = $this->_get_release_key($release);
540 if(isset($all[$key]) && count($all[$key]['ENTRIES'])){
541 $res = $this->_get_all_entries(TRUE,TRUE,$all[$key]['ENTRIES']);
542 return($res);
543 }
544 return(array());
545 }
548 /*! \brief Save the currently edited entry
549 */
550 function _save_entry_edit()
551 {
552 $all = $this->_get_all_entries();
553 $entry = $this->edit_entry;
554 $r_entry= &$all[$entry['UNIQID']];
556 if($entry['TYPE'] == "ENTRY"){
557 $r_entry['PARAMETER'] = $this->app_parameter;
558 $r_entry['STATUS'] = "EDITED";
559 }
560 if($entry['TYPE'] == "FOLDER"){
561 $r_entry['ICON'] = $this->edit_entry['ICON'];
562 $r_entry['STATUS'] = "EDITED";
563 }
564 $this->dialog = FALSE;
565 $this->edit_entry = array();
566 }
569 /*! \brief prepare the entry with the given ID, to be edited.
570 Read application Parameter from ldap.
571 */
572 function _edit_entry_edit($id)
573 {
574 $all = $this->_get_all_entries();
575 $entry = $all[$id];
577 $this->app_parameter = array();
578 if($entry['TYPE'] == "ENTRY"){
579 $found = FALSE;
580 foreach($this->apps as $id => $app){
582 if($app['cn'][0] == $entry['NAME']){
583 $found = TRUE;
584 break;
585 }
586 }
587 if($found){
589 /* Create a list of editable parameter */
590 if(isset($app['gosaApplicationParameter'])){
591 for($i = 0 ; $i < $app['gosaApplicationParameter']['count'] ; $i++) {
592 $para = $app['gosaApplicationParameter'][$i];
593 $tmp = split(":",$para);
594 $this->app_parameter[$tmp[0]] = $tmp[1];
595 }
596 }
598 /* Overwrite parameters with entry parameters */
599 foreach($entry['PARAMETER'] as $name => $value){
600 $this->app_parameter[$name] = $value;
601 }
603 $this->dialog = TRUE;
604 $this->edit_entry = $entry;
605 }
606 }
608 if($entry['TYPE'] == "FOLDER"){
609 $this->dialog = TRUE;
610 $this->edit_entry = $entry;
611 }
612 }
615 /*! \brief Removes the menu structure from ldap
616 */
617 function remove_from_parent()
618 {
619 $ldap = $this->config->get_ldap_link();
620 $ldap->cd($this->dn);
621 $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=FAIbranch)(objectClass=gotoMenuEntry))",$this->dn,array("*"));
622 $a_remove = array();
623 while($attrs = $ldap->fetch()){
624 $a_remove[] = $attrs['dn'];
625 }
626 foreach($a_remove as $remove){
627 $ldap->rmdir_recursive($remove);
628 if (!$ldap->success()){
629 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_DEL, get_class()));
630 }
631 }
632 $this->_load_menu_structure();
633 }
636 function check()
637 {
638 $message = plugin::check();
639 return($message);
640 }
643 /*! \brief Create missing releases, if there is a release selected \
644 that is currently not part of the menu structure \
645 then create this entry
646 */
647 function _check_missing_release($release)
648 {
649 $release_info = $this->Releases[$release];
651 $parent_id = $this->a_Structure[0]['UNIQID'];
652 $cur = &$this->a_Structure[0]['ENTRIES'];
653 for($i = 0 ; $i < count($release_info['parts']) ; $i ++){
654 $part = $release_info['parts'][$i];
655 $found = FALSE;
656 foreach($cur as $key => $name){
657 if($name['NAME'] == $part){
658 $parent_id = $cur[$key]['UNIQID'];
659 $cur = &$cur[$key]['ENTRIES'];
661 $found =TRUE;
662 break;
663 }
664 }
665 if(!$found){
666 $release = array();
667 $release['UNIQID'] = uniqid();
668 $release['PARENT'] = $parent_id;
669 $release['NAME'] = $part;
670 $release['TYPE'] = "RELEASE";
671 $release['ENTRIES']= array();
672 $release['STATUS'] = "ADDED";
673 $release['FAIstate'] = $release_info['FAIstate'];
674 $cur[] = $release;
675 $i --;
676 }
677 }
678 }
682 /*! \brief Moves a given object ($id) in a specified direction ($dir).
683 @param String The object ID of the object we want to move
684 @dir String Move "up" or "down"
685 */
686 function _move_entry($id,$dir)
687 {
688 $all = $this->_get_all_entries();
689 if($dir == "down"){
690 $to = $this->_get_next($id);
691 }
692 if($dir == "up"){
693 $to = $this->_get_last($id);
694 }
696 if(!$to){
697 return;
698 }
700 $o_to = $all[$to];
701 $o_from = $all[$id];
703 if($o_to['PARENT'] == $o_from['UNIQID'] && $dir == "down"){
704 $to = $this->_get_next($to,$o_from['PARENT']);
705 $o_to = $all[$to];
706 }
708 /* Target is ENTRY && same BASE, just switch */
709 if($o_to['PARENT'] == $o_from['PARENT'] ){
710 $parent = $all[$o_to['PARENT']];
711 $pos = 0;
712 foreach($parent['ENTRIES'] as $entry){
713 $pos ++;
714 if($entry['UNIQID'] == $to){
715 break;
716 }
717 }
718 if($dir == "up" && $pos > 0){
719 $pos --;
720 }
721 $this->_add_entry($parent['UNIQID'],$o_from,$pos);
722 $this->_remove_entry_id($id);
723 return(TRUE);
724 }
725 return(FALSE);
726 }
730 /*! \brief Returns the railing object ID of the given object.
731 @return String The id of the trailing object.
732 */
733 function _get_last($id)
734 {
735 $all_l = array_reverse($this->_get_entries_for_release($this->FAIrelease));
736 for($i = 0 ; $i < count($all_l) ; $i ++){
737 if(isset($all_l[$i]['UNIQID']) && $all_l[$i]['UNIQID'] == $id){
738 $i++;
739 break;
740 }
741 }
742 while(isset($all_l[$i]) && !in_array($all_l[$i]['TYPE'],array("ENTRY","FOLDER","CLOSE","OPEN")) && $i < count($all_l)){
743 $i++;
744 }
746 if(!isset($all_l[$i])){
747 return(FALSE);
748 }
750 if(in_array($all_l[$i]['TYPE'],array("CLOSE","OPEN"))){
751 return($all_l[$i]['PARENT']);
752 }
754 return($all_l[$i]['UNIQID']);
755 }
758 /*! \brief Returns the following object ID of the given object.
759 @return String The id of the following object.
760 */
761 function _get_next($id,$parent = 0)
762 {
763 $all_l = $this->_get_entries_for_release($this->FAIrelease);
764 for($i = 0 ; $i < count($all_l) ; $i ++){
765 if(isset($all_l[$i]['UNIQID']) && $all_l[$i]['UNIQID'] == $id){
766 $i++;
767 break;
768 }
769 }
770 if($parent != 0){
771 while(isset($all_l[$i]) && $all_l[$i]['PARENT'] != $parent){
772 $i++;
773 }
774 }else{
775 while(isset($all_l[$i]) && !in_array($all_l[$i]['TYPE'],array("ENTRY","FOLDER")) && $i < count($all_l)){
776 $i++;
777 }
778 }
779 if(!isset($all_l[$i])){
780 return(FALSE);
781 }
782 if(in_array($all_l[$i]['TYPE'],array("CLOSE","OPEN"))){
783 return($all_l[$i]['PARENT']);
784 }
785 return($all_l[$i]['UNIQID']);
786 }
791 /* !\brief Handle ui POSTS, like sort up/down/delete
792 */
793 function save_object()
794 {
795 foreach($_POST as $name => $value){
796 if(preg_match("/del_/",$name)){
797 $id = preg_replace("/^del_/","",$name);
798 $id = preg_replace("/_(x|y)$/","",$id);
799 $this->_remove_entry_id($id);
800 break;
801 }
802 if(preg_match("/app_entry_edit/",$name)){
803 $id = preg_replace("/^app_entry_edit/","",$name);
804 $id = preg_replace("/_(x|y)$/","",$id);
805 $this->_edit_entry_edit($id);
806 break;
807 }
808 if(preg_match("/up_/",$name)){
809 $id = preg_replace("/^up_/","",$name);
810 $id = preg_replace("/_(x|y)$/","",$id);
811 $this->_move_entry($id,"up");
812 break;
813 }
814 if(preg_match("/down_/",$name)){
815 $id = preg_replace("/^down_/","",$name);
816 $id = preg_replace("/_(x|y)$/","",$id);
817 $this->_move_entry($id,"down");
818 break;
819 }
820 if(preg_match("/^parameter_/",$name) &&
821 count($this->edit_entry) && $this->edit_entry['TYPE'] == "ENTRY"){
822 $name = preg_replace("/^parameter_/","",$name);
823 $this->app_parameter[$name] = $value;
824 }
825 }
826 if(isset($_POST['FAIrelease'])){
827 $this->FAIrelease = $_POST['FAIrelease'];
828 $this->_check_missing_release($this->FAIrelease);
829 }
830 if(isset($_GET['act']) && $_GET['act'] == 'depopen'){
831 $this->curbase = base64_decode($_GET['depid']);
832 }
833 if(isset($_POST['add_to_folder']) && isset($_POST['folder'])){
834 $folder = $_POST['folder'];
835 foreach($_POST as $name => $value){
836 if(preg_match("/^AddApp_[0-9]*$/",$name)){
837 $this->_add_app_id($folder,preg_replace("/^AddApp_/","",$name));
838 }
839 }
840 }
842 /* Add seperator */
843 if(isset($_POST['add_seperator']) && isset($_POST['menu_folder'])){
844 $folder = $_POST['menu_folder'];
845 $this->_add_seperator($folder);
846 }
848 if(isset($_POST['add_menu_to_folder']) && isset($_POST['menu_folder'])){
849 $folder = $_POST['menu_folder'];
850 $name = $_POST['menu_folder_name'];
851 if(strlen($name) > 0 && preg_match("/[a-z ]/i",$name)){
852 $this->_add_sub_folder($folder,$name);
853 }
854 }
855 if(isset($_POST['app_entry_save'])){
856 $this->_save_entry_edit();
857 }
859 if(isset($_FILES['folder_image']) && isset($_POST['folder_image_upload'])){
860 if($_FILES['folder_image']['error'] == 0 && $_FILES['folder_image']['size'] > 0){
861 $this->edit_entry['ICON'] = file_get_contents($_FILES['folder_image']['tmp_name']);
862 }
863 }
865 if(isset($_POST['edit_reset_image'])){
866 $this->edit_entry['ICON'] = "";
867 }
869 if(isset($_POST['app_entry_cancel'])){
870 $this->edit_entry = array();
871 $this->dialog = FALSE;
872 }
873 $this->reload();
874 }
877 /*! \brief Returns the UNIQID of the currently selected release
878 */
879 function _get_release_key($release,$add_if_missing = FALSE)
880 {
881 $release_info = $this->Releases[$release];
883 if($release_info['name'] == "/"){
884 return($this->a_Structure['0']['UNIQID']);
885 }
887 $cur = &$this->a_Structure[0]['ENTRIES'];
888 $s_key = "";
889 $found = FALSE;
890 foreach($release_info['parts'] as $name){
891 foreach($cur as $key => $obj){
892 if($obj['TYPE'] == "RELEASE" && $obj['NAME'] == $name){
893 $s_key = $cur[$key]['UNIQID'];
894 $cur = &$cur[$key]['ENTRIES'];
895 $found = TRUE;
896 break;
897 }
898 $found = FALSE;
899 }
900 }
901 if($found){
902 return($s_key);
903 }
904 return(FALSE);
905 }
908 /*! \brief Add a new folder folder to the specified folder id
909 @param String $folder The folder id in where we want to add the new folder.
910 @param String $name The name of the new folder.
911 */
912 function _add_sub_folder($folder,$name)
913 {
914 $all = $this->_get_all_entries();
915 if($folder == "BASE"){
916 $folder = $this->_get_release_key($this->FAIrelease,TRUE);
917 }
919 if(isset($all[$folder])){
920 $a_folder = array();
921 $a_folder['STATUS'] = "ADDED";
922 $a_folder['NAME'] = $name;
923 $a_folder['UNIQID'] = uniqid();
924 $a_folder['ENTRIES']= array();
925 $a_folder['PARENT'] = $folder;
926 $a_folder['TYPE'] = "FOLDER";
927 $a_folder['ICON'] = "";
928 $all[$folder]['ENTRIES'][] = $a_folder;
929 }
930 }
933 /* !\brief Remove the given id from the menu structure.
934 @param String ID to of the entry we want to remove.
935 @return Boolean TRUE on success
936 */
937 function _remove_entry_id($id)
938 {
939 $all = $this->_get_all_entries();
940 if(isset($all[$id])){
941 $all[$id]['STATUS'] = "REMOVED";
942 $all[$id]['ENTRIES'] = array();
943 return(TRUE);
944 }
945 return(FALSE);
946 }
949 /* !\brief Adds an object to a given folder.
950 @param String The folder where we should add the entry
951 @param Array The entry we want to add.
952 @param Array The position in the destination entry array.
953 */
954 function _add_entry($folder_id,$entry,$pos = 0)
955 {
956 $all = $this->_get_all_entries();
958 /* Do not add removed */
959 if($entry['STATUS'] == "REMOVED"){
960 return;
961 }
963 /* Check if the folder exists
964 */
965 if(isset($all[$folder_id])){
967 /* Check if the entry we want to add,
968 contains su objects.
969 */
970 if(!isset($entry['ENTRIES'])){
971 $entries = array();
972 }else{
973 $entries = $entry['ENTRIES'];
974 }
975 $folder = &$all[$folder_id];
977 /* Prepare the entry to be added.
978 */
979 $entry['UNIQID'] = uniqid();
980 $entry['PARENT'] = $folder_id;
981 $entry['ENTRIES']= array();
982 $entry['STATUS'] = "ADDED";
984 /* Append the ebtry to the given folder
985 and to the given position \$pos
986 */
987 $cnt = 0;
988 $new = array();
989 $added =FALSE;
990 foreach($folder['ENTRIES'] as $key => $obj){
991 if($obj['STATUS'] == "LOADED"){
992 $obj['STATUS'] = "EDITED";
993 }
994 if($pos == $cnt){
995 $new[] = $entry;
996 $added = TRUE;
997 }
998 $cnt ++;
999 $new[] = $obj;
1000 }
1001 if(!$added){
1002 $new[] = $entry;
1003 }
1004 $all[$folder_id]['ENTRIES'] = &$new;
1006 /* Add sub entries too.
1007 */
1008 foreach($entries as $sub){
1009 $this->_add_entry($entry['UNIQID'],$sub,-1);
1010 }
1011 return(TRUE);
1012 }
1013 return(FALSE);
1014 }
1017 /*! \brief Add the application identified by $app_id to folder $folder_id
1018 @param String folder_id The UNIQID of the folder where we want to add the new folder.
1019 @param Integer app_id The ID of the application which should be added.
1020 */
1021 function _add_app_id($folder_id,$app_id)
1022 {
1023 $all = $this->_get_all_entries();
1024 if($folder_id == "BASE"){
1025 $folder_id = $this->_get_release_key($this->FAIrelease);
1026 }
1027 if(isset($all[$folder_id]) && isset($this->apps[$app_id])){
1029 $new = array();
1030 $new['TYPE'] = "ENTRY";
1031 $new['NAME'] = $this->apps[$app_id]['cn'][0];
1032 $new['UNIQID']= uniqid();
1033 $new['PARENT']= $folder_id;
1034 $new['PARAMETER']= array();
1035 if(isset($this->apps[$app_id]['description'][0])){
1036 $new['INFO'] = $this->apps[$app_id]['description'][0];
1037 }else{
1038 $new['INFO'] = "";
1039 }
1040 $new['STATUS']= "ADDED";
1041 $all[$folder_id]['ENTRIES'][] = $new;
1042 }
1043 }
1046 /*! \brief Add the application identified by $app_id to folder $folder_id
1047 @param String folder_id The UNIQID of the folder where we want to add the new folder.
1048 @param Integer app_id The ID of the application which should be added.
1049 */
1050 function _add_seperator($folder_id)
1051 {
1052 $all = $this->_get_all_entries();
1053 if($folder_id == "BASE"){
1054 $folder_id = $this->_get_release_key($this->FAIrelease);
1055 }
1057 if(isset($all[$folder_id])){
1058 $new = array();
1059 $new['TYPE'] = "SEPERATOR";
1060 $new['NAME'] = "SEPERATOR";
1061 $new['UNIQID']= uniqid();
1062 $new['PARENT']= $folder_id;
1063 $new['PARAMETER']= array();
1064 $new['STATUS']= "ADDED";
1065 $all[$folder_id]['ENTRIES'][] = $new;
1066 }
1067 }
1070 /*! \brief Return all entries linear. ($this->a_Structure is a multidimensional array)
1071 @param Boolean $add_tags If TRUE, OPEN/CLOSE Tags will be appended.
1072 Used in the smarty template to display logical sperations.
1073 @param &Array Start here, Pointer to an array.
1074 */
1075 function _get_all_entries($add_tags = FALSE, $skip_release = FALSE, &$cur = NULL)
1076 {
1077 $ret = array();
1078 if($cur == NULL){
1079 $cur = &$this->a_Structure;
1080 }
1082 /* Walk through all entries and append them to our return array
1083 */
1084 foreach($cur as $key => $entry){
1085 if($skip_release && $entry['TYPE'] == "RELEASE"){
1086 continue;
1087 }
1088 if($entry['TYPE'] == "ENTRY"){
1089 $found = FALSE;
1090 foreach($this->apps as $app){
1091 if($app['cn'][0] == $entry['NAME']){
1092 $found = TRUE;
1093 if(isset($app['description'][0])){
1094 $entry['INFO'] = "[".$app['description'][0]."]";
1095 }
1096 break;
1097 }
1098 }
1099 if(!$found){
1100 $entry['INFO'] = "<font color='red'>"._("Not available in release.")."</font>";
1101 }
1102 }
1104 $tmp = $entry;
1106 /* Recursive resolution of the subentries
1107 There are two methods.
1108 - Just add sub entries
1109 - Add sub entries and additionaly add OPEN / CLOSE tags to be able
1110 to display logical seperators in the smarty template.
1111 */
1112 if(!$add_tags){
1113 $ret[$tmp['UNIQID']] = &$cur[$key];
1114 if(isset($entry['ENTRIES']) && count($entry['ENTRIES'])){
1115 $ret = array_merge($ret,$this->_get_all_entries($add_tags,$skip_release,$cur[$key]['ENTRIES']));
1116 }
1117 }else{
1119 if(isset($tmp['ENTRIES'])){
1120 unset($tmp['ENTRIES']);
1121 }
1122 if($tmp['STATUS'] != "REMOVED"){
1123 $ret[] = $tmp;
1124 if(isset($entry['ENTRIES']) && count($entry['ENTRIES'])){
1125 $add = false;
1126 foreach($entry['ENTRIES'] as $entry){
1127 if($entry['STATUS'] != "REMOVED"){
1128 $add = TRUE;
1129 break;
1130 }
1131 }
1133 if($add){
1134 $ret[] = array("TYPE" => "OPEN", "PARENT" => $entry['PARENT']);
1135 $ret = array_merge($ret,$this->_get_all_entries($add_tags,$skip_release,$cur[$key]['ENTRIES']));
1136 $ret[] = array("TYPE" => "CLOSE" , "PARENT" => $entry['PARENT']);
1137 }
1138 }
1139 }
1140 }
1141 }
1142 return($ret);
1143 }
1146 /*! \brief Save this plugin data to ldap.
1147 Save the current menu structure to ldap.
1148 */
1149 function save()
1150 {
1151 $ldap = $this->config->get_ldap_link();
1152 $all = $this->_get_all_entries();
1153 $prio = 0;
1154 $Actions = array("Remove" => array(),"Edit" => array() , "Add" => array());
1157 /* Walk through the menu structure and build up the ldap data object,
1158 the entry dn and the entry priority.
1159 */
1160 $sep_id = 0;
1161 foreach($all as $entry){
1162 $prio ++;
1163 $cur = $entry;
1164 $dn = "";
1166 /* Build entry dn
1167 */
1168 do{
1169 if($cur['TYPE'] == "SEPERATOR"){
1170 $sep_id ++;
1171 $dn.= "cn=seperator_".$sep_id.",";
1172 }elseif($cur['TYPE'] == "ENTRY"){
1173 $dn.= "cn=".$cur['NAME'].",";
1174 }elseif($cur['TYPE'] == "FOLDER"){
1175 $dn.= "cn=".$cur['NAME'].",";
1176 }elseif($cur['TYPE'] == "RELEASE"){
1177 $dn.= "ou=".$cur['NAME'].",";
1178 }elseif($cur['TYPE'] == "BASE"){
1179 }
1180 if(!isset($all[$cur['PARENT']])){
1181 $cur = NULL;
1182 }else{
1183 $cur = $all[$cur['PARENT']];
1184 }
1185 }while(is_array($cur));
1187 $cur_dn = $dn.$this->dn;
1188 $attrs = array();
1190 /* Build entry data object.
1191 */
1192 switch($entry['TYPE']){
1193 case "SEPERATOR" :
1194 {
1195 $attrs['objectClass'] = array("gotoMenuEntry");
1196 $attrs['cn'] = "seperator_".$sep_id;
1197 $attrs['gosaApplicationPriority'] = $prio;
1198 $attrs['gosaApplicationParameter'] = "*separator*";
1199 }
1200 break;
1201 case "ENTRY" :
1202 {
1203 $attrs['objectClass'] = array("gotoMenuEntry");
1204 $attrs['cn'] = $entry['NAME'];
1205 $attrs['gosaApplicationPriority'] = $prio;
1206 $attrs['gosaApplicationParameter'] = array();
1208 foreach($entry['PARAMETER'] as $name => $value){
1209 $attrs['gosaApplicationParameter'][] = $name.":".$value;
1210 }
1211 if($entry['STATUS'] == "ADDED" && !count($attrs['gosaApplicationParameter'])){
1212 unset($attrs['gosaApplicationParameter']);
1213 }
1214 }
1215 break;
1216 case "FOLDER" :
1217 {
1218 $attrs['objectClass'] = array("gotoSubmenuEntry");
1219 $attrs['cn'] = $entry['NAME'];
1220 $attrs['gosaApplicationPriority'] = $prio;
1221 if($entry['STATUS'] != "ADDED"){
1222 $attrs['gosaApplicationIcon'] = array();
1223 }
1225 if(!empty($entry['ICON'])){
1226 $attrs['gosaApplicationIcon'] = $entry['ICON'];
1227 }
1228 }
1229 break;
1230 case "RELEASE" :
1231 {
1232 $attrs['ou'] = $entry['NAME'];
1233 $attrs['objectClass'] = array();
1234 $attrs['objectClass'][] = "top";
1235 $attrs['objectClass'][] = "organizationalUnit";
1236 $attrs['objectClass'][] = "FAIbranch";
1237 if(!empty($entry['FAIstate'])){
1238 $attrs['FAIstate'] = $entry['FAIstate'];
1239 }
1240 }
1241 break;
1242 }
1244 /* Append missing ObjectClasses, ... Tagging
1245 */
1246 if(isset($entry['LDAP_ATTRS'])){
1247 for($i = 0 ; $i < $entry['LDAP_ATTRS']['objectClass']['count']; $i ++){
1248 $oc = $entry['LDAP_ATTRS']['objectClass'][$i];
1249 if(!in_array($oc,$attrs['objectClass'])){
1250 $attrs['objectClass'][] = $oc;
1251 }
1252 }
1253 }
1255 /* Create an array containing all operations sorted by type. (add,remove...)
1256 */
1257 if($entry['STATUS'] == "LOADED"){
1258 continue;
1259 }
1260 if($entry['STATUS'] == "REMOVED"){
1261 if(isset($entry['DN'])){
1262 $Actions['Remove'][$entry['DN']] = $entry['DN'];
1263 }else{
1264 $Actions['Remove'][$cur_dn] = $cur_dn;
1265 }
1266 }
1267 if($entry['STATUS'] == "EDITED"){
1268 $Actions['Edit'][$cur_dn] = $attrs;
1269 }
1270 if($entry['STATUS'] == "ADDED"){
1271 $Actions['Add'][$cur_dn] = $attrs;
1272 }
1273 }
1275 /* First remove entries
1276 */
1277 $ldap = $this->config->get_ldap_link();
1278 $ldap->cd($this->config->current['BASE']);
1279 foreach($Actions['Remove'] as $dn){
1280 $ldap->cd($dn);
1281 $ldap->cat($dn);
1282 if($ldap->count()){
1283 $ldap->rmdir_recursive($dn);
1284 if (!$ldap->success()){
1285 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, LDAP_DEL, get_class()));
1286 }
1287 }
1288 }
1290 /* Add new entries
1291 */
1292 foreach($Actions['Add'] as $dn => $data){
1293 $ldap->cd($dn);
1294 $ldap->cat($dn);
1295 if(!$ldap->count()){
1296 $ldap->add($data);
1297 if (!$ldap->success()){
1298 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, LDAP_DEL, get_class()));
1299 }
1300 }
1301 }
1303 /* Modify entries
1304 */
1305 foreach($Actions['Edit'] as $dn => $data){
1306 $ldap->cd($dn);
1307 $ldap->cat($dn);
1308 if($ldap->count()){
1309 $ldap->modify($data);
1310 if (!$ldap->success()){
1311 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, LDAP_DEL, get_class()));
1312 }
1313 }
1314 }
1316 $this->_load_menu_structure();
1317 }
1320 /*! \brief Return plugin informations for acl handling
1321 @return Array containing all plugin ACL informations
1322 */
1323 static function plInfo()
1324 {
1325 return (array(
1326 "plShortName" => _("Applications"),
1327 "plDescription" => _("Group applications"),
1328 "plSelfModify" => FALSE,
1329 "plDepends" => array(),
1330 "plPriority" => 0,
1331 "plSection" => array("admin"),
1332 "plCategory" => array("groups"),
1333 "plProvidedAcls"=> array(
1334 "gosaMemberApplication" => _("Application"),
1335 "FAIrelease" => _("Release"),
1336 "gosaApplicationParameter" => _("Application parameter"))
1337 ));
1338 }
1341 /* \brief Prepare this plugin to be copied.
1342 Adapt all required attributes from the source object.
1343 In this case, update the menu structure too, mark all elements
1344 as newly added, so they will be saved in save();
1345 */
1346 function PrepareForCopyPaste($source)
1347 {
1348 plugin::PrepareForCopyPaste($source);
1350 $tmp = new appgroup($this->config,$source['dn']);
1351 $this->is_account = TRUE;
1352 $this->a_Structure = $tmp->a_Structure;
1353 $all = $this->_get_all_entries();
1354 foreach($all as &$entry){
1355 if(isset($entry['STATUS'])){
1356 $entry['STATUS'] = "ADDED";
1357 }
1358 }
1359 }
1362 /*! \brief Save HTML posts in multiple edit mode
1363 */
1364 function multiple_save_object()
1365 {
1366 if(isset($_POST['group_apps_multi'])){
1367 $this->save_object();
1368 plugin::multiple_save_object();
1370 /* Get posts */
1371 foreach(array("apps") as $attr){
1372 if(isset($_POST['use_'.$attr])) {
1373 $this->multi_boxes[] = $attr;
1374 }
1375 }
1376 }
1377 }
1380 /*! \brief Return values used in multiple edit mode.
1381 Some values can be modified for multiple
1382 groups at the same time.
1383 @return Array All values that support multiple edit.
1384 */
1385 function get_multi_edit_values()
1386 {
1387 $ret = plugin::get_multi_edit_values();
1389 if(in_array("apps",$this->multi_boxes)){
1390 $ret['gosaApplicationParameter'] = $this->gosaApplicationParameter;
1391 $ret['Categories'] = $this->Categories;
1392 $ret['gosaMemberApplication'] = $this->gosaMemberApplication;
1393 $ret['FAIrelease'] = $this->FAIrelease;
1394 $ret['appoption'] = $this->appoption;
1395 }
1396 return($ret);
1397 }
1398 }
1399 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1400 ?>