1 <?php
2 class application extends plugin
3 {
4 /* application attributes */
5 var $cn= "";
6 var $description= "";
7 var $base= "";
8 var $gosaApplicationExecute= "";
9 var $gosaApplicationName= "";
10 var $gosaApplicationFlags= "";
11 var $gosaApplicationIcon= "";
12 var $gotoLogonScript ="";
13 var $iconData;
14 var $view_logged = FALSE;
16 /* Headpage attributes */
17 var $last_sorting= "invalid";
18 var $applications= array();
20 /* attribute list for save action */
21 var $attributes= array("cn", "description", "gosaApplicationExecute", "gosaApplicationName","gosaApplicationIcon",
22 "gosaApplicationFlags","gotoLogonScript");
24 var $objectclasses= array("top", "gosaApplication");
26 function application (&$config, $dn= NULL, $parent= NULL)
27 {
28 plugin::plugin ($config, $dn, $parent);
30 /* Load icon */
31 $ldap= $config->get_ldap_link();
32 if ($dn != 'new'){
33 $this->iconData= $ldap->get_attribute($dn, "gosaApplicationIcon");
34 $this->saved_attributes['gosaApplicationIcon'] = $this->iconData;
35 }
36 if ($this->iconData == ""){
37 $this->set_picture("");
38 }
39 session::set('binary',$this->iconData);
40 session::set('binarytype',"image/jpeg");
41 $this->gosaApplicationIcon= $this->iconData;
43 /* This is always an account */
44 $this->is_account= TRUE;
46 if ($this->dn == "new"){
47 if(session::is_set('CurrentMainBase')){
48 $this->base = session::get('CurrentMainBase');
49 }else{
50 $ui= get_userinfo();
51 $this->base= dn2base($ui->dn);
52 }
53 } else {
54 $this->base= preg_replace ("/^[^,]+,".get_ou('applicationou')."/", "", $this->dn);
55 }
56 }
59 function generateTemplate()
60 {
61 $str= "# This code is part of GOsa (https://gosa.gonicus.de)\n#\n";
63 $values = array();
64 $names = array();
65 if($this->parent->by_object['applicationParameters']->is_account){
66 $names = $this->parent->by_object['applicationParameters']->option_name;
67 $values = $this->parent->by_object['applicationParameters']->option_value;
68 }
70 if (count($names)){
71 $str .="# This plugin handles these environment variables:\n";
72 } else {
73 $str .="# This plugin handles no environment variables.\n";
74 }
76 foreach($names as $index => $name){
78 // Fix length
79 for($i = strlen($name) ; $i < 30 ; $i++){
80 $name= $name." ";
81 }
82 if((isset($values[$index]))&&(!empty($values[$index]))){
83 $str.= "# ".$name."\t(e.g. '".$values[$index]."')\n";
84 }else{
85 $str.= "# ".$name."\t("._("no example").")\n";
86 }
87 }
88 $str .= "#\n".
89 "# Don't remove the following tag, it is used for header update.\n".
90 "### END HEADER ###";
92 return($str);
93 }
95 function execute()
96 {
97 /* Call parent execute */
98 plugin::execute();
100 /* Log view */
101 if($this->is_account && !$this->view_logged){
102 $this->view_logged = TRUE;
103 new log("view","application/".get_class($this),$this->dn);
104 }
106 $smarty= get_smarty();
108 $tmp = $this->plInfo();
109 foreach($tmp['plProvidedAcls'] as $name => $translation){
110 $smarty->assign($name."ACL",$this->getacl($name));
111 }
113 /* Do we represent a valid group? */
114 if (!$this->is_account && $this->parent === NULL){
115 $display= "<img alt=\"\" src=\"images/small-error.png\" align=\"middle\"> <b>".
116 msgPool::noValidExtension(_("application"))."</b>";
117 return ($display);
118 }
120 /* Download requested */
121 foreach($_POST as $name => $value){
122 if(preg_match("/^downloadScript/",$name)){
123 session::set('binary',$this->gotoLogonScript);
124 session::set('binarytype',"octet-stream");
125 session::set('binaryfile',$this->cn.".gosaApplication");
126 header("location: getbin.php ");
127 exit();
128 }
129 }
131 /* Reassign picture data, sometimes its corrupt cause we started a download of application scripts */
132 session::set('binary',$this->iconData);
133 session::set('binarytype',"image/jpeg");
135 $smarty->assign("rand", rand(0, 10000));
136 $head = $this->generateTemplate();
137 $this->gotoLogonScript= $this->generateTemplate().preg_replace('/.*### END HEADER ###/s', '', $this->gotoLogonScript);
139 if((isset($_POST['upLoad']))&&(isset($_FILES['ScriptFile']))){
140 $str = file_get_contents($_FILES['ScriptFile']['tmp_name']);
141 $this->gotoLogonScript = $str;
142 }
144 /* Fill templating stuff */
145 $smarty->assign("cn", $this->cn);
146 if(!$this->is_release()){
147 $smarty->assign("bases", $this->get_allowed_bases());
148 }else{
149 $smarty->assign("bases", array());
150 }
151 if ($this->dn == "new"){
152 $smarty->assign("selectmode", "");
153 $smarty->assign("namemode", "");
154 } else {
155 $smarty->assign("namemode", "readonly");
156 $smarty->assign("selectmode", "disabled");
157 }
159 /* Base select dialog */
160 $once = true;
161 foreach($_POST as $name => $value){
162 if(preg_match("/^chooseBase/",$name) && $once){
163 $once = false;
164 $this->dialog = new baseSelectDialog($this->config,$this,$this->get_allowed_bases());
165 $this->dialog->setCurrentBase($this->base);
166 }
167 }
169 /* Dialog handling */
170 if(is_object($this->dialog)){
171 /* Must be called before save_object */
172 $this->dialog->save_object();
174 if($this->dialog->isClosed()){
175 $this->dialog = false;
176 }elseif($this->dialog->isSelected()){
178 /* Just allow selection valid bases */
179 $tmp = $this->get_allowed_bases();
180 if(isset($tmp[$this->dialog->isSelected()])){
181 $this->base = $this->dialog->isSelected();
182 }
183 $this->dialog= false;
184 }else{
185 return($this->dialog->execute());
186 }
187 }
189 /* Get random number for pictures */
190 srand((double)microtime()*1000000);
191 $smarty->assign("rand", rand(0, 10000));
193 /* Variables */
194 foreach(array("description", "gosaApplicationExecute", "gosaApplicationName","cn") as $val){
195 $smarty->assign($val, $this->$val);
196 }
198 /* Checkboxes */
199 foreach (array("G" => "exec_for_groupmembers", "O" => "overwrite_config",
200 "L" => "place_on_kicker",
201 "D" => "place_on_desktop", "M" => "place_in_startmenu") as $key => $val){
202 if (preg_match("/$key/", $this->gosaApplicationFlags)){
203 $smarty->assign("$val", "checked");
204 } else {
205 $smarty->assign("$val", "");
206 }
207 }
209 $smarty->assign("isReleaseApplikation" ,$this->is_release());
210 $smarty->assign("gotoLogonScript",htmlentities($this->gotoLogonScript, ENT_COMPAT, 'UTF-8'));
211 $smarty->assign("base_select", $this->base);
212 /* Show main page */
213 return($smarty->fetch (get_template_path('generic.tpl', TRUE)));
214 }
217 function remove_from_parent()
218 {
219 restore_error_handler();
221 /* Parse release out of object dn */
222 $release = preg_replace("/".get_ou("applicationou").normalizePreg($this->base)."$/","",$this->dn);
223 $release = preg_replace("/^cn=[^,]+,/","",$release);
225 /* Get a list of all groups
226 */
227 $groups = array();
228 $ldap= $this->config->get_ldap_link();
229 $ldap->cd($this->config->current['BASE']);
230 $ldap->search("(objectClass=posixGroup)",array("dn"));
231 while($attrs = $ldap->fetch()){
232 $groups[$attrs['dn']] = array();
233 }
235 /* Check if there are groups, useing this application
236 */
237 $found = array();
238 foreach($groups as $group => $data){
239 $ldap->cd($release.$group);
240 $ldap->search("(objectClass=gotoMenuEntry)",array("dn"));
241 while($attrs = $ldap->fetch()){
242 $info = preg_replace("/".normalizePreg($release.$group)."$/","",$attrs['dn']);
243 if(preg_match("/^cn=".$this->cn."/",$info) && !preg_match("/ou=[^,]+,/",$info)){
244 $found[] = $attrs['dn'];
245 }
246 }
247 }
249 /* Create an error message an skip remove, if
250 this application is still in use.
251 */
252 if(count($found)){
253 msg_dialog::display(_("Error"), sprintf(_("Cannot remove application - it is still in use by these objects: %s"), "<br>".msgPool::buildList($found)), ERROR_DIALOG);
254 return(FALSE);
255 }
257 $ldap->rmDir($this->dn);
258 new log("remove","application/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());
259 if (!$ldap->success()){
260 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_DEL, get_class()), ERROR_DIALOG);
261 }
263 /* Optionally execute a command after we're done */
264 $this->handle_post_events("remove");
266 /* Delete references to object groups */
267 $ldap->cd ($this->config->current['BASE']);
268 $ldap->search ("(&(objectClass=gosaGroupOfNames)(member=".LDAP::prepare4filter($this->dn)."))", array("cn"));
269 while ($ldap->fetch()){
270 $og= new ogroup($this->config, $ldap->getDN());
271 unset($og->member[$this->dn]);
272 $og->save ();
273 if (!$ldap->success()){
274 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, 0, get_class()), ERROR_DIALOG);
275 }
276 }
277 }
280 /* Save data to object */
281 function save_object()
282 {
283 if (isset($_POST['cn'])){
285 /* Create a base backup and reset the
286 base directly after calling plugin::save_object();
287 Base will be set seperatly a few lines below */
288 $base_tmp = $this->base;
289 plugin::save_object();
290 $this->base = $base_tmp;
292 /* Save attributes */
293 parent::save_object();
295 /* Save application flags */
296 $flag= "";
297 if (isset($_POST['exec_for_groupmembers']) && $_POST['exec_for_groupmembers'] == 1){
298 $flag.= "G";
299 }
300 if (isset($_POST['place_on_desktop']) && $_POST['place_on_desktop'] == 1){
301 $flag.= "D";
302 }
303 if (isset($_POST['place_on_kicker']) && $_POST['place_on_kicker'] == 1){
304 $flag.= "L";
305 }
306 if (isset($_POST['place_in_startmenu']) && $_POST['place_in_startmenu'] == 1){
307 $flag.= "M";
308 }
309 if (isset($_POST['overwrite_config']) && $_POST['overwrite_config'] == 1){
310 $flag.= "O";
311 }
312 if ($this->acl_is_writeable("gosaApplicationFlags")){
313 $this->gosaApplicationFlags= "[$flag]";
314 }
316 /* Remove current picture */
317 if(isset($_POST['remove_picture'])){
318 $this->set_picture("");
319 }
321 /* Check for picture upload */
322 if (isset($_FILES['picture_file']['name']) && $_FILES['picture_file']['name'] != ""){
324 if (!is_uploaded_file($_FILES['picture_file']['tmp_name'])) {
325 msg_dialog::display(_("Error"), msgPool::incorrectUpload(), ERROR_DIALOG);
326 }
328 if (!function_exists("imagick_blob2image")){
329 /* Get temporary file name for conversation */
330 $fname = tempnam (TEMP_DIR, "GOsa");
332 /* Open file and write out photoData */
333 $fp = fopen ($fname, "w");
334 fwrite ($fp, $_FILES['picture_file']['tmp_name']);
335 fclose ($fp);
337 /* Build conversation query. Filename is generated automatically, so
338 we do not need any special security checks. Exec command and save
339 output. For PHP safe mode, you'll need a configuration which respects
340 image magick as executable... */
341 $query= "convert -size 48x48 $fname -resize 48x48 +profile \"*\" -";
342 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__, $query, "Execute");
344 /* Read data written by convert */
345 $output= "";
346 $sh= popen($query, 'r');
347 while (!feof($sh)){
348 $output.= fread($sh, 4096);
349 }
350 pclose($sh);
352 unlink($fname);
353 } else {
355 /* Load the new uploaded Photo */
356 if(!$handle = imagick_ReadImage($_FILES['picture_file']['tmp_name'])){
357 msg_dialog::display(_("Error"), msgPool::incorrectUpload(_("no read permission")), ERROR_DIALOG);
358 }
360 /* Resizing image to 147x200 and blur */
361 if(!imagick_resize($handle,48,48,IMAGICK_FILTER_GAUSSIAN,0)){
362 msg_dialog::display(_("Error"), msgPool::incorrectUpload(_("cannot resize image")), ERROR_DIALOG);
363 }
365 /* Converting image to JPEG */
366 if(!imagick_convert($handle,"PNG")) {
367 msg_dialog::display(_("Error"), msgPool::incorrectUpload(_("cannot convert image")), ERROR_DIALOG);
368 }
370 if(!imagick_writeimage($handle,$_FILES['picture_file']['tmp_name'])){
371 msg_dialog::display(_("Error"), msgPool::incorrectUpload(sprintf(_("cannot save image to '%s'"), $_FILES['picture_file']['tmp_name'])), ERROR_DIALOG);
372 }
374 imagick_free($handle);
375 }
377 /* Activate new picture */
378 $this->set_picture($_FILES['picture_file']['tmp_name']);
379 }
381 if(!$this->is_release()){
382 $tmp = $this->get_allowed_bases();
383 if(isset($_POST['base'])){
384 if(isset($tmp[$_POST['base']])){
385 $this->base= $_POST['base'];
386 }
387 }
388 }
389 }
390 }
393 /* Check values */
394 function check()
395 {
396 /* Call common method to give check the hook */
397 $message= plugin::check();
399 if(!preg_match("#^/#",$this->gosaApplicationExecute)){
400 $message[]=msgPool::invalid(_("Execute path"),"","","/some/path");
401 }
403 /* Permissions for that base? */
404 if ($this->base != ""){
405 $new_dn= "cn=".$this->cn.",".get_ou('applicationou').$this->base;
406 } else {
407 $new_dn= $this->dn;
408 }
411 if($this->dn == "new"){
412 $this->set_acl_base($this->base);
413 }
415 /* All required fields are set? */
416 if ($this->cn == ""){
417 $message[]= msgPool::required(_("Name"));
418 }
420 if(preg_match("/[^a-z0-9]/",$this->cn)) {
421 $message[]=msgPool::invalid(_("Name"),$this->cn,"/^[a-z0-9]*$/");
422 }
424 if ($this->gosaApplicationExecute == ""){
425 $message[]= msgPool::required(_("Execute"));
426 }
428 /* Check for existing application */
429 $ldap= $this->config->get_ldap_link();
430 $ldap->cd($this->config->current["BASE"]);
432 $tmp = $this->config->search("faiManagement", "CLASS",array('menu','tabs'));
434 if($this->is_release()){
435 $base = $this->parent->parent->app_release;
436 }else{
437 $base = get_ou('applicationou').$this->base;
438 }
440 $ldap->ls("(&(objectClass=gosaApplication)(cn=".$this->cn."))",$base,array("cn"));
441 if($ldap->count()){
442 $attrs = $ldap->fetch();
443 if($this->dn != $attrs['dn']) {
444 $message[]= msgPool::duplicated("cn");
445 }
446 }
447 return $message;
448 }
451 /* Save to LDAP */
452 function save()
453 {
454 /* Get application script without header part, to check if we must save the script itself */
455 $script = preg_replace('/.*### END HEADER ###/s', '', $this->gotoLogonScript);
457 plugin::save();
458 $this->attrs["gosaApplicationIcon"]= $this->gosaApplicationIcon;
460 /* Write back to ldap */
461 $ldap= $this->config->get_ldap_link();
462 $ldap->cat($this->dn, array('dn'));
464 $a= $ldap->fetch();
465 if (count($a)){
467 /* Remove gotoLogonScript if it is empty */
468 if(empty($script)) {
469 $this->attrs['gotoLogonScript'] = array();
470 }
472 $ldap->cd($this->dn);
473 $this->cleanup();
474 $ldap->modify ($this->attrs);
475 $this->handle_post_events("modify");
476 new log("modify","application/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());
477 } else {
479 /* Remove gotoLogonScript if it is empty */
480 if(empty($script)) {
481 unset($this->attrs['gotoLogonScript']);
482 }
484 $ldap->cd($this->config->current['BASE']);
485 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $this->dn));
486 $ldap->cd($this->dn);
487 $ldap->add($this->attrs);
488 new log("create","application/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());
489 $this->handle_post_events("add");
490 }
491 if (!$ldap->success()){
492 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, 0, get_class()), ERROR_DIALOG);
493 }
494 }
497 function is_release()
498 {
499 if(isset($this->parent->parent)){
500 return($this->parent->parent->IsReleaseManagementActivated());
501 }else{
502 /* Check if we should enable the release selection */
503 $tmp = $this->config->search("faiManagement", "CLASS",array('menu','tabs'));
504 if(!empty($tmp)){
505 return(true);
506 }
507 }
508 return(FALSE);
509 }
512 function set_picture($filename)
513 {
514 if (!is_file($filename)){
515 $filename= "./images/default_icon.png";
516 $this->gosaApplicationIcon= "*removed*";
517 }
519 if (file_exists($filename)){
520 $fd = fopen ($filename, "rb");
521 $this->iconData= fread ($fd, filesize ($filename));
522 session::set('binary',$this->iconData);
523 session::set('binarytype',"image/jpeg");
524 $this->gosaApplicationIcon= $this->iconData;
526 fclose ($fd);
527 }
528 }
530 function getCopyDialog()
531 {
532 $vars = array("cn");
534 $str ="<h2>"._("Application settings")."</h2>
535 <table>
536 <tr>
537 <td>".
538 _("Application name").
539 "</td>
540 <td>
541 <input id='gosaApplicationName' name='cn' size='35' maxlength='60'
542 value='".$this->cn."'
543 title='"._("Application name to be displayed (i.e. below icons)")."'>
544 </td>
545 </tr>
546 </table>";
547 $ret = array();
548 $ret['status'] = "";
549 $ret['string'] = $str;
550 return($ret);
551 }
553 function saveCopyDialog()
554 {
555 if(isset($_POST['cn'])){
556 $this->cn = $_POST['cn'];
557 }
558 }
561 function PrepareForCopyPaste($source)
562 {
563 plugin::PrepareForCopyPaste($source);
564 $source_o = new application($this->config,$source['dn']);
565 $this->gosaApplicationIcon = $source_o->gosaApplicationIcon;
566 }
569 /* Return plugin informations for acl handling
570 #FIXME FAIscript seams to ununsed within this class... */
571 static function plInfo()
572 {
573 return (array(
574 "plShortName" => _("Generic"),
575 "plDescription" => _("Application generic"),
576 "plSelfModify" => FALSE,
577 "plDepends" => array(),
578 "plPriority" => 0,
579 "plSection" => array("administration"),
580 "plCategory" => array("application" => array("description" => _("Application"),
581 "objectClass" => "gosaApplication")),
582 "plProvidedAcls"=> array(
583 "cn" => _("Name"),
584 "base" => _("Base"),
585 "description" => _("Description"),
586 "gosaApplicationExecute" => _("Execute"),
587 "gosaApplicationName" => _("Name"),
588 "gosaApplicationIcon" => _("Icon"),
589 "gosaApplicationFlags" => _("Flag"),
590 "gotoLogonScript" => _("Script content"),
592 "exec_for_groupmembers" => _("Only executable for members"), // G
593 "place_on_desktop" => _("Place icon on members desktop"), // D
594 "place_on_kicker" => _("Place entry in members launch bar"), // L
595 "place_in_startmenu" => _("Place entry in members startmenu"), // M
596 "overwrite_config" => _("Replace user configuration on startup")) // O
597 ));
598 }
599 }
600 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
601 ?>