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 if(isset($_SESSION['config']->data['MAIN']['PPD_PATH'])){
43 $this->pathToPPD = $_SESSION['config']->data['MAIN']['PPD_PATH'];
44 $this->pathToPPD= preg_replace("/\/\//", "/", $this->pathToPPD);
45 if(!preg_match("/\/$/",$this->pathToPPD)){
46 $this->pathToPPD = $this->pathToPPD."/";
47 }
48 }else{
49 $this->pathToPPD = "";
50 }
52 /* It seams that we have an existing PPD path, so go on */
53 if(!((!is_dir($this->pathToPPD))||(empty($this->pathToPPD)))){
55 /* Load all available PPD files and sort them into an array */
56 $this->ppdManager= new ppdManager($this->pathToPPD);
57 $this->getPrinterReload ();
59 /* The user has already a valid PPD assigned
60 * Get some informations about this PPD
61 * and set it as selected.
62 * The ppdpath ['link'] should be relative from .../ppd/modified/
63 * e.g. "/Compaq/Compaq-J1200.ppd" */
64 if(($ppdfile!== NULL)&&(strlen($ppdfile)>0)){
65 $ppdfile = preg_replace("#".$this->pathToModified."#","",$ppdfile);
66 if(!file_exists($this->pathToPPD.$this->pathToModified.$ppdfile)){
67 print_red(sprintf(_("Can't open '%s', ppd settings resetted."),$ppdfile));
68 }else{
69 $res = $this->ppdManager->loadDescription($this->pathToPPD.$this->pathToModified.$ppdfile);
70 if($res){
71 $tmp = split("\n",$res);
72 $tmp3 = array();
73 $tmp3['name'] = trim(preg_replace("/^\-/","",trim($tmp[1])));
74 $tmp3['link'] = $ppdfile;
75 $tmp3['ppd'] = $res;
76 }
77 $this->selectedPPD = $tmp3;
78 }
79 }
80 }
81 }
84 function execute()
85 {
86 /* Call parent execute */
87 plugin::execute();
89 /* Fill templating stuff */
90 $display= "";
91 $smarty= get_smarty();
92 $smarty->assign("ppdString", _("Can't get ppd informations."));
93 $smarty->assign("showOptions", "");
95 /* Check these paths */
96 $paths = array($this->pathToPPD, $this->pathToPPD.$this->pathToModified);
98 /* If one of our required paths is not available, stop here and display some info */
99 foreach($paths as $path){
101 /* Check if path is write/readable*/
102 $is_r = @is_readable($path);
103 if(((!is_dir($path))||(empty($path)) || (!$is_r)) && (!@mkdir($path))){
104 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));
105 /* Print out template */
106 $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
107 return($display);
108 }
109 }
111 // PPD selection / upload / dialog handling
113 /* Is there a new PPD file uploaded ? */
114 if((isset($_FILES['NewPPDFile']))&&(isset($_POST['SubmitNewPPDFile']))){
115 $file = ($_FILES['NewPPDFile']);
116 if($file['size'] != 0 ){
117 if($name = $this->AddPPD($file['tmp_name'])){
118 $this->SelectPPD($name);
119 }
120 }else{
121 print_red(_("Please specify a valid ppd file."));
122 }
123 }
125 /* Overwrite existing PPD file and select it as currently used for this object */
126 if(is_object($this->add_later_msg_dialog) && ($this->add_later_msg_dialog->is_confirmed()) && $this->add_ppd_later != ""){
127 if($name = $this->AddPPD($this->add_ppd_later,TRUE)){
128 $this->SelectPPD($name);
129 }
130 $this->add_ppd_later = "";
131 $this->add_later_msg_dialog = NULL;
132 }
134 /* Open a dialog that allow us to select different PPDs */
135 if(isset($_POST['SelectPPD'])){
136 $this->dialog= new printerPPDSelectionDialog($this->config,$this->dn,$this->ppdList,$this->ppdListHeader,$this->selectedPPD);
137 }
139 /* The selection dialog fpr PPDs is canceled */
140 if(isset($_POST['ClosePPDSelection'])){
141 unset($this->dialog);
142 $this->dialog=FALSE;
143 }
145 /* Div Selection */
146 if((isset($_GET['act']))&&($_GET['act']=="use")){
147 $this->SelectPPD(base64_decode($_GET['id']));
148 unset($this->dialog);
149 $this->dialog=FALSE;
151 }
153 /* if a dialog is open, print the dialog instead of this class */
154 if(is_object($this->dialog)){
155 $display = $this->dialog->execute();
156 return($display);
157 }
159 // ENDE PPD selection / upload / dialog handling
161 /* Give smarty the information it needs */
162 $smarty->assign("ppdString" ,$this->getPPDInformation());
163 $tmp= $this->generateProperties();
164 if ($tmp == ""){
165 $smarty->assign("showOptions", 0);
166 } else {
167 $smarty->assign("showOptions", 1);
168 $smarty->assign("properties",$this->generateProperties());
169 }
171 /* Print out template */
172 $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
173 return($display);
174 }
177 /* Select PPD */
178 function SelectPPD($name)
179 {
180 /* Replace base path we don't need it here
181 The path we need looks like this : "/Vendor/ModellName.ppd";
182 thats all */
183 $name = preg_replace("#".$this->pathToPPD."#","",$name);
185 /* Intialise some base vars */
186 $AbsoluteSourceName = $this->pathToPPD.$name;
187 $AbsoluteDestinationPath = $this->pathToPPD.$this->pathToModified;
188 $Vendor = ""; // Vendor
189 $Name = ""; // Name
190 $Modell = ""; // Modell
191 $PrinterName = ""; // The new name of the printer
192 $PPDName = "";
194 /* Force reload of config dialog */
195 $this->ppdConfig = false;
196 $this->selectedPPD['link'] = false;
198 /* Get PPD informations and set vendor / modell / name */
199 if((!file_exists($AbsoluteSourceName)) || (!is_readable($AbsoluteSourceName))){
200 print_red(sprintf(_("Can't select PPD file '%s', the file is not readable"),$AbsoluteSourceName));
201 return;
202 }
203 $res = $this->ppdManager->loadDescription($AbsoluteSourceName);
204 if($res){
205 $tmp = split("\n",$res);
206 $Name = trim(preg_replace("/^\-/","",trim($tmp[1])));
207 $Vendor = trim($tmp[0]);
208 $Model = trim(preg_replace("/".$Vendor."/","",$Name));
209 }
211 $PrinterName = $this->cn."-".preg_replace("/[^a-z0-9-_\.]/i","_",$Name);
212 $PPDName = $Vendor."/".$PrinterName.".ppd";
214 /* Create the vendors path, if it doesn't exists already */
215 if(!is_dir($AbsoluteDestinationPath.$Vendor)){
216 if(!(@mkdir($AbsoluteDestinationPath.$Vendor))){
217 print_red(sprintf(_("Can't create folder '%s' for the uploaded ppd file."),$AbsoluteDestinationPath.$Vendor));
218 return(false);
219 }
220 }
222 /* Create destination file handle */
223 $fp = @fopen($AbsoluteDestinationPath.$PPDName,"w+");
224 if(!$fp){
225 print_red(sprintf(_("Can't create file '%s' to store modifed ppd informations."),$AbsoluteDestinationPath.$PPDName));
226 return(false);
227 }
229 $str = file_get_contents($AbsoluteSourceName);
230 fputs($fp,$str);
231 @fclose($fp);
233 //$this->ppdManager->updateAttribute($filename,"NO_SECTION","ModelName",$printerName);
235 $tmp3['link'] =$PPDName;
236 $this->selectedPPD = $tmp3;
237 $this->getPrinterReload();
238 return($PPDName);
239 }
242 /* This function adds a new ppd file to the list of available ppds.
243 All required paths and files will be created
244 $_PathOnHdd e.g. = /tmp/PHP_tmpfile213452 */
245 function AddPPD($_PathOnHdd,$overwrite = FALSE)
246 {
247 /* Check if file exists && is readable */
248 if((!is_file($_PathOnHdd)) || (!is_readable($_PathOnHdd))){
249 print_red(sprintf(_("Can't add new ppd file, the source file '%s' is not accessible."),$_PathOnHdd));
250 return(false);
251 }
253 /* Reload list to detect changes e.g. a file has been deleted */
254 $this->getPrinterReload();
256 /* Get Description from ppd, & parse out some informations */
257 $res = @$this->ppdManager->loadDescription($_PathOnHdd);
258 if($res){
259 $tmp = split("\n",$res);
260 $name = trim(preg_replace("/^\-/","",trim($tmp[1])));
261 $vendor = trim($tmp[0]);
262 $model = trim(preg_replace("/".$vendor."/","",$name));
263 }
265 /* Check if parse was successfull */
266 if(empty($name) || empty($vendor)){
267 print_red(sprintf(_("The given ppd file '%s' seams to be invalid, can't get any model or vendor informations."),$_PathOnHdd));
268 return(false);
269 }
271 /* Prepare list of ppds */
272 if(!isset($this->ppdList[$vendor])){
273 $this->ppdList[$vendor] = array();
274 }
276 /* Create ppd file and fill in the source contents */
277 $ppdname = $vendor."/".$name.".ppd";
278 $filename = $this->pathToPPD.preg_replace("/[^a-z0-9-_\.\/]/i","_",$ppdname);
279 $filename = $this->pathToPPD.$ppdname;
280 $contents = file_get_contents($_PathOnHdd);
283 /* Check if this ppd already exists */
284 $found = false;
285 foreach($this->ppdList[$vendor] as $key => $val){
286 if(preg_match("/".$model.".*/i",$key)){
287 $found = true;
288 if(!$overwrite){
289 if(!copy($_PathOnHdd,$_PathOnHdd."_back")){
290 print_red(sprintf(_("Can't add new ppd file, the source file '%s' is not accessible."),$_PathOnHdd));
291 }else{
292 $this->add_ppd_later = $_PathOnHdd."_back";
293 $this->add_later_msg_dialog = new msg_dialog(_("Overwrite existing PPD"),
294 _("There is already a ppd file for this kind of printer. Do you want to overwrite it?"),CONFIRM_DIALOG);
295 }
296 return;
297 }
298 }
299 }
301 /* Open file handle */
302 $fp = fopen($filename,"w+");
304 /* Create the vendors path, if it doesn't exists already */
305 if(!is_dir($this->pathToPPD.$vendor)){
306 if(!(@mkdir($this->pathToPPD.$vendor))){
307 print_red(sprintf(_("Can't create folder '%s' for the uploaded ppd file."),$this->pathToPPD.$vendor));
308 return(false);
309 }
310 }
312 /* Check file handle & contents */
313 if(!$fp){
314 print_red(sprintf(_("Can't save file '%s'."),$filename));
315 return;
316 }
317 if(empty($contents)){
318 print_red(_("Uploaded ppd file is empty, can't create new ppd file."));
319 return;
320 }
322 /* Fille file with data */
323 fputs($fp,$contents);
324 @fclose($fp);
326 /* Our job is done here */
327 return($ppdname);
328 }
331 /* This function reloads the list of available printers/vendors
332 $this->ppdListHeader
333 Compaq => 1
334 $this->ppdList
335 Compaq => Compaq IJ1200 => name => Compaq IJ1200
336 link => /var/spool/ppd/Compaq/Compaq-J1200.ppd
337 ppd => Compaq - Co
338 */
339 function getPrinterReload()
340 {
341 if(is_readable($this->pathToPPD)){
342 $tmp = @$this->ppdManager->getPrinterList(true);
344 $this->ppdListHeader = $this->ppdList = array();
346 /* Sort all available files, and create header (Vendor index) */
347 foreach($tmp as $file=>$ppd){
349 if(preg_match("#".$this->pathToModified."#",$file)) continue;
351 $tmp2 = split("\n",$ppd);
352 if(!isset($this->ppdListHeader[$tmp2[0]])){
353 $this->ppdListHeader[$tmp2[0]]=0;
354 }
355 $tmp3['name'] =preg_replace("/^ -/","",$tmp2[1]." - ".$tmp2[2]);
356 $tmp3['link'] =$file;
357 $tmp3['ppd'] =$ppd;
358 $this->ppdListHeader[$tmp2[0]]++;
359 $this->ppdList[$tmp2[0]][preg_replace("/^ -/","",$tmp2[1]." - ".$tmp2[2])]=$tmp3;
360 }
361 }
362 }
365 /* Save all options posted from ppd dialog */
366 function save_object()
367 {
368 if(!((isset($_POST['PPDDisSubmitted'])) && (is_array($this->ppdConfig)))){
369 return;
370 }
372 foreach($this->ppdConfig as $cat => $obj){
373 foreach($obj as $attr => $attributes){
374 if(isset($_POST[base64_encode($attributes['_name'])])){
375 $this->ppdConfig[$cat][$attr]['_default'] = $_POST[base64_encode($attributes['_name'])];
376 }
377 }
378 }
379 }
382 /* Save modified ppd */
383 function save_ppd()
384 {
385 if($this->ppdManager){
386 $this->ppdManager->saveProperties($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'],$this->ppdConfig);
387 }
388 }
391 /* Return selected ppd path, if none is selected then false */
392 function save()
393 {
394 /* return the selected PPD, and in future the selected options too */
395 return($this->pathToModified.$this->selectedPPD['link']);
396 }
399 /* Get Information for a single PPD entry
400 * This will be shown on top of template
401 */
402 function getPPDInformation()
403 {
404 $str = "none";
405 if(!empty($this->selectedPPD)){
406 $str = $this->ppdManager->loadDescription($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link']);
407 }
408 return($str) ;
409 }
412 /* Display all options from the selected ppd file */
413 function generateProperties()
414 {
415 /* Set Headline */
416 $str = "";
417 $feed= "";
419 $s_ppd = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
421 /* If ppd exists and is readable */
422 if((!empty($this->selectedPPD['link']))&&(file_exists($s_ppd))){
424 /* If there is no initial Configuration, load it */
425 if($this->ppdConfig == false){
426 $this->ppdConfig = $this->ppdManager->loadProperties($s_ppd);
427 }
429 /* Create a table */
430 $str .= "<div style='padding-left:30px;'><table summary=''>";
432 /* Input all data to the table */
433 foreach($this->ppdConfig as $cat => $obj){
435 /* Add new category */
436 $str .= "<tr><td colspan='2'>$feed";
437 if ($feed == ""){
438 $feed= "<br>";
439 }
440 $str .= "<b>"._("Section")." '".$cat."' </b><br>";
441 $str .= "</td></tr>";
443 /* Add attributes of the current category */
444 foreach($obj as $attr => $settings){
446 /* Skip all entries beginning with _ */
447 if($attr[0] == "_") continue;
449 /* Prepare data */
450 $values = array();
451 $name = $settings['_name'];
453 if (!isset($settings['_default'])){
454 $default = "";
455 } else {
456 $default = $settings['_default'];
457 }
459 $type = $settings['_type'];
461 /* Add name to table */
462 $str .= "<tr><td style='padding-left:40px;'>\n";
463 $str .= $name."<br>\n";
464 $str .= "</td><td>\n";
466 /* Get all values */
467 foreach( $settings as $vname => $value){
468 if($vname[0] != "_"){
469 $values[$vname]= $value;
470 }
471 }
473 /* preparing Html output
474 * Supported types are PickOne/Boolean
475 */
477 /* If type is PickOne, create a select box */
478 if(($type == "PickOne")||(($type=="Boolean")&&(count($values)>1))){
480 $str .= "<select name='".base64_encode($name)."'>\n";
481 foreach($values as $optionKey => $value){
482 $selected = "";
483 if($optionKey == $default){
484 $selected = " selected ";
485 }
486 $str .= "<option value='".$optionKey."' ".$selected.">".$value."</option>\n";
487 }
488 $str .= "</select>\n";
490 }elseif($type == "Boolean"){
492 /* If type is Boolean & no values are given */
493 $str .= "<select name='".base64_encode($name)."'>\n";
494 if($default == "False"){
495 $str .= "<option value='True' >"._("True")."</option>\n";
496 $str .= "<option value='False' selected>"._("False")."</option>\n";
497 }else{
498 $str .= "<option value='True' selected>"._("True")."</option>\n";
499 $str .= "<option value='False' >"._("False")."</option>\n";
500 }
501 $str .= "</select>\n";
503 }else{
504 print_red(sprintf(_("Unsupported ppd type '%s' used for '%s' "),$type,$name));
505 }
506 $str .= "</td></tr>\n";
507 }
508 }
509 $str .= "</table></div>\n";
510 }
511 return($str);
512 }
514 function removeModifiedPPD()
515 {
516 $path = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
518 if(file_exists($path)){
519 if(is_writeable($path)){
520 if(!@unlink($path)){
521 print_red(sprintf(_("Removing old ppd file '%s' failed."),$path));
522 }
523 }else{
524 print_red(sprintf(_("Removing old ppd file '%s' failed. File is not accessible."),$path));
525 }
526 }else{
527 print_red(sprintf(_("Removing old ppd file '%s' failed. File does not exists or is not accessible."),$path));
528 }
529 }
531 function update_ppd_url()
532 {
533 $this->SelectPPD("modified/".$this->selectedPPD['link']);
534 }
536 function check()
537 {
538 $message = plugin::check();
539 if(empty($this->selectedPPD['link'])){
540 $message[] = _("Please select a valid ppd file or use 'Cancel' to go back to printer configuration.");
541 }
542 return($message);
543 }
544 }
545 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
546 ?>