1 <?php
3 class printerPPDDialog extends plugin
4 {
5 /* CLI vars */
6 var $cli_summary = "Manage server basic objects";
7 var $cli_description = "Some longer text\nfor help";
8 var $cli_parameters = array("eins" => "Eins ist toll", "zwei" => "Zwei ist noch besser");
10 /* attribute list for save action */
11 var $ignore_account = TRUE;
12 var $attributes = array("cn");
13 var $objectclasses = array("whatever");
15 /* PPD Handling */
16 var $selectedPPD = false; // e.g. /vendor/device.ppd
17 var $ppdManager = false; // new ppdManager;
18 var $ppdConfig = false; // $this->ppdManager->loadProperties($this->selectedPPD['link']);
19 var $ppdList = array(); // Contains all Printer models
20 var $ppdListHeader = array(); // Contains all printer vendors
22 /* Paths */
23 var $pathToPPD = ""; // Base path, defined in gosa.conf e.g. "/var/spool/ppd/"
24 var $pathToModified = "modified/"; // used to store the modified ppds
26 /* Object Info */
27 var $cn = "" ; // Used to tag the ppds modified by the printer object,
29 /* If there is already a ppd file for the same type of printer,
30 * remember the path to ppd file and display a dialog which allows
31 * to overwrite the current ppd file.
32 */
33 var $add_ppd_later = "";
34 var $add_later_msg_dialog = NULL;
36 function printerPPDDialog (&$config, $dn= NULL, $ppdfile=NULL )
37 {
38 plugin::plugin ($config, $dn);
39 $this->depselect = $this->config->current['BASE'];
41 /* Get PPD path and remove double //, and add trailing / */
42 $config = session::get('config');
43 if(isset($config->data['MAIN']['PPD_PATH'])){
44 $this->pathToPPD = $config->data['MAIN']['PPD_PATH'];
45 $this->pathToPPD= preg_replace("/\/\//", "/", $this->pathToPPD);
46 if(!preg_match("/\/$/",$this->pathToPPD)){
47 $this->pathToPPD = $this->pathToPPD."/";
48 }
49 }else{
50 $this->pathToPPD = "";
51 }
53 /* It seams that we have an existing PPD path, so go on */
54 if(!((!is_dir($this->pathToPPD))||(empty($this->pathToPPD)))){
56 /* Load all available PPD files and sort them into an array */
57 $this->ppdManager= new ppdManager($this->pathToPPD);
58 $this->getPrinterReload ();
60 /* The user has already a valid PPD assigned
61 * Get some informations about this PPD
62 * and set it as selected.
63 * The ppdpath ['link'] should be relative from .../ppd/modified/
64 * e.g. "/Compaq/Compaq-J1200.ppd" */
65 if(($ppdfile!== NULL)&&(strlen($ppdfile)>0)){
66 $ppdfile = preg_replace("#".$this->pathToModified."#","",$ppdfile);
67 if(!file_exists($this->pathToPPD.$this->pathToModified.$ppdfile)){
68 print_red(sprintf(_("Can't open '%s', ppd settings resetted."),$ppdfile));
69 }else{
70 $res = $this->ppdManager->loadDescription($this->pathToPPD.$this->pathToModified.$ppdfile);
71 if($res){
72 $tmp = split("\n",$res);
73 $tmp3 = array();
74 $tmp3['name'] = trim(preg_replace("/^\-/","",trim($tmp[1])));
75 $tmp3['link'] = $ppdfile;
76 $tmp3['ppd'] = $res;
77 }
78 $this->selectedPPD = $tmp3;
79 }
80 }
81 }
82 }
85 function execute()
86 {
87 /* Call parent execute */
88 plugin::execute();
90 /* Fill templating stuff */
91 $display= "";
92 $smarty= get_smarty();
93 $smarty->assign("ppdString", _("Can't get ppd informations."));
94 $smarty->assign("showOptions", "");
96 /* Check these paths */
97 $paths = array($this->pathToPPD, $this->pathToPPD.$this->pathToModified);
99 /* If one of our required paths is not available, stop here and display some info */
100 foreach($paths as $path){
102 /* Check if path is write/readable*/
103 $is_r = @is_readable($path);
104 if(((!is_dir($path))||(empty($path)) || (!$is_r)) && (!@mkdir($path))){
105 print_red(sprintf(_("The specified path '%s' which results from PPD_PATH in your gosa.conf is invalid, can't read/write any ppd informations."),$path));
106 /* Print out template */
107 $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
108 return($display);
109 }
110 }
112 // PPD selection / upload / dialog handling
114 /* Is there a new PPD file uploaded ? */
115 if((isset($_FILES['NewPPDFile']))&&(isset($_POST['SubmitNewPPDFile']))){
116 $file = ($_FILES['NewPPDFile']);
117 if($file['size'] != 0 ){
118 if($name = $this->AddPPD($file['tmp_name'])){
119 $this->SelectPPD($name);
120 }
121 }else{
122 print_red(_("Please specify a valid ppd file."));
123 }
124 }
126 /* Overwrite existing PPD file and select it as currently used for this object */
127 if(is_object($this->add_later_msg_dialog) && ($this->add_later_msg_dialog->is_confirmed()) && $this->add_ppd_later != ""){
128 if($name = $this->AddPPD($this->add_ppd_later,TRUE)){
129 $this->SelectPPD($name);
130 }
131 $this->add_ppd_later = "";
132 $this->add_later_msg_dialog = NULL;
133 }
135 /* Open a dialog that allow us to select different PPDs */
136 if(isset($_POST['SelectPPD'])){
137 $this->dialog= new printerPPDSelectionDialog($this->config,$this->dn,$this->ppdList,$this->ppdListHeader,$this->selectedPPD);
138 }
140 /* The selection dialog fpr PPDs is canceled */
141 if(isset($_POST['ClosePPDSelection'])){
142 unset($this->dialog);
143 $this->dialog=FALSE;
144 }
146 /* Div Selection */
147 if((isset($_GET['act']))&&($_GET['act']=="use")){
148 $this->SelectPPD(base64_decode($_GET['id']));
149 unset($this->dialog);
150 $this->dialog=FALSE;
152 }
154 /* if a dialog is open, print the dialog instead of this class */
155 if(is_object($this->dialog)){
156 $display = $this->dialog->execute();
157 return($display);
158 }
160 // ENDE PPD selection / upload / dialog handling
162 /* Give smarty the information it needs */
163 $smarty->assign("ppdString" ,$this->getPPDInformation());
164 $tmp= $this->generateProperties();
165 if ($tmp == ""){
166 $smarty->assign("showOptions", 0);
167 } else {
168 $smarty->assign("showOptions", 1);
169 $smarty->assign("properties",$this->generateProperties());
170 }
172 /* Print out template */
173 $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
174 return($display);
175 }
178 /* Select PPD */
179 function SelectPPD($name)
180 {
181 /* Replace base path we don't need it here
182 The path we need looks like this : "/Vendor/ModellName.ppd";
183 thats all */
184 $name = preg_replace("#".$this->pathToPPD."#","",$name);
186 /* Intialise some base vars */
187 $AbsoluteSourceName = $this->pathToPPD.$name;
188 $AbsoluteDestinationPath = $this->pathToPPD.$this->pathToModified;
189 $Vendor = ""; // Vendor
190 $Name = ""; // Name
191 $Modell = ""; // Modell
192 $PrinterName = ""; // The new name of the printer
193 $PPDName = "";
195 /* Force reload of config dialog */
196 $this->ppdConfig = false;
197 $this->selectedPPD['link'] = false;
199 /* Get PPD informations and set vendor / modell / name */
200 if((!file_exists($AbsoluteSourceName)) || (!is_readable($AbsoluteSourceName))){
201 print_red(sprintf(_("Can't select PPD file '%s', the file is not readable"),$AbsoluteSourceName));
202 return;
203 }
204 $res = $this->ppdManager->loadDescription($AbsoluteSourceName);
205 if($res){
206 $tmp = split("\n",$res);
207 $Name = trim(preg_replace("/^\-/","",trim($tmp[1])));
208 $Vendor = trim($tmp[0]);
209 $Model = trim(preg_replace("/".$Vendor."/","",$Name));
210 }
212 $PrinterName = $this->cn."-".preg_replace("/[^a-z0-9-_\.]/i","_",$Name);
213 $PPDName = $Vendor."/".$PrinterName.".ppd";
215 /* Create the vendors path, if it doesn't exists already */
216 if(!is_dir($AbsoluteDestinationPath.$Vendor)){
217 if(!(@mkdir($AbsoluteDestinationPath.$Vendor))){
218 print_red(sprintf(_("Can't create folder '%s' for the uploaded ppd file."),$AbsoluteDestinationPath.$Vendor));
219 return(false);
220 }
221 }
223 /* Create destination file handle */
224 $fp = @fopen($AbsoluteDestinationPath.$PPDName,"w+");
225 if(!$fp){
226 print_red(sprintf(_("Can't create file '%s' to store modifed ppd informations."),$AbsoluteDestinationPath.$PPDName));
227 return(false);
228 }
230 $str = file_get_contents($AbsoluteSourceName);
231 fputs($fp,$str);
232 @fclose($fp);
234 //$this->ppdManager->updateAttribute($filename,"NO_SECTION","ModelName",$printerName);
236 $tmp3['link'] =$PPDName;
237 $this->selectedPPD = $tmp3;
238 $this->getPrinterReload();
239 return($PPDName);
240 }
243 /* This function adds a new ppd file to the list of available ppds.
244 All required paths and files will be created
245 $_PathOnHdd e.g. = /tmp/PHP_tmpfile213452 */
246 function AddPPD($_PathOnHdd,$overwrite = FALSE)
247 {
248 /* Check if file exists && is readable */
249 if((!is_file($_PathOnHdd)) || (!is_readable($_PathOnHdd))){
250 print_red(sprintf(_("Can't add new ppd file, the source file '%s' is not accessible."),$_PathOnHdd));
251 return(false);
252 }
254 /* Reload list to detect changes e.g. a file has been deleted */
255 $this->getPrinterReload();
257 /* Get Description from ppd, & parse out some informations */
258 $res = @$this->ppdManager->loadDescription($_PathOnHdd);
259 if($res){
260 $tmp = split("\n",$res);
261 $name = trim(preg_replace("/^\-/","",trim($tmp[1])));
262 $vendor = trim($tmp[0]);
263 $model = trim(preg_replace("/".$vendor."/","",$name));
264 }
266 /* Check if parse was successfull */
267 if(empty($name) || empty($vendor)){
268 print_red(sprintf(_("The given ppd file '%s' seams to be invalid, can't get any model or vendor informations."),$_PathOnHdd));
269 return(false);
270 }
272 /* Prepare list of ppds */
273 if(!isset($this->ppdList[$vendor])){
274 $this->ppdList[$vendor] = array();
275 }
277 /* Create ppd file and fill in the source contents */
278 $ppdname = $vendor."/".$name.".ppd";
279 $filename = $this->pathToPPD.preg_replace("/[^a-z0-9-_\.\/]/i","_",$ppdname);
280 $filename = $this->pathToPPD.$ppdname;
281 $contents = file_get_contents($_PathOnHdd);
284 /* Check if this ppd already exists */
285 $found = false;
286 foreach($this->ppdList[$vendor] as $key => $val){
287 if(preg_match("/".$model.".*/i",$key)){
288 $found = true;
289 if(!$overwrite){
290 if(!copy($_PathOnHdd,$_PathOnHdd."_back")){
291 print_red(sprintf(_("Can't add new ppd file, the source file '%s' is not accessible."),$_PathOnHdd));
292 }else{
293 $this->add_ppd_later = $_PathOnHdd."_back";
294 $this->add_later_msg_dialog = new msg_dialog(_("Overwrite existing PPD"),
295 _("There is already a ppd file for this kind of printer. Do you want to overwrite it?"),CONFIRM_DIALOG);
296 }
297 return;
298 }
299 }
300 }
302 /* Create the vendors path, if it doesn't exists already */
303 if(!is_dir($this->pathToPPD.$vendor)){
304 if(!(@mkdir($this->pathToPPD.$vendor))){
305 print_red(sprintf(_("Can't create folder '%s' for the uploaded ppd file."),$this->pathToPPD.$vendor));
306 return(false);
307 }
308 }
310 /* Open file handle */
311 $fp = fopen($filename,"w+");
313 /* Check file handle & contents */
314 if(!$fp){
315 print_red(sprintf(_("Can't save file '%s'."),$filename));
316 return;
317 }
318 if(empty($contents)){
319 print_red(_("Uploaded ppd file is empty, can't create new ppd file."));
320 return;
321 }
323 /* Fille file with data */
324 fputs($fp,$contents);
325 @fclose($fp);
327 /* Our job is done here */
328 return($ppdname);
329 }
332 /* This function reloads the list of available printers/vendors
333 $this->ppdListHeader
334 Compaq => 1
335 $this->ppdList
336 Compaq => Compaq IJ1200 => name => Compaq IJ1200
337 link => /var/spool/ppd/Compaq/Compaq-J1200.ppd
338 ppd => Compaq - Co
339 */
340 function getPrinterReload()
341 {
342 if(is_readable($this->pathToPPD)){
343 $tmp = @$this->ppdManager->getPrinterList(true);
345 $this->ppdListHeader = $this->ppdList = array();
347 /* Sort all available files, and create header (Vendor index) */
348 foreach($tmp as $file=>$ppd){
350 if(preg_match("#".$this->pathToModified."#",$file)) continue;
352 $tmp2 = split("\n",$ppd);
353 if(!isset($this->ppdListHeader[$tmp2[0]])){
354 $this->ppdListHeader[$tmp2[0]]=0;
355 }
356 $tmp3['name'] =preg_replace("/^ -/","",$tmp2[1]." - ".$tmp2[2]);
357 $tmp3['link'] =$file;
358 $tmp3['ppd'] =$ppd;
359 $this->ppdListHeader[$tmp2[0]]++;
360 $this->ppdList[$tmp2[0]][preg_replace("/^ -/","",$tmp2[1]." - ".$tmp2[2])]=$tmp3;
361 }
362 }
363 }
366 /* Save all options posted from ppd dialog */
367 function save_object()
368 {
369 if(!((isset($_POST['PPDDisSubmitted'])) && (is_array($this->ppdConfig)))){
370 return;
371 }
373 foreach($this->ppdConfig as $cat => $obj){
374 foreach($obj as $attr => $attributes){
375 if(isset($_POST[base64_encode($attributes['_name'])])){
376 $this->ppdConfig[$cat][$attr]['_default'] = $_POST[base64_encode($attributes['_name'])];
377 }
378 }
379 }
380 }
383 /* Save modified ppd */
384 function save_ppd()
385 {
386 if($this->ppdManager){
387 $this->ppdManager->saveProperties($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'],$this->ppdConfig);
388 }
389 }
392 /* Return selected ppd path, if none is selected then false */
393 function save()
394 {
395 /* return the selected PPD, and in future the selected options too */
396 return($this->pathToModified.$this->selectedPPD['link']);
397 }
400 /* Get Information for a single PPD entry
401 * This will be shown on top of template
402 */
403 function getPPDInformation()
404 {
405 $str = "none";
406 if(!empty($this->selectedPPD)){
407 $str = $this->ppdManager->loadDescription($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link']);
408 }
409 return($str) ;
410 }
413 /* Display all options from the selected ppd file */
414 function generateProperties()
415 {
416 /* Set Headline */
417 $str = "";
418 $feed= "";
420 $s_ppd = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
422 /* If ppd exists and is readable */
423 if((!empty($this->selectedPPD['link']))&&(file_exists($s_ppd))){
425 /* If there is no initial Configuration, load it */
426 if($this->ppdConfig == false){
427 $this->ppdConfig = $this->ppdManager->loadProperties($s_ppd);
428 }
430 /* Create a table */
431 $str .= "<div style='padding-left:30px;'><table summary=''>";
433 /* Input all data to the table */
434 foreach($this->ppdConfig as $cat => $obj){
436 /* Add new category */
437 $str .= "<tr><td colspan='2'>$feed";
438 if ($feed == ""){
439 $feed= "<br>";
440 }
441 $str .= "<b>"._("Section")." '".$cat."' </b><br>";
442 $str .= "</td></tr>";
444 /* Add attributes of the current category */
445 foreach($obj as $attr => $settings){
447 /* Skip all entries beginning with _ */
448 if($attr[0] == "_") continue;
450 /* Prepare data */
451 $values = array();
452 $name = $settings['_name'];
454 if (!isset($settings['_default'])){
455 $default = "";
456 } else {
457 $default = $settings['_default'];
458 }
460 $type = $settings['_type'];
462 /* Add name to table */
463 $str .= "<tr><td style='padding-left:40px;'>\n";
464 $str .= $name."<br>\n";
465 $str .= "</td><td>\n";
467 /* Get all values */
468 foreach( $settings as $vname => $value){
469 if($vname[0] != "_"){
470 $values[$vname]= $value;
471 }
472 }
474 /* preparing Html output
475 * Supported types are PickOne/Boolean
476 */
478 /* If type is PickOne, create a select box */
479 if(($type == "PickOne")||(($type=="Boolean")&&(count($values)>1))){
481 $str .= "<select name='".base64_encode($name)."'>\n";
482 foreach($values as $optionKey => $value){
483 $selected = "";
484 if($optionKey == $default){
485 $selected = " selected ";
486 }
487 $str .= "<option value='".$optionKey."' ".$selected.">".$value."</option>\n";
488 }
489 $str .= "</select>\n";
491 }elseif($type == "Boolean"){
493 /* If type is Boolean & no values are given */
494 $str .= "<select name='".base64_encode($name)."'>\n";
495 if($default == "False"){
496 $str .= "<option value='True' >"._("True")."</option>\n";
497 $str .= "<option value='False' selected>"._("False")."</option>\n";
498 }else{
499 $str .= "<option value='True' selected>"._("True")."</option>\n";
500 $str .= "<option value='False' >"._("False")."</option>\n";
501 }
502 $str .= "</select>\n";
504 }else{
505 print_red(sprintf(_("Unsupported ppd type '%s' used for '%s' "),$type,$name));
506 }
507 $str .= "</td></tr>\n";
508 }
509 }
510 $str .= "</table></div>\n";
511 }
512 return($str);
513 }
515 function removeModifiedPPD()
516 {
517 $path = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
519 if(file_exists($path)){
520 if(is_writeable($path)){
521 if(!@unlink($path)){
522 print_red(sprintf(_("Removing old ppd file '%s' failed."),$path));
523 }
524 }else{
525 print_red(sprintf(_("Removing old ppd file '%s' failed. File is not accessible."),$path));
526 }
527 }else{
528 print_red(sprintf(_("Removing old ppd file '%s' failed. File does not exists or is not accessible."),$path));
529 }
530 }
532 function update_ppd_url()
533 {
534 $this->SelectPPD("modified/".$this->selectedPPD['link']);
535 }
537 function check()
538 {
539 $message = plugin::check();
540 if(empty($this->selectedPPD['link'])){
541 $message[] = _("Please select a valid ppd file or use 'Cancel' to go back to printer configuration.");
542 }
543 return($message);
544 }
545 }
546 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
547 ?>