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,
23 var $ui;
25 /* If there is already a ppd file for the same type of printer,
26 * remember the path to ppd file and display a dialog which allows
27 * to overwrite the current ppd file.
28 */
29 var $add_ppd_later = "";
30 var $add_later_msg_dialog = NULL;
32 function printerPPDDialog (&$config, $dn= NULL, $ppdfile=NULL )
33 {
34 plugin::plugin ($config, $dn);
35 $this->depselect = $this->config->current['BASE'];
37 $this->ui = get_userinfo();
39 /* Get PPD path and remove double //, and add trailing / */
40 $config = session::get('config');
41 if($config->get_cfg_value("ppdPath") != ""){
42 $this->pathToPPD = $config->get_cfg_value("ppdPath");
43 $this->pathToPPD= preg_replace("/\/\//", "/", $this->pathToPPD);
44 if(!preg_match("/\/$/",$this->pathToPPD)){
45 $this->pathToPPD = $this->pathToPPD."/";
46 }
47 }else{
48 $this->pathToPPD = "";
49 }
51 /* Check if ppdPath is set in gosa.conf.
52 */
53 if(empty($this->pathToPPD)){
54 msg_dialog::display(_("Configuration error"), msgPool::invalidConfigurationAttribute("ppdPath"), ERROR_DIALOG);
55 }
57 /* It seams that we have an existing PPD path, so go on */
58 if(!((!is_dir($this->pathToPPD))||(empty($this->pathToPPD)))){
60 /* Load all available PPD files and sort them into an array */
61 $this->ppdManager= new ppdManager($this->pathToPPD);
62 $this->getPrinterReload ();
64 /* The user has already a valid PPD assigned
65 * Get some informations about this PPD
66 * and set it as selected.
67 * The ppdpath ['link'] should be relative from .../ppd/modified/
68 * e.g. "/Compaq/Compaq-J1200.ppd" */
69 if(($ppdfile!== NULL)&&(strlen($ppdfile)>0)){
70 $ppdfile = preg_replace("#".$this->pathToModified."#","",$ppdfile);
71 if(!file_exists($this->pathToPPD.$this->pathToModified.$ppdfile)){
72 msg_dialog::display(_("PPD error"), sprintf(_("Cannot open PPD '%s'!"), $ppdfile), ERROR_DIALOG);
73 }else{
74 $ppdDesc = $this->ppdManager->loadDescription($this->pathToPPD.$this->pathToModified.$ppdfile);
75 if($ppdDesc){
76 $selectedPPD = array();
77 $selectedPPD['name'] = $ppdDesc['name'];
78 $selectedPPD['link'] = $ppdfile;
79 $selectedPPD['ppd'] = $ppdDesc;
80 }
81 $this->selectedPPD = $selectedPPD;
82 }
83 }
84 }
85 }
88 function execute()
89 {
90 /* Call parent execute */
91 plugin::execute();
93 /* Fill templating stuff */
94 $display= "";
95 $smarty= get_smarty();
96 $smarty->assign("ppdString", _("Can't get ppd informations."));
97 $smarty->assign("showOptions", "");
98 $smarty->assign("path_valid", TRUE);
99 $smarty->assign("acl",$this->ui->get_permissions($this->acl_base,"printer/printgeneric","gotoPrinterPPD"));
101 $acl = $this->ui->get_permissions($this->acl_base,"printer/printgeneric","gotoPrinterPPD");
103 if(empty($this->pathToPPD)){
105 /* Print out template */
106 $smarty->assign("path_valid", FALSE);
107 $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
108 return($display);
109 }
111 /* Check these paths */
112 $paths = array($this->pathToPPD, $this->pathToPPD.$this->pathToModified);
114 /* If one of our required paths is not available, stop here and display some info */
115 foreach($paths as $path){
117 /* Check if path is write/readable*/
118 $is_r = @is_readable($path);
119 if(((!is_dir($path))||(empty($path)) || (!$is_r)) && (!@mkdir($path))){
120 msg_dialog::display(_("Configuration error"),
121 sprintf(_("Cannot open PPD path '%s' for reading and writing!"), $path), ERROR_DIALOG);
123 /* Print out template */
124 $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
125 return($display);
126 }
127 }
129 // PPD selection / upload / dialog handling
131 /* Is there a new PPD file uploaded ? */
132 if(preg_match("/w/",$acl)){
133 if((isset($_FILES['NewPPDFile']))&&(isset($_POST['SubmitNewPPDFile']))){
134 $file = ($_FILES['NewPPDFile']);
135 if($file['size'] != 0 ){
136 if($name = $this->AddPPD($file['tmp_name'])){
137 $this->SelectPPD($name);
138 }
139 }else{
140 msg_dialog::display(_("PPD error"), msgPool::incorrectUpload(_("file is empty")), ERROR_DIALOG);
141 }
142 }
143 }
145 /* Overwrite existing PPD file and select it as currently used for this object */
146 if(is_object($this->add_later_msg_dialog) && ($this->add_later_msg_dialog->is_confirmed()) && $this->add_ppd_later != ""){
147 if($name = $this->AddPPD($this->add_ppd_later,TRUE)){
148 $this->SelectPPD($name);
149 }
150 $this->add_ppd_later = "";
151 $this->add_later_msg_dialog = NULL;
152 }
154 /* Open a dialog that allow us to select different PPDs */
155 if(preg_match("/w/",$acl)){
156 if(isset($_POST['SelectPPD'])){
157 $this->dialog= new printerPPDSelectionDialog($this->config,$this->dn,$this->ppdList,$this->ppdListHeader,$this->selectedPPD);
158 }
159 }
161 /* The selection dialog fpr PPDs is canceled */
162 if(isset($_POST['ClosePPDSelection'])){
163 unset($this->dialog);
164 $this->dialog=FALSE;
165 }
167 /* Div Selection */
168 if((isset($_GET['act']))&&($_GET['act']=="use")){
169 $this->SelectPPD(base64_decode($_GET['id']));
170 unset($this->dialog);
171 $this->dialog=FALSE;
173 }
175 /* if a dialog is open, print the dialog instead of this class */
176 if(is_object($this->dialog)){
177 $display = $this->dialog->execute();
178 return($display);
179 }
181 // ENDE PPD selection / upload / dialog handling
183 /* Give smarty the information it needs */
184 $smarty->assign("ppdString" ,$this->getPPDInformation());
185 $tmp= $this->generateProperties();
186 if ($tmp == ""){
187 $smarty->assign("showOptions", 0);
188 } else {
189 $smarty->assign("showOptions", 1);
190 $smarty->assign("properties",$this->generateProperties());
191 }
193 /* Print out template */
194 $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
195 return($display);
196 }
199 /* Select PPD */
200 function SelectPPD($name)
201 {
202 /* Replace base path we don't need it here
203 The path we need looks like this : "/Vendor/ModellName.ppd";
204 thats all */
205 $name = preg_replace("#".$this->pathToPPD."#","",$name);
207 /* Intialise some base vars */
208 $AbsoluteSourceName = $this->pathToPPD.$name;
209 $AbsoluteDestinationPath = $this->pathToPPD.$this->pathToModified;
210 $Vendor = ""; // Vendor
211 $Name = ""; // Name
212 $Modell = ""; // Modell
213 $PrinterName = ""; // The new name of the printer
214 $PPDName = "";
216 /* Force reload of config dialog */
217 $this->ppdConfig = false;
218 $this->selectedPPD['link'] = false;
220 /* Get PPD informations and set vendor / modell / name */
221 if((!file_exists($AbsoluteSourceName)) || (!is_readable($AbsoluteSourceName))){
222 msg_dialog::display(_("PPD error"), msgPool::cannotReadFile($AbsoluteSourceName), ERROR_DIALOG);
223 return;
224 }
225 $ppdDesc = $this->ppdManager->loadDescription($AbsoluteSourceName);
226 if($ppdDesc){
227 $Name = $ppdDesc['name'];
228 $Vendor = $ppdDesc['manufacturer'];
229 $Model = $ppdDesc['model'];
230 }
232 $PrinterName = $this->cn."-".preg_replace("/[^a-z0-9-_\.]/i","_",$Name);
233 $PPDName = $Vendor."/".$PrinterName.".ppd";
235 /* Create the vendors path, if it doesn't exists already */
236 if(!is_dir($AbsoluteDestinationPath.$Vendor)){
237 if(!(@mkdir($AbsoluteDestinationPath.$Vendor))){
238 msg_dialog::display(_("PPD error"), msgPool::cannotCreateFolder($AbsoluteDestinationPath.$Vendor), ERROR_DIALOG);
239 return(false);
240 }
241 }
243 /* Create destination file handle */
244 $fp = @fopen($AbsoluteDestinationPath.$PPDName,"w+");
245 if(!$fp){
246 msg_dialog::display(_("PPD error"), msgPool::cannotWriteFile($AbsoluteDestinationPath.$PPDName), ERROR_DIALOG);
247 return(false);
248 }
250 $str = file_get_contents($AbsoluteSourceName);
251 fputs($fp,$str);
252 @fclose($fp);
254 //$this->ppdManager->updateAttribute($filename,"NO_SECTION","ModelName",$printerName);
256 $tmp3['link'] =$PPDName;
257 $this->selectedPPD = $tmp3;
258 $this->getPrinterReload();
259 return($PPDName);
260 }
263 /* This function adds a new ppd file to the list of available ppds.
264 All required paths and files will be created
265 $_PathOnHdd e.g. = /tmp/PHP_tmpfile213452 */
266 function AddPPD($_PathOnHdd,$overwrite = FALSE)
267 {
268 /* Check if file exists && is readable */
269 if((!is_file($_PathOnHdd)) || (!is_readable($_PathOnHdd))){
270 msg_dialog::display(_("PPD error"), msgPool::cannotReadFile($_PathOnHdd), ERROR_DIALOG);
271 return(false);
272 }
274 /* Reload list to detect changes e.g. a file has been deleted */
275 $this->getPrinterReload();
277 /* Get Description from ppd, & parse out some informations */
278 $ppdDesc = @$this->ppdManager->loadDescription($_PathOnHdd);
279 if($ppdDesc){
280 $name = preg_replace("/\//","-",$ppdDesc['name']);
281 $vendor = $ppdDesc['manufacturer'];
282 $model = $ppdDesc['model'];
283 }
285 /* Check if parse was successfull */
286 if(empty($name) || empty($vendor)){
287 msg_dialog::display(_("PPD error"), sprintf(_("Cannot parse PPD '%s'!"), $_PathOnHdd), ERROR_DIALOG);
288 return(false);
289 }
291 /* Prepare list of ppds */
292 if(!isset($this->ppdList[$vendor])){
293 $this->ppdList[$vendor] = array();
294 }
296 /* Create ppd file and fill in the source contents */
297 $ppdname = $vendor."/".$name.".ppd";
298 $filename = $this->pathToPPD.preg_replace("/[^a-z0-9-_\.\/]/i","_",$ppdname);
299 $filename = $this->pathToPPD.$ppdname;
300 $contents = file_get_contents($_PathOnHdd);
303 /* Check if this ppd already exists */
304 $found = false;
306 foreach($this->ppdList[$vendor] as $key => $val){
307 if(preg_match("/".preg_quote($model,'/').".*/i",$key)){
308 $found = true;
309 if(!$overwrite){
310 if(!copy($_PathOnHdd,$_PathOnHdd."_back")){
311 msg_dialog::display(_("PPD error"), msgPool::cannotReadFile($_PathOnHdd), ERROR_DIALOG);
312 }else{
313 $this->add_ppd_later = $_PathOnHdd."_back";
314 $this->add_later_msg_dialog = new msg_dialog(_("Overwrite existing PPD"),
315 _("There is already a ppd file for this kind of printer. Do you want to overwrite it?"),CONFIRM_DIALOG);
316 }
317 return;
318 }
319 }
320 }
322 /* Create the vendors path, if it doesn't exists already */
323 if(!is_dir($this->pathToPPD.$vendor)){
324 if(!(@mkdir($this->pathToPPD.$vendor))){
325 msg_dialog::display(_("PPD error"), msgPool::cannotCreateFolder($this->pathToPPD.$vendor), ERROR_DIALOG);
326 return(false);
327 }
328 }
330 /* Open file handle */
331 $fp = fopen($filename,"w+");
333 /* Check file handle & contents */
334 if(!$fp){
335 msg_dialog::display(_("PPD error"), msgPool::cannotWriteFile($filename), ERROR_DIALOG);
336 return;
337 }
338 if(empty($contents)){
339 msg_dialog::display(_("PPD error"), msgPool::incorrectUpload(_("file is empty")), ERROR_DIALOG);
340 return;
341 }
343 /* Fille file with data */
344 fputs($fp,$contents);
345 @fclose($fp);
347 /* Our job is done here */
348 return($ppdname);
349 }
352 /* This function reloads the list of available printers/vendors
353 $this->ppdListHeader
354 Compaq => 1
355 $this->ppdList
356 Compaq => Compaq IJ1200 => name => Compaq IJ1200
357 link => /var/spool/ppd/Compaq/Compaq-J1200.ppd
358 ppd => Compaq - Co
359 */
360 function getPrinterReload()
361 {
362 if(is_readable($this->pathToPPD)){
363 $tmp = @$this->ppdManager->getPrinterList(true);
365 $this->ppdListHeader = $this->ppdList = array();
367 /* Sort all available files, and create header (Vendor index) */
368 foreach($tmp as $file=>$ppd){
370 if(preg_match("#".preg_quote($this->pathToModified,'#')."#",$file)) continue;
372 if(!isset($this->ppdListHeader[$ppd['manufacturer']])){
373 $this->ppdListHeader[$ppd['manufacturer']]=0;
374 }
376 $tmp3['name'] =$ppd['name'];
377 $tmp3['link'] =$file;
378 $tmp3['ppd'] =$ppd;
379 $this->ppdListHeader[$ppd['manufacturer']]++;
380 $this->ppdList[$ppd['manufacturer']][$ppd['name']]=$tmp3;
381 }
382 }
383 }
386 /* Save all options posted from ppd dialog */
387 function save_object()
388 {
389 if(!((isset($_POST['PPDDisSubmitted'])) && (is_array($this->ppdConfig)))){
390 return;
391 }
393 if(preg_match("/w/",$this->ui->get_permissions($this->acl_base,"printer/printgeneric","gotoPrinterPPD"))){
394 foreach($this->ppdConfig as $cat => $obj){
395 foreach($obj as $attr => $attributes){
396 if(isset($_POST[base64_encode($attributes['_name'])])){
397 $this->ppdConfig[$cat][$attr]['_default'] = $_POST[base64_encode($attributes['_name'])];
398 }
399 }
400 }
401 }
402 }
405 /* Save modified ppd */
406 function save_ppd()
407 {
408 if($this->ppdManager){
409 $this->ppdManager->saveProperties($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'],$this->ppdConfig);
410 }
411 }
414 /* Return selected ppd path, if none is selected then false */
415 function save()
416 {
417 /* return the selected PPD, and in future the selected options too */
418 return($this->pathToModified.$this->selectedPPD['link']);
419 }
422 /* Get Information for a single PPD entry
423 * This will be shown on top of template
424 */
425 function getPPDInformation()
426 {
427 $str = "none";
428 if(!empty($this->selectedPPD)){
429 $ppdDesc = $this->ppdManager->loadDescription($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link']);
430 $str = $ppdDesc['name'];
431 }
432 return($str) ;
433 }
435 /* Display all options from the selected ppd file */
436 function generateProperties()
437 {
438 /* Set Headline */
439 $str = "";
440 $feed= "";
442 $s_ppd = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
444 /* If ppd exists and is readable */
445 if((!empty($this->selectedPPD['link']))&&(file_exists($s_ppd))){
447 /* If there is no initial Configuration, load it */
448 if($this->ppdConfig == false){
449 $this->ppdConfig = $this->ppdManager->loadProperties($s_ppd);
450 }
452 /* Create a table */
453 $str .= "<div style='padding-left:30px;'><table summary=''>";
455 /* Input all data to the table */
456 foreach($this->ppdConfig as $cat => $obj){
458 /* Add new category */
459 $str .= "<tr><td colspan='2'>$feed";
460 if ($feed == ""){
461 $feed= "<br>";
462 }
463 $str .= "<b>"._("Section")." '".$cat."' </b><br>";
464 $str .= "</td></tr>";
466 /* Add attributes of the current category */
467 foreach($obj as $attr => $settings){
469 /* Skip all entries beginning with _ */
470 if($attr[0] == "_") continue;
472 /* Prepare data */
473 $values = array();
474 $name = $settings['_name'];
476 if (!isset($settings['_default'])){
477 $default = "";
478 } else {
479 $default = $settings['_default'];
480 }
482 $type = $settings['_type'];
484 /* Add name to table */
485 $str .= "<tr><td style='padding-left:40px;'>\n";
486 $str .= $name."<br>\n";
487 $str .= "</td><td>\n";
489 /* Get all values */
490 foreach( $settings as $vname => $value){
491 if($vname[0] != "_"){
492 $values[$vname]= $value;
493 }
494 }
496 $acl ="";
497 if(!preg_match("/w/",$this->ui->get_permissions($this->acl_base,"printer/printgeneric","gotoPrinterPPD"))){
498 $acl = "disabled";
499 }
501 /* preparing Html output
502 * Supported types are PickOne/Boolean
503 */
505 /* If type is PickOne, create a select box */
506 if(($type == "PickOne")||(($type=="Boolean")&&(count($values)>1))){
508 $str .= "<select name='".base64_encode($name)."' $acl >\n";
509 foreach($values as $optionKey => $value){
510 $selected = "";
511 if($optionKey == $default){
512 $selected = " selected ";
513 }
514 $str .= "<option value='".$optionKey."' ".$selected.">".$value."</option>\n";
515 }
516 $str .= "</select>\n";
518 }elseif($type == "Boolean"){
520 /* If type is Boolean & no values are given */
521 $str .= "<select name='".base64_encode($name)."' $acl>\n";
522 if($default == "False"){
523 $str .= "<option value='True' >"._("True")."</option>\n";
524 $str .= "<option value='False' selected>"._("False")."</option>\n";
525 }else{
526 $str .= "<option value='True' selected>"._("True")."</option>\n";
527 $str .= "<option value='False' >"._("False")."</option>\n";
528 }
529 $str .= "</select>\n";
531 }else{
532 msg_dialog::display(_("PPD error"), sprintf(_("PPD type '%s' is not supported!"), $type), ERROR_DIALOG);
533 }
534 $str .= "</td></tr>\n";
535 }
536 }
537 $str .= "</table></div>\n";
538 }
539 return($str);
540 }
542 function removeModifiedPPD()
543 {
544 $path = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
546 if(file_exists($path)){
547 if(is_writeable($path)){
548 if(!@unlink($path)){
549 msg_dialog::display(_("PPD error"), msgPool::cannotDeleteFile($path), ERROR_DIALOG);
550 }
551 }else{
552 msg_dialog::display(_("PPD error"), msgPool::cannotDeleteFile($path), ERROR_DIALOG);
553 }
554 }else{
555 msg_dialog::display(_("PPD error"), msgPool::cannotDeleteFile($path), ERROR_DIALOG);
556 }
557 }
559 function update_ppd_url()
560 {
561 $this->SelectPPD("modified/".$this->selectedPPD['link']);
562 return("modified/".$this->selectedPPD['link']);
563 }
565 function check()
566 {
567 $message = plugin::check();
568 if(empty($this->selectedPPD['link'])){
569 $message[] = _("Please select a valid ppd file or use 'Cancel' to go back to printer configuration.");
570 }
571 return($message);
572 }
573 }
574 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
575 ?>