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