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("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("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 }
811 /* !\brief Handle ui POSTS, like sort up/down/delete
812 */
813 function save_object()
814 {
815 foreach($_POST as $name => $value){
817 if(preg_match("/^menu_copy_/",$name)){
818 $this->copied_release = $this->FAIrelease;
819 break;
820 }
821 if(preg_match("/^menu_delete/",$name)){
822 $current_rel = $this->_get_release_key($this->FAIrelease);
823 $this->_remove_entry_id($current_rel);
824 break;
825 }
826 if(preg_match("/^menu_paste_/",$name)){
827 $source_rel = $this->_get_release_key($this->copied_release);
828 $current_rel = $this->_get_release_key($this->FAIrelease);
830 $all = $this->_get_all_entries();
831 $menu = $all[$source_rel]['ENTRIES'];
833 foreach($menu as $entry){
834 if(in_array($entry['TYPE'],array("FOLDER","ENTRY","SEPERATOR"))){
835 $this->_add_entry($current_rel,$entry,-1);
836 }
837 }
838 $this->copied_release = "";
839 break;
840 }
842 if(preg_match("/del_/",$name)){
843 $id = preg_replace("/^del_/","",$name);
844 $id = preg_replace("/_(x|y)$/","",$id);
845 $this->_remove_entry_id($id);
846 break;
847 }
848 if(preg_match("/app_entry_edit/",$name)){
849 $id = preg_replace("/^app_entry_edit/","",$name);
850 $id = preg_replace("/_(x|y)$/","",$id);
851 $this->_edit_entry_edit($id);
852 break;
853 }
854 if(preg_match("/up_/",$name)){
855 $id = preg_replace("/^up_/","",$name);
856 $id = preg_replace("/_(x|y)$/","",$id);
857 $this->_move_entry($id,"up");
858 break;
859 }
860 if(preg_match("/down_/",$name)){
861 $id = preg_replace("/^down_/","",$name);
862 $id = preg_replace("/_(x|y)$/","",$id);
863 $this->_move_entry($id,"down");
864 break;
865 }
866 if(preg_match("/^parameter_/",$name) &&
867 count($this->edit_entry) && $this->edit_entry['TYPE'] == "ENTRY"){
868 $name = preg_replace("/^parameter_/","",$name);
869 $this->app_parameter[$name] = $value;
870 }
871 }
872 if(isset($_POST['FAIrelease'])){
873 $this->FAIrelease = $_POST['FAIrelease'];
874 $this->_check_missing_release($this->FAIrelease);
875 }
876 if(isset($_GET['act']) && $_GET['act'] == 'depopen'){
877 $this->curbase = base64_decode($_GET['depid']);
878 }
879 if(isset($_POST['add_to_folder']) && isset($_POST['folder'])){
880 $folder = $_POST['folder'];
881 foreach($_POST as $name => $value){
882 if(preg_match("/^AddApp_[0-9]*$/",$name)){
883 $this->_add_app_id($folder,preg_replace("/^AddApp_/","",$name));
884 }
885 }
886 }
888 /* Add seperator */
889 if(isset($_POST['add_seperator']) && isset($_POST['menu_folder'])){
890 $folder = $_POST['menu_folder'];
891 $this->_add_seperator($folder);
892 }
894 if(isset($_POST['add_menu_to_folder']) && isset($_POST['menu_folder'])){
895 $folder = $_POST['menu_folder'];
896 $name = $_POST['menu_folder_name'];
897 if(strlen($name) > 0 && preg_match("/[a-z ]/i",$name)){
898 $this->_add_sub_folder($folder,$name);
899 }
900 }
901 if(isset($_POST['app_entry_save'])){
902 $this->_save_entry_edit();
903 }
905 if(isset($_FILES['folder_image']) && isset($_POST['folder_image_upload'])){
906 if($_FILES['folder_image']['error'] == 0 && $_FILES['folder_image']['size'] > 0){
907 $this->edit_entry['ICON'] = file_get_contents($_FILES['folder_image']['tmp_name']);
908 }
909 }
911 if(isset($_POST['edit_reset_image'])){
912 $this->edit_entry['ICON'] = "";
913 }
915 if(isset($_POST['app_entry_cancel'])){
916 $this->edit_entry = array();
917 $this->dialog = FALSE;
918 }
919 $this->reload();
920 }
923 /*! \brief Returns the UNIQID of the currently selected release
924 */
925 function _get_release_key($release,$add_if_missing = FALSE)
926 {
927 $release_info = $this->Releases[$release];
929 if($release_info['name'] == "/"){
930 return($this->a_Structure['0']['UNIQID']);
931 }
933 $cur = &$this->a_Structure[0]['ENTRIES'];
934 $s_key = "";
935 $found = FALSE;
936 foreach($release_info['parts'] as $name){
937 foreach($cur as $key => $obj){
938 if($obj['TYPE'] == "RELEASE" && $obj['NAME'] == $name){
939 $s_key = $cur[$key]['UNIQID'];
940 $cur = &$cur[$key]['ENTRIES'];
941 $found = TRUE;
942 break;
943 }
944 $found = FALSE;
945 }
946 }
947 if($found){
948 return($s_key);
949 }
950 return(FALSE);
951 }
954 /*! \brief Add a new folder folder to the specified folder id
955 @param String $folder The folder id in where we want to add the new folder.
956 @param String $name The name of the new folder.
957 */
958 function _add_sub_folder($folder,$name)
959 {
960 $all = $this->_get_all_entries();
961 if($folder == "BASE"){
962 $folder = $this->_get_release_key($this->FAIrelease,TRUE);
963 }
965 if(isset($all[$folder])){
966 $a_folder = array();
967 $a_folder['STATUS'] = "ADDED";
968 $a_folder['NAME'] = $name;
969 $a_folder['UNIQID'] = uniqid();
970 $a_folder['ENTRIES']= array();
971 $a_folder['PARENT'] = $folder;
972 $a_folder['TYPE'] = "FOLDER";
973 $a_folder['ICON'] = "";
974 $all[$folder]['ENTRIES'][] = $a_folder;
975 }
976 }
979 /* !\brief Remove the given id from the menu structure.
980 @param String ID to of the entry we want to remove.
981 @return Boolean TRUE on success
982 */
983 function _remove_entry_id($id)
984 {
985 $all = $this->_get_all_entries();
986 if(isset($all[$id])){
987 $all[$id]['STATUS'] = "REMOVED";
988 $all[$id]['ENTRIES'] = array();
989 return(TRUE);
990 }
991 return(FALSE);
992 }
995 /* !\brief Adds an object to a given folder.
996 @param String The folder where we should add the entry
997 @param Array The entry we want to add.
998 @param Array The position in the destination entry array.
999 */
1000 function _add_entry($folder_id,$entry,$pos = 0)
1001 {
1002 $all = $this->_get_all_entries();
1004 /* Do not add removed */
1005 if($entry['STATUS'] == "REMOVED"){
1006 return;
1007 }
1009 /* Check if the folder exists
1010 */
1011 if(isset($all[$folder_id])){
1013 /* Check if the entry we want to add,
1014 contains su objects.
1015 */
1016 if(!isset($entry['ENTRIES'])){
1017 $entries = array();
1018 }else{
1019 $entries = $entry['ENTRIES'];
1020 }
1021 $folder = &$all[$folder_id];
1023 /* Prepare the entry to be added.
1024 */
1025 $entry['UNIQID'] = uniqid();
1026 $entry['PARENT'] = $folder_id;
1027 $entry['ENTRIES']= array();
1028 $entry['STATUS'] = "ADDED";
1030 /* Append the ebtry to the given folder
1031 and to the given position \$pos
1032 */
1033 $cnt = 0;
1034 $new = array();
1035 $added =FALSE;
1036 foreach($folder['ENTRIES'] as $key => $obj){
1037 if($obj['STATUS'] == "LOADED"){
1038 $obj['STATUS'] = "EDITED";
1039 }
1040 if($pos == $cnt){
1041 $new[] = $entry;
1042 $added = TRUE;
1043 }
1044 $cnt ++;
1045 $new[] = $obj;
1046 }
1047 if(!$added){
1048 $new[] = $entry;
1049 }
1050 $all[$folder_id]['ENTRIES'] = &$new;
1052 /* Add sub entries too.
1053 */
1054 foreach($entries as $sub){
1055 $this->_add_entry($entry['UNIQID'],$sub,-1);
1056 }
1057 return(TRUE);
1058 }
1059 return(FALSE);
1060 }
1063 /*! \brief Add the application identified by $app_id to folder $folder_id
1064 @param String folder_id The UNIQID of the folder where we want to add the new folder.
1065 @param Integer app_id The ID of the application which should be added.
1066 */
1067 function _add_app_id($folder_id,$app_id)
1068 {
1069 $all = $this->_get_all_entries();
1070 if($folder_id == "BASE"){
1071 $folder_id = $this->_get_release_key($this->FAIrelease);
1072 }
1073 if(isset($all[$folder_id]) && isset($this->apps[$app_id])){
1075 $new = array();
1076 $new['TYPE'] = "ENTRY";
1077 $new['NAME'] = $this->apps[$app_id]['cn'][0];
1078 $new['UNIQID']= uniqid();
1079 $new['PARENT']= $folder_id;
1080 $new['PARAMETER']= array();
1081 if(isset($this->apps[$app_id]['description'][0])){
1082 $new['INFO'] = $this->apps[$app_id]['description'][0];
1083 }else{
1084 $new['INFO'] = "";
1085 }
1086 $new['STATUS']= "ADDED";
1087 $all[$folder_id]['ENTRIES'][] = $new;
1088 }
1089 }
1092 /*! \brief Add the application identified by $app_id to folder $folder_id
1093 @param String folder_id The UNIQID of the folder where we want to add the new folder.
1094 @param Integer app_id The ID of the application which should be added.
1095 */
1096 function _add_seperator($folder_id)
1097 {
1098 $all = $this->_get_all_entries();
1099 if($folder_id == "BASE"){
1100 $folder_id = $this->_get_release_key($this->FAIrelease);
1101 }
1103 if(isset($all[$folder_id])){
1104 $new = array();
1105 $new['TYPE'] = "SEPERATOR";
1106 $new['NAME'] = "SEPERATOR";
1107 $new['UNIQID']= uniqid();
1108 $new['PARENT']= $folder_id;
1109 $new['PARAMETER']= array();
1110 $new['STATUS']= "ADDED";
1111 $all[$folder_id]['ENTRIES'][] = $new;
1112 }
1113 }
1116 /*! \brief Return all entries linear. ($this->a_Structure is a multidimensional array)
1117 @param Boolean $add_tags If TRUE, OPEN/CLOSE Tags will be appended.
1118 Used in the smarty template to display logical sperations.
1119 @param &Array Start here, Pointer to an array.
1120 */
1121 function _get_all_entries($add_tags = FALSE, $skip_release = FALSE, &$cur = NULL)
1122 {
1123 $ret = array();
1124 if($cur == NULL){
1125 $cur = &$this->a_Structure;
1126 }
1128 /* Walk through all entries and append them to our return array
1129 */
1130 foreach($cur as $key => $entry){
1131 if($skip_release && $entry['TYPE'] == "RELEASE"){
1132 continue;
1133 }
1134 if($entry['TYPE'] == "ENTRY"){
1135 $found = FALSE;
1136 foreach($this->apps as $app){
1137 if($app['cn'][0] == $entry['NAME']){
1138 $found = TRUE;
1139 if(isset($app['description'][0])){
1140 $entry['INFO'] = "[".$app['description'][0]."]";
1141 }
1142 break;
1143 }
1144 }
1145 if(!$found){
1146 $entry['INFO'] = "<font color='red'>"._("Not available in release.")."</font>";
1147 }
1148 }
1150 $tmp = $entry;
1152 /* Recursive resolution of the subentries
1153 There are two methods.
1154 - Just add sub entries
1155 - Add sub entries and additionaly add OPEN / CLOSE tags to be able
1156 to display logical seperators in the smarty template.
1157 */
1158 if(!$add_tags){
1159 $ret[$tmp['UNIQID']] = &$cur[$key];
1160 if(isset($entry['ENTRIES']) && count($entry['ENTRIES'])){
1161 $ret = array_merge($ret,$this->_get_all_entries($add_tags,$skip_release,$cur[$key]['ENTRIES']));
1162 }
1163 }else{
1165 if(isset($tmp['ENTRIES'])){
1166 unset($tmp['ENTRIES']);
1167 }
1168 if($tmp['STATUS'] != "REMOVED"){
1169 $ret[] = $tmp;
1170 if(isset($entry['ENTRIES']) && count($entry['ENTRIES'])){
1171 $add = false;
1172 foreach($entry['ENTRIES'] as $entry){
1173 if($entry['STATUS'] != "REMOVED"){
1174 $add = TRUE;
1175 break;
1176 }
1177 }
1179 if($add){
1180 $ret[] = array("TYPE" => "OPEN", "PARENT" => $entry['PARENT']);
1181 $ret = array_merge($ret,$this->_get_all_entries($add_tags,$skip_release,$cur[$key]['ENTRIES']));
1182 $ret[] = array("TYPE" => "CLOSE" , "PARENT" => $entry['PARENT']);
1183 }
1184 }
1185 }
1186 }
1187 }
1188 return($ret);
1189 }
1192 /*! \brief Save this plugin data to ldap.
1193 Save the current menu structure to ldap.
1194 */
1195 function save()
1196 {
1197 $ldap = $this->config->get_ldap_link();
1198 $all = $this->_get_all_entries();
1199 $prio = 0;
1200 $Actions = array("Remove" => array(),"Edit" => array() , "Add" => array());
1202 /* Walk through the menu structure and build up the ldap data object,
1203 the entry dn and the entry priority.
1204 */
1205 $sep_id = 0;
1206 foreach($all as $entry){
1207 $prio ++;
1208 $cur = $entry;
1209 $dn = "";
1211 /* Build entry dn
1212 */
1213 do{
1214 if($cur['TYPE'] == "SEPERATOR"){
1215 $sep_id ++;
1216 $dn.= "cn=seperator_".$sep_id.",";
1217 }elseif($cur['TYPE'] == "ENTRY"){
1218 $dn.= "cn=".$cur['NAME'].",";
1219 }elseif($cur['TYPE'] == "FOLDER"){
1220 $dn.= "cn=".$cur['NAME'].",";
1221 }elseif($cur['TYPE'] == "RELEASE"){
1222 $dn.= "ou=".$cur['NAME'].",";
1223 }elseif($cur['TYPE'] == "BASE"){
1224 }
1225 if(!isset($all[$cur['PARENT']])){
1226 $cur = NULL;
1227 }else{
1228 $cur = $all[$cur['PARENT']];
1229 }
1230 }while(is_array($cur));
1232 $cur_dn = $dn.$this->dn;
1233 $attrs = array();
1235 /* Build entry data object.
1236 */
1237 switch($entry['TYPE']){
1238 case "SEPERATOR" :
1239 {
1240 $attrs['objectClass'] = array("gotoMenuEntry");
1241 $attrs['cn'] = "seperator_".$sep_id;
1242 $attrs['gosaApplicationPriority'] = $prio;
1243 $attrs['gosaApplicationParameter'] = "*separator*";
1244 }
1245 break;
1246 case "ENTRY" :
1247 {
1248 $attrs['objectClass'] = array("gotoMenuEntry");
1249 $attrs['cn'] = $entry['NAME'];
1250 $attrs['gosaApplicationPriority'] = $prio;
1251 $attrs['gosaApplicationParameter'] = array();
1253 foreach($entry['PARAMETER'] as $name => $value){
1254 $attrs['gosaApplicationParameter'][] = $name.":".$value;
1255 }
1256 if($entry['STATUS'] == "ADDED" && !count($attrs['gosaApplicationParameter'])){
1257 unset($attrs['gosaApplicationParameter']);
1258 }
1259 }
1260 break;
1261 case "FOLDER" :
1262 {
1263 $attrs['objectClass'] = array("gotoSubmenuEntry");
1264 $attrs['cn'] = $entry['NAME'];
1265 $attrs['gosaApplicationPriority'] = $prio;
1266 if($entry['STATUS'] != "ADDED"){
1267 $attrs['gosaApplicationIcon'] = array();
1268 }
1270 if(!empty($entry['ICON'])){
1271 $attrs['gosaApplicationIcon'] = $entry['ICON'];
1272 }
1273 }
1274 break;
1275 case "RELEASE" :
1276 {
1277 $attrs['ou'] = $entry['NAME'];
1278 $attrs['objectClass'] = array();
1279 $attrs['objectClass'][] = "top";
1280 $attrs['objectClass'][] = "organizationalUnit";
1281 $attrs['objectClass'][] = "FAIbranch";
1282 if(!empty($entry['FAIstate'])){
1283 $attrs['FAIstate'] = $entry['FAIstate'];
1284 }
1285 }
1286 break;
1287 }
1289 /* Append missing ObjectClasses, ... Tagging
1290 */
1291 if(isset($entry['LDAP_ATTRS'])){
1292 for($i = 0 ; $i < $entry['LDAP_ATTRS']['objectClass']['count']; $i ++){
1293 $oc = $entry['LDAP_ATTRS']['objectClass'][$i];
1294 if(!in_array($oc,$attrs['objectClass'])){
1295 $attrs['objectClass'][] = $oc;
1296 }
1297 }
1298 }
1300 /* Create an array containing all operations sorted by type. (add,remove...)
1301 */
1302 if($entry['STATUS'] == "LOADED"){
1303 continue;
1304 }
1305 if($entry['STATUS'] == "REMOVED"){
1306 if(isset($entry['DN'])){
1307 $Actions['Remove'][$entry['DN']] = $entry['DN'];
1308 }else{
1309 $Actions['Remove'][$cur_dn] = $cur_dn;
1310 }
1311 }
1312 if($entry['STATUS'] == "EDITED"){
1313 $Actions['Edit'][$cur_dn] = $attrs;
1314 }
1315 if($entry['STATUS'] == "ADDED"){
1316 $Actions['Add'][$cur_dn] = $attrs;
1317 }
1318 }
1320 /* First remove entries
1321 */
1322 $ldap = $this->config->get_ldap_link();
1323 $ldap->cd($this->config->current['BASE']);
1324 foreach($Actions['Remove'] as $dn){
1325 $ldap->cd($dn);
1326 $ldap->cat($dn);
1327 if($ldap->count()){
1328 $ldap->rmdir_recursive($dn);
1329 if (!$ldap->success()){
1330 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, LDAP_DEL, get_class()));
1331 }
1332 }
1333 }
1335 /* Add new entries
1336 */
1337 foreach($Actions['Add'] as $dn => $data){
1338 $this->tag_attrs($data,$dn,$this->gosaUnitTag);
1339 $ldap->cd($dn);
1340 $ldap->cat($dn);
1341 if(!$ldap->count()){
1342 $ldap->add($data);
1343 if (!$ldap->success()){
1344 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, LDAP_ADD, get_class()));
1345 }
1346 }
1347 }
1349 /* Modify entries
1350 */
1351 foreach($Actions['Edit'] as $dn => $data){
1352 $this->tag_attrs($data,$dn,$this->gosaUnitTag);
1353 $ldap->cd($dn);
1354 $ldap->cat($dn);
1355 if($ldap->count()){
1356 $ldap->modify($data);
1357 if (!$ldap->success()){
1358 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, LDAP_MOD, get_class()));
1359 }
1360 }
1361 }
1363 $this->_load_menu_structure();
1364 }
1367 /*! \brief Return plugin informations for acl handling
1368 @return Array containing all plugin ACL informations
1369 */
1370 static function plInfo()
1371 {
1372 return (array(
1373 "plShortName" => _("Applications"),
1374 "plDescription" => _("Group applications"),
1375 "plSelfModify" => FALSE,
1376 "plDepends" => array(),
1377 "plPriority" => 7,
1378 "plSection" => array("administration"),
1379 "plCategory" => array("groups"),
1380 "plProvidedAcls"=> array(
1381 "gosaMemberApplication" => _("Application"),
1382 "FAIrelease" => _("Release"),
1383 "gosaApplicationParameter" => _("Application parameter"))
1384 ));
1385 }
1388 /* \brief Prepare this plugin to be copied.
1389 Adapt all required attributes from the source object.
1390 In this case, update the menu structure too, mark all elements
1391 as newly added, so they will be saved in save();
1392 */
1393 function PrepareForCopyPaste($source)
1394 {
1395 plugin::PrepareForCopyPaste($source);
1397 $tmp = new appgroup($this->config,$source['dn']);
1398 $this->is_account = TRUE;
1399 $this->a_Structure = $tmp->a_Structure;
1400 $all = $this->_get_all_entries();
1401 foreach($all as &$entry){
1402 if(isset($entry['STATUS'])){
1403 $entry['STATUS'] = "ADDED";
1404 }
1405 }
1406 }
1409 /*! \brief Save HTML posts in multiple edit mode
1410 */
1411 function multiple_save_object()
1412 {
1413 if(isset($_POST['group_apps_multi'])){
1414 $this->save_object();
1415 plugin::multiple_save_object();
1417 /* Get posts */
1418 foreach(array("apps") as $attr){
1419 if(isset($_POST['use_'.$attr])) {
1420 $this->multi_boxes[] = $attr;
1421 }
1422 }
1423 }
1424 }
1427 /*! \brief Return values used in multiple edit mode.
1428 Some values can be modified for multiple
1429 groups at the same time.
1430 @return Array All values that support multiple edit.
1431 */
1432 function get_multi_edit_values()
1433 {
1434 $ret = plugin::get_multi_edit_values();
1436 if(in_array("apps",$this->multi_boxes)){
1437 $ret['gosaApplicationParameter'] = $this->gosaApplicationParameter;
1438 $ret['Categories'] = $this->Categories;
1439 $ret['gosaMemberApplication'] = $this->gosaMemberApplication;
1440 $ret['FAIrelease'] = $this->FAIrelease;
1441 $ret['appoption'] = $this->appoption;
1442 }
1443 return($ret);
1444 }
1445 }
1446 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1447 ?>