Code

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