54b1694442fdce83284ee2f02ad7b35abc01cb37
1 <?php
2 class appgroup extends plugin
3 {
4 var $config;
5 var $curbase;
7 /* Contains the menu structure in an array.
8 */
9 var $a_Structure= array();
10 var $a_Structure_on_load = array();
11 var $Releases;
12 var $FAIrelease = 0;
13 var $apps = array();
14 var $_cache = array();
16 var $app_parameter = array();
17 var $edit_entry = array();
18 var $enableReleaseManagement = FALSE;
20 var $copied_release = "";
23 public function __construct(&$config, $dn= NULL, $parent= NULL)
24 {
25 plugin::plugin($config,$dn,$parent);
26 $this->dn = $dn;
27 $this->_load_menu_structure();
28 $this->a_Structure_on_load = $this->a_Structure;
30 /* Check if we have relase mangement enabled and prepare group application for release management */
31 $tmp = $config->search("faiManagement", "CLASS",array('menu','tabs'));
32 if(!empty($tmp)){
33 $this->enableReleaseManagement = true;
34 }
36 $this->Releases = $this->getReleases();
37 $this->FAIrelease = "/";
38 $this->curbase = $this->config->current['BASE'];
39 $this->reload();
41 /* If we have at least one assigned application-
42 Enable this account.
43 */
44 $this->is_account = FALSE;
45 if(count($this->_get_all_entries()) > 1){
46 $this->is_account= TRUE;
47 }
48 $this->initially_was_account = $this->is_account;
49 }
52 /*! \brief Reload the list of applications for the currently selected release.
53 If necessary, maybe the list is already cached.
54 */
55 function reload()
56 {
57 $ret = array();
58 $release_info = $this->Releases[$this->FAIrelease];
60 /* Check if the available application were already been fetched.
61 If not, build up a list of available applications.
62 */
63 if(!isset($this->_cache['ReleaseApps'][$release_info['suffix']])){
65 /* First of all, get all application departments to search in.
66 */
67 $ldap = $this->config->get_ldap_link();
68 $ldap->cd($this->config->current['BASE']);
69 $ldap->search("ou=apps",array("dn"));
70 $app_deps = array();
71 while($attrs = $ldap->fetch()){
72 $app_deps[] = $attrs['dn'];
73 }
75 /* Search all release departments for the above fetched application departments
76 */
77 foreach($app_deps as $dep){
78 $ldap->cd($dep);
79 $ldap->search("objectClass=FAIbranch",array("dn"));
80 while($attrs = $ldap->fetch()){
81 $app_deps[] = $attrs['dn'];
82 }
83 }
85 /* Filter out those releases that match the currently selected release,
86 and fetch all applications from those departments.
87 */
88 foreach($app_deps as $dep){
89 if(preg_match("/^".normalizePreg($release_info['suffix'])."/",$dep)){
90 $ret = array_merge($ret,get_list("(objectClass=gosaApplication)","application",$dep,array("*"),GL_NONE));
91 }
92 }
94 /* Create a new array containing all fetch apps for the currently selected release,
95 sort it and store results in cache.
96 */
97 $tmp = array();
98 foreach($ret as $key => $app){
99 $tmp[$key] = $app['cn'][0];
100 }
101 natcasesort($tmp);
102 $res = array();
103 foreach($tmp as $key => $app){
104 $res[] = $ret[$key];
105 }
107 $this->_cache['ReleaseApps'][$release_info['suffix']] = $res;
108 }
109 $this->apps = $this->_cache['ReleaseApps'][$release_info['suffix']];
110 }
114 /*! \brief generate a list of available releases
115 @return return an array with all available releases.
117 e.g.
119 / "name" /
120 "found" 1
121 "parts" Array (empty)
122 "suffix" ou=apps,
124 halut "name" halut
125 "found" 1
126 "FAIstate"
127 "dn" ou=halut,ou=apps,ou=Direktorium,o=Landeshauptstadt München,c=de
128 "parts" 0 halut
129 "suffix" ou=halut,ou=apps,
131 This will be used as base for the application menu structure.
132 If there is a menu assigned for a release, this menu will be
133 appended with the index 'ENTRIES';
134 */
135 function getReleases()
136 {
137 $ret =array("/" => array("name" => "/", "found" => TRUE , "parts" => array(),"suffix" => get_ou('applicationou')));
138 if($this->enableReleaseManagement){
140 /* Only display those releases that we are able to read
141 */
142 $dn = get_ou("applicationou").$this->config->current['BASE'];
143 $filter = "(&(objectClass=organizationalUnit)(objectClass=FAIbranch))";
144 $res = get_sub_list($filter,array("application","fai"),
145 array(get_ou("applicationou"),get_ou("faiou")),$dn, array("ou","FAIstate"), GL_SUBSEARCH);
147 /* Go through all departments and check which department is a valid
148 department release.
149 */
150 foreach($res as $attrs){
151 if(preg_match("/".get_ou('applicationou')."/",$attrs['dn'])){
153 /* Parse all returned departments dns into a useable type.
154 (ou=1.0.0,ou=halut,ou=apps ==> halue/1.0.0)
155 */
156 $bb = preg_replace("/".get_ou('applicationou').".*/","",$attrs['dn']);
157 $parts = array_reverse(split("ou=",$bb));
159 $str ="";
160 foreach($parts as $key => $part){
161 if(empty($part)) {
162 unset($parts[$key]);
163 continue;
164 }
165 $part = str_replace(",","",$part);
166 $str .= $part."/";
167 $parts[$key] = $part;
168 }
169 $name = preg_replace("/\/$/","",$str);
170 if(empty($name)) {
171 $name ="/";
172 }
174 $FAIstate = "";
175 if(isset($attrs['FAIstate'])){
176 $FAIstate = $attrs['FAIstate'][0];
177 }
179 /* Check if this department has a menu structure assigned
180 */
181 $all = $this->_get_all_entries();
182 $found = FALSE;
183 foreach($all as $entry){
184 if(isset($entry['DN']) && preg_match("/^".normalizePreg($bb)."/",$entry['DN'])){
185 $found =TRUE;
186 break;
187 }
188 }
190 $ret[$name] = array("name" => $name,
191 "found" => $found,
192 "FAIstate" => $FAIstate,
193 "dn" => $attrs['dn'],
194 "parts" => $parts,"suffix" => $bb.get_ou('applicationou'));
195 }
196 }
197 }
198 ksort($ret);
199 return($ret);
200 }
203 /*! \brief Load the menu structure from ldap and create a multi dimensional array.
205 This will create a multidimensional array.
206 e.g.:
208 $this->a_Structure =
210 [0]['TYPE'] = "BASE"
211 [0]['ENTRIES'] [0]['TYPE'] = "RELEASE"
212 [0]['NAME'] = "halut"
213 [0]['ENTRIES']= array()
214 ...
215 [0]['ENTRIES'] [1]['TYPE'] = "RELEASE"
216 [1]['NAME'] = "halut/1.0.0"
217 [1]['ENTRIES'] [0]['TYPE'] = "TYPE"
218 [0]['NAME'] = "Programme"
219 [0]['ENTRIES'][0]['TYPE'] = "ENTRY"
220 [0]['NAME'] = "konqueror"
221 [1]['TYPE'] = "ENTRY"
222 [1]['NAME'] = "firefox"
223 */
224 function _load_menu_structure()
225 {
226 /* Create the base object
227 */
228 $base = array();
229 $base['UNIQID'] = uniqid();
230 $base['PARENT'] = 0;
231 $base['NAME'] = "";
232 $base['TYPE'] = "BASE";
233 $base['ENTRIES']= array();
234 $base['STATUS'] = "LOADED";
236 $this->a_Structure = array();
237 $this->a_Structure[0] = $base;
239 /* Search for all Releases/Menu Folders and Menu Entries,
240 to append them to our structure array.
241 */
242 $ldap = $this->config->get_ldap_link();
243 $ldap->cd($this->dn);
244 $ldap->search("(|(objectClass=gotoSubmenuEntry)(objectClass=FAIbranch)(objectClass=gotoMenuEntry))",array("*"));
245 while($attrs = $ldap->fetch()){
247 /* Find the correct position where to add this entry.
248 e.g. If we have cn=firefox,cn=Programme,ou=halut...
250 1. get a pointer to the halut array ($this->a_Structure['0'][ENTRIES''][]['halut'])
251 2. then get a pointer to the halut['ENTRIES'][]['Programme'] array.
252 3. append 'firefox' to the 'ENTRIES' of our "Programme" pointer.
253 */
254 $cur = &$this->a_Structure[0]['ENTRIES'];
255 $parent_id = $base['UNIQID'];
256 $sub_dn = preg_replace("/,".normalizePreg($this->dn)."$/","",$attrs['dn']);
257 $sub_dn_array = split("\,",$sub_dn);
259 /* Walk through our menu structure array while we have found
260 the correct position where to add this object.
261 */
262 $found = true;
263 for($i = (count($sub_dn_array)-1) ; $i >= 0 ; $i--){
264 $name = preg_replace("/^[^=]*+=/","",$sub_dn_array[$i]);
266 /* We haven't found the end node where this object has to be added
267 */
268 if($i > 0){
269 $found =FALSE;
270 foreach($cur as $key => $entry){
271 if($entry['NAME'] == $name){
272 $cur = &$cur[$key]['ENTRIES'];
273 $parent_id = $entry['UNIQID'];
274 $found =true;
275 break;
276 }
277 }
278 }else{
280 if(!$found){
281 break;
282 }
284 /* Get application priority.
285 And ensure that each priority exists once.
286 */
287 $priority = 1;
288 if(isset($attrs['gosaApplicationPriority'])){
289 $priority= $attrs['gosaApplicationPriority'][0];
290 }
291 while(isset($cur[$priority])){
292 $priority ++;
293 }
295 /* Create the data object that should be added
296 * Folder
297 * Entry
298 * Release
299 */
300 $data = array();
302 /* Add a menu folder
303 */
304 if(in_array("gotoSubmenuEntry",$attrs['objectClass'])){
305 $type = "FOLDER";
307 $data['ICON'] = "";
308 if(isset($attrs['gosaApplicationIcon'])){
309 $data['ICON'] = $ldap->get_attribute($attrs['dn'],"gosaApplicationIcon");
310 }
312 /* Add a menu entry
313 */
314 }elseif(in_array("gotoMenuEntry",$attrs['objectClass'])){
316 $type = "ENTRY";
317 $data['INFO'] = "";
318 $data['PARAMETER'] = array();
319 if(isset($attrs['gosaApplicationParameter'])){
320 for($p = 0 ; $p < $attrs['gosaApplicationParameter']['count'] ; $p ++){
321 if(preg_match("/:/",$attrs['gosaApplicationParameter'][$p])){
322 $tmp = split(":",$attrs['gosaApplicationParameter'][$p]);
323 $data['PARAMETER'][$tmp[0]] = $tmp[1];
324 }elseif($attrs['gosaApplicationParameter'][$p] == "*separator*"){
325 $type = "SEPERATOR";
326 $data['PARAMETER'] = array();
327 break;
328 }
329 }
330 }
332 /* Add a release
333 */
334 }elseif(in_array("FAIbranch",$attrs['objectClass'])){
335 $type = "RELEASE";
336 if(isset($attrs['FAIstate'][0])){
337 $data['FAIstate'] = $attrs['FAIstate'][0];
338 }else{
339 $data['FAIstate'] = "";
340 }
341 }
343 /* Create object and append it to the current structure pointer
344 */
345 $data['LDAP_ATTRS'] = $attrs;
346 $data['DN'] = $attrs['dn'];
347 $data['NAME'] = $name;
348 $data['TYPE'] = $type;
349 $data['PRIORITY'] = $priority;
350 $data['ENTRIES'] = array();
351 $data['UNIQID'] = uniqid();
352 $data['PARENT'] = $parent_id;
353 $data['STATUS'] = "LOADED";
354 $cur[$priority] = $data;
355 ksort($cur);
356 }
357 }
358 }
359 }
362 function execute()
363 {
364 /* Call parent execute */
365 plugin::execute();
367 if(isset($_GET['r'])) $this->__construct($this->config,$this->dn);
369 if (isset($_POST['modify_state'])){
370 $this->is_account = !$this->is_account;
371 }
373 /* Do we represent a valid account? */
374 if (!$this->is_account){
375 $display= $this->show_disable_header(msgPool::addFeaturesButton(_("Menu")), msgPool::featuresDisabled(_("Menu")));
376 return ($display);
377 }
379 $display= $this->show_disable_header(msgPool::removeFeaturesButton(_("Menu")), msgPool::featuresEnabled(_("Menu")));
381 if(isset($_GET['send'])){
382 $id = $_GET['send'];
383 $all = $this->_get_all_entries();
384 if(isset($all[$id])){
385 send_binary_content($all[$id]['ICON'],$id.".jpg","image/jpeg");
386 exit;
387 }
388 }
390 if(isset($_GET['r']))
391 $this->__construct($this->config,$this->dn);
393 if(count($this->edit_entry)){
394 if($this->edit_entry['TYPE'] == "ENTRY"){
395 $smarty = get_smarty();
396 $smarty->assign("type", "ENTRY");
397 $smarty->assign("entry",$this->edit_entry);
398 $smarty->assign("paras",$this->app_parameter);
399 $display= $smarty->fetch (get_template_path('edit_entry.tpl', TRUE, dirname(__FILE__)));
400 return($display);
401 }
402 if($this->edit_entry['TYPE'] == "FOLDER"){
403 $smarty = get_smarty();
405 session::set("binarytype" , "image/jpeg");
406 session::set("binary" , $this->edit_entry['ICON']);
408 $smarty->assign("rand", microtime(TRUE));
409 $smarty->assign("image_set" , strlen($this->edit_entry['ICON']) > 0);
410 $smarty->assign("type", "FOLDER");
411 $smarty->assign("entry",$this->edit_entry);
412 $display= $smarty->fetch (get_template_path('edit_entry.tpl', TRUE, dirname(__FILE__)));
413 return($display);
414 }
415 }
417 $smarty = get_smarty();
418 $smarty->assign("plug_id" , $_GET['plug']);
420 /* Create application list */
421 $div = new divSelectBox("appgroup");
422 $div->SetHeight(300);
423 $departments = array();
424 $res = get_list("(objectClass=gosaDepartment)", "application", $this->curbase,array("description","cn","ou"),GL_SIZELIMIT);
425 foreach($res as $value){
426 $fdn = $value['dn'];
427 $fdn = preg_replace("/".normalizePreg($this->curbase)."/","",$fdn);
428 $fdn= @LDAP::fix($fdn);
429 if($value["description"][0]!=".."){
430 $departments[$value['dn']]= convert_department_dn($fdn)." - [".$value["description"][0]."]";
431 }else{
432 $departments[$value['dn']]=convert_department_dn($fdn)." ["._("Back")."]";
433 }
434 }
436 $linkopen = "<a href='?plug=".$_GET['plug']."&act=depopen&depid=%s'>%s</a>";
438 /* Create base back entry */
439 $base_back = preg_replace("/^[^,]+,/","",$this->curbase);
440 if((strlen($base_back)>= strlen($this->config->current['BASE']))&&($this->curbase!=$this->config->current['BASE'])){
441 $div->AddEntry(array(
442 array("string"=>sprintf($linkopen,base64_encode($base_back),".. ["._("back")."]"),
443 "attach"=>"style='border:0px;'")
444 ));
445 }
447 /* Append departments for current base */
448 foreach($departments as $key => $app){
449 $div->AddEntry(array(
450 array("string"=>"<img class='center' src='images/lists/folder.png' alt='"._("department")."'> ".sprintf($linkopen,
451 base64_encode($key),$app),
452 "attach"=>"style='border:0px;'")
453 ));
454 }
457 /* Add applications found on this base */
458 $used_apps = $this->_get_used_entry_name();
459 foreach($this->apps as $key => $app){
460 if(in_array($app['cn'][0],$used_apps)){
461 continue;
462 }
463 if(!preg_match("/".get_ou('applicationou').normalizePreg($this->curbase)."$/",$app['dn'])){
464 continue;
465 }
467 $name = $app['cn'][0];
468 if(isset($app['description'])){
469 $name .= " [".$app['description'][0]."]";
470 }
471 $div->AddEntry(array(
472 array("string"=>sprintf("<input class='center' type='checkbox' value='1' name='AddApp_%s'>",$key).
473 "<img class='center' src='images/select_application.png' alt='"._("application")."'> ".$name,
474 "attach"=>"style='border:0px;'")
475 ));
476 }
478 /* Assign copy / paste values
479 */
480 if(!empty($this->copied_release)){
481 $smarty->assign("copied", TRUE);
482 $smarty->assign("copy_source", $this->copied_release);
483 }else{
484 $smarty->assign("copied", FALSE);
485 }
486 $smarty->assign("enableReleaseManagement",$this->enableReleaseManagement);
487 $smarty->assign("FAIrelease",$this->FAIrelease);
488 $smarty->assign("app_list",$div->DrawList());
489 $smarty->assign("i",0);
490 $smarty->assign("releases",$this->Releases);
491 $smarty->assign("folders" , $this->_get_folder_names());
492 $entries = $this->_get_entries_for_release($this->FAIrelease);
493 $smarty->assign("entries",$entries);
494 $display.= $smarty->fetch (get_template_path('app_list.tpl', TRUE, dirname(__FILE__)));
495 return($display);
496 }
499 /*! \brief Returns all used folder names
500 @return Array All used folder names.
501 */
502 function _get_folder_names()
503 {
504 $data = $this->_get_entries_for_release($this->FAIrelease);
505 $all = $this->_get_all_entries();
506 $ret = array("BASE" => ".");
507 foreach($data as $entry){
509 if($entry['TYPE'] == "FOLDER"){
510 $str = $entry['NAME'];
511 $parent = $entry['PARENT'];
512 $i = 10;
513 while(isset($all[$parent]) && $i){
514 $i --;
515 $parent_o = $all[$parent];
516 $str = $parent_o['NAME']."/".$str;
517 $parent = $all[$parent_o['UNIQID']]['PARENT'];
518 }
519 $ret[$entry['UNIQID']] = $str;
520 }
521 }
522 return($ret);
523 }
526 /*! \brief return all used applications
527 @return Array All used applications.
528 */
529 function _get_used_entry_name()
530 {
531 $data = $this->_get_entries_for_release($this->FAIrelease);
532 $ret = array();
533 foreach($data as $entry){
534 if($entry['TYPE'] == "ENTRY"){
535 $ret[] = $entry['NAME'];
536 }
537 }
538 return($ret);
539 }
542 /*! \brief Returns all folder an entries for the selected release
543 @return Array Returns the complete menu structure for the given array.
544 */
545 function _get_entries_for_release($release,$cur = NULL)
546 {
547 $all = $this->_get_all_entries();
548 $key = $this->_get_release_key($release);
549 if(isset($all[$key]) && count($all[$key]['ENTRIES'])){
550 $res = $this->_get_all_entries(TRUE,TRUE,$all[$key]['ENTRIES']);
551 return($res);
552 }
553 return(array());
554 }
557 /*! \brief Save the currently edited entry
558 */
559 function _save_entry_edit()
560 {
561 $all = $this->_get_all_entries();
562 $entry = $this->edit_entry;
563 $r_entry= &$all[$entry['UNIQID']];
565 if($entry['TYPE'] == "ENTRY"){
566 $r_entry['PARAMETER'] = $this->app_parameter;
567 $r_entry['STATUS'] = "EDITED";
568 }
569 if($entry['TYPE'] == "FOLDER"){
570 $r_entry['ICON'] = $this->edit_entry['ICON'];
571 $r_entry['STATUS'] = "EDITED";
572 }
573 $this->dialog = FALSE;
574 $this->edit_entry = array();
575 }
578 /*! \brief prepare the entry with the given ID, to be edited.
579 Read application Parameter from ldap.
580 */
581 function _edit_entry_edit($id)
582 {
583 $all = $this->_get_all_entries();
584 $entry = $all[$id];
586 $this->app_parameter = array();
587 if($entry['TYPE'] == "ENTRY"){
588 $found = FALSE;
589 foreach($this->apps as $id => $app){
591 if($app['cn'][0] == $entry['NAME']){
592 $found = TRUE;
593 break;
594 }
595 }
596 if($found){
598 /* Create a list of editable parameter */
599 if(isset($app['gosaApplicationParameter'])){
600 for($i = 0 ; $i < $app['gosaApplicationParameter']['count'] ; $i++) {
601 $para = $app['gosaApplicationParameter'][$i];
602 $tmp = split(":",$para);
603 $this->app_parameter[$tmp[0]] = $tmp[1];
604 }
605 }
607 /* Overwrite parameters with entry parameters */
608 foreach($entry['PARAMETER'] as $name => $value){
609 $this->app_parameter[$name] = $value;
610 }
612 $this->dialog = TRUE;
613 $this->edit_entry = $entry;
614 }
615 }
617 if($entry['TYPE'] == "FOLDER"){
618 $this->dialog = TRUE;
619 $this->edit_entry = $entry;
620 }
621 }
624 /*! \brief Removes the menu structure from ldap
625 */
626 function remove_from_parent()
627 {
628 $ldap = $this->config->get_ldap_link();
629 $ldap->cd($this->dn);
630 $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=FAIbranch)(objectClass=gotoMenuEntry))",$this->dn,array("*"));
631 $a_remove = array();
632 while($attrs = $ldap->fetch()){
633 $a_remove[] = $attrs['dn'];
634 }
635 foreach($a_remove as $remove){
636 $ldap->rmdir_recursive($remove);
637 if (!$ldap->success()){
638 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_DEL, get_class()));
639 }
640 }
641 $this->_load_menu_structure();
642 }
645 function check()
646 {
647 $message = plugin::check();
648 return($message);
649 }
652 /*! \brief Create missing releases, if there is a release selected \
653 that is currently not part of the menu structure \
654 then create this entry
655 */
656 function _check_missing_release($release)
657 {
658 $release_info = $this->Releases[$release];
660 $parent_id = $this->a_Structure[0]['UNIQID'];
661 $cur = &$this->a_Structure[0]['ENTRIES'];
662 for($i = 0 ; $i < count($release_info['parts']) ; $i ++){
663 $part = $release_info['parts'][$i];
664 $found = FALSE;
665 foreach($cur as $key => $name){
666 if($name['NAME'] == $part){
667 $parent_id = $cur[$key]['UNIQID'];
668 $cur = &$cur[$key]['ENTRIES'];
670 $found =TRUE;
671 break;
672 }
673 }
674 if(!$found){
675 $release = array();
676 $release['UNIQID'] = uniqid();
677 $release['PARENT'] = $parent_id;
678 $release['NAME'] = $part;
679 $release['TYPE'] = "RELEASE";
680 $release['ENTRIES']= array();
681 $release['STATUS'] = "ADDED";
682 $release['FAIstate'] = $release_info['FAIstate'];
683 $cur[] = $release;
684 $i --;
685 }
686 }
687 }
691 /*! \brief Moves a given object ($id) in a specified direction ($dir).
692 @param String The object ID of the object we want to move
693 @dir String Move "up" or "down"
694 */
695 function _move_entry($id,$dir)
696 {
697 $all = $this->_get_all_entries();
698 if($dir == "down"){
699 $to = $this->_get_next($id);
700 }
701 if($dir == "up"){
702 $to = $this->_get_last($id);
703 }
705 if(!$to){
706 return;
707 }
709 $o_to = $all[$to];
710 $o_from = $all[$id];
712 if($o_to['PARENT'] == $o_from['UNIQID'] && $dir == "down"){
713 $to = $this->_get_next($to,$o_from['PARENT']);
714 $o_to = $all[$to];
715 }
717 /* Target is ENTRY && same BASE, just switch */
718 if($o_to['PARENT'] == $o_from['PARENT'] ){
719 $parent = $all[$o_to['PARENT']];
720 $pos = 0;
721 foreach($parent['ENTRIES'] as $entry){
722 $pos ++;
723 if($entry['UNIQID'] == $to){
724 break;
725 }
726 }
727 if($dir == "up" && $pos > 0){
728 $pos --;
729 }
730 $this->_add_entry($parent['UNIQID'],$o_from,$pos);
731 $this->_remove_entry_id($id);
732 return(TRUE);
733 }
734 return(FALSE);
735 }
739 /*! \brief Returns the railing object ID of the given object.
740 @return String The id of the trailing object.
741 */
742 function _get_last($id)
743 {
744 $all_l = array_reverse($this->_get_entries_for_release($this->FAIrelease));
745 for($i = 0 ; $i < count($all_l) ; $i ++){
746 if(isset($all_l[$i]['UNIQID']) && $all_l[$i]['UNIQID'] == $id){
747 $i++;
748 break;
749 }
750 }
751 while(isset($all_l[$i]) && !in_array($all_l[$i]['TYPE'],array("ENTRY","FOLDER","CLOSE","OPEN")) && $i < count($all_l)){
752 $i++;
753 }
755 if(!isset($all_l[$i])){
756 return(FALSE);
757 }
759 if(in_array($all_l[$i]['TYPE'],array("CLOSE","OPEN"))){
760 return($all_l[$i]['PARENT']);
761 }
763 return($all_l[$i]['UNIQID']);
764 }
767 /*! \brief Returns the following object ID of the given object.
768 @return String The id of the following object.
769 */
770 function _get_next($id,$parent = 0)
771 {
772 $all_l = $this->_get_entries_for_release($this->FAIrelease);
773 for($i = 0 ; $i < count($all_l) ; $i ++){
774 if(isset($all_l[$i]['UNIQID']) && $all_l[$i]['UNIQID'] == $id){
775 $i++;
776 break;
777 }
778 }
779 if($parent != 0){
780 while(isset($all_l[$i]) && $all_l[$i]['PARENT'] != $parent){
781 $i++;
782 }
783 }else{
784 while(isset($all_l[$i]) && !in_array($all_l[$i]['TYPE'],array("ENTRY","FOLDER")) && $i < count($all_l)){
785 $i++;
786 }
787 }
788 if(!isset($all_l[$i])){
789 return(FALSE);
790 }
791 if(in_array($all_l[$i]['TYPE'],array("CLOSE","OPEN"))){
792 return($all_l[$i]['PARENT']);
793 }
794 return($all_l[$i]['UNIQID']);
795 }
800 /* !\brief Handle ui POSTS, like sort up/down/delete
801 */
802 function save_object()
803 {
804 foreach($_POST as $name => $value){
806 if(preg_match("/^menu_copy_/",$name)){
807 $this->copied_release = $this->FAIrelease;
808 break;
809 }
810 if(preg_match("/^menu_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'];
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 }
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 }
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 }
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 }
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";
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;
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 }
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;
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{
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();
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 }
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 }
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 }
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 }
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);
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();
1405 /* Get posts */
1406 foreach(array("apps") as $attr){
1407 if(isset($_POST['use_'.$attr])) {
1408 $this->multi_boxes[] = $attr;
1409 }
1410 }
1411 }
1412 }
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 }
1433 }
1434 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1435 ?>