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