Code

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