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