Code

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