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