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