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 msg_dialog::display(_("PPD error"), sprintf(_("Cannot open PPD '%s'!"), $ppdfile), ERROR_DIALOG);
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 msg_dialog::display(_("Configuration error"), sprintf(_("Cannot open PPD path '%s' for reading and writing!"), $path), ERROR_DIALOG);
102 /* Print out template */
103 $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
104 return($display);
105 }
106 }
108 // PPD selection / upload / dialog handling
110 /* Is there a new PPD file uploaded ? */
111 if((isset($_FILES['NewPPDFile']))&&(isset($_POST['SubmitNewPPDFile']))){
112 $file = ($_FILES['NewPPDFile']);
113 if($file['size'] != 0 ){
114 if($name = $this->AddPPD($file['tmp_name'])){
115 $this->SelectPPD($name);
116 }
117 }else{
118 msg_dialog::display(_("PPD error"), msgPool::incorrectUpload(_("file is empty")), ERROR_DIALOG);
119 }
120 }
122 /* Overwrite existing PPD file and select it as currently used for this object */
123 if(is_object($this->add_later_msg_dialog) && ($this->add_later_msg_dialog->is_confirmed()) && $this->add_ppd_later != ""){
124 if($name = $this->AddPPD($this->add_ppd_later,TRUE)){
125 $this->SelectPPD($name);
126 }
127 $this->add_ppd_later = "";
128 $this->add_later_msg_dialog = NULL;
129 }
131 /* Open a dialog that allow us to select different PPDs */
132 if(isset($_POST['SelectPPD'])){
133 $this->dialog= new printerPPDSelectionDialog($this->config,$this->dn,$this->ppdList,$this->ppdListHeader,$this->selectedPPD);
134 }
136 /* The selection dialog fpr PPDs is canceled */
137 if(isset($_POST['ClosePPDSelection'])){
138 unset($this->dialog);
139 $this->dialog=FALSE;
140 }
142 /* Div Selection */
143 if((isset($_GET['act']))&&($_GET['act']=="use")){
144 $this->SelectPPD(base64_decode($_GET['id']));
145 unset($this->dialog);
146 $this->dialog=FALSE;
148 }
150 /* if a dialog is open, print the dialog instead of this class */
151 if(is_object($this->dialog)){
152 $display = $this->dialog->execute();
153 return($display);
154 }
156 // ENDE PPD selection / upload / dialog handling
158 /* Give smarty the information it needs */
159 $smarty->assign("ppdString" ,$this->getPPDInformation());
160 $tmp= $this->generateProperties();
161 if ($tmp == ""){
162 $smarty->assign("showOptions", 0);
163 } else {
164 $smarty->assign("showOptions", 1);
165 $smarty->assign("properties",$this->generateProperties());
166 }
168 /* Print out template */
169 $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
170 return($display);
171 }
174 /* Select PPD */
175 function SelectPPD($name)
176 {
177 /* Replace base path we don't need it here
178 The path we need looks like this : "/Vendor/ModellName.ppd";
179 thats all */
180 $name = preg_replace("#".$this->pathToPPD."#","",$name);
182 /* Intialise some base vars */
183 $AbsoluteSourceName = $this->pathToPPD.$name;
184 $AbsoluteDestinationPath = $this->pathToPPD.$this->pathToModified;
185 $Vendor = ""; // Vendor
186 $Name = ""; // Name
187 $Modell = ""; // Modell
188 $PrinterName = ""; // The new name of the printer
189 $PPDName = "";
191 /* Force reload of config dialog */
192 $this->ppdConfig = false;
193 $this->selectedPPD['link'] = false;
195 /* Get PPD informations and set vendor / modell / name */
196 if((!file_exists($AbsoluteSourceName)) || (!is_readable($AbsoluteSourceName))){
197 msg_dialog::display(_("PPD error"), msgPool::cannotReadFile($AbsoluteSourceName), ERROR_DIALOG);
198 return;
199 }
200 $res = $this->ppdManager->loadDescription($AbsoluteSourceName);
201 if($res){
202 $tmp = split("\n",$res);
203 $Name = trim(preg_replace("/^\-/","",trim($tmp[1])));
204 $Vendor = trim($tmp[0]);
205 $Model = trim(preg_replace("/".$Vendor."/","",$Name));
206 }
208 $PrinterName = $this->cn."-".preg_replace("/[^a-z0-9-_\.]/i","_",$Name);
209 $PPDName = $Vendor."/".$PrinterName.".ppd";
211 /* Create the vendors path, if it doesn't exists already */
212 if(!is_dir($AbsoluteDestinationPath.$Vendor)){
213 if(!(@mkdir($AbsoluteDestinationPath.$Vendor))){
214 msg_dialog::display(_("PPD error"), msgPool::cannotCreateFolder($AbsoluteDestinationPath.$Vendor), ERROR_DIALOG);
215 return(false);
216 }
217 }
219 /* Create destination file handle */
220 $fp = @fopen($AbsoluteDestinationPath.$PPDName,"w+");
221 if(!$fp){
222 msg_dialog::display(_("PPD error"), msgPool::cannotWriteFile($AbsoluteDestinationPath.$PPDName), ERROR_DIALOG);
223 return(false);
224 }
226 $str = file_get_contents($AbsoluteSourceName);
227 fputs($fp,$str);
228 @fclose($fp);
230 //$this->ppdManager->updateAttribute($filename,"NO_SECTION","ModelName",$printerName);
232 $tmp3['link'] =$PPDName;
233 $this->selectedPPD = $tmp3;
234 $this->getPrinterReload();
235 return($PPDName);
236 }
239 /* This function adds a new ppd file to the list of available ppds.
240 All required paths and files will be created
241 $_PathOnHdd e.g. = /tmp/PHP_tmpfile213452 */
242 function AddPPD($_PathOnHdd,$overwrite = FALSE)
243 {
244 /* Check if file exists && is readable */
245 if((!is_file($_PathOnHdd)) || (!is_readable($_PathOnHdd))){
246 msg_dialog::display(_("PPD error"), msgPool::cannotReadFile($_PathOnHdd), ERROR_DIALOG);
247 return(false);
248 }
250 /* Reload list to detect changes e.g. a file has been deleted */
251 $this->getPrinterReload();
253 /* Get Description from ppd, & parse out some informations */
254 $res = @$this->ppdManager->loadDescription($_PathOnHdd);
255 if($res){
256 $tmp = split("\n",$res);
257 $name = trim(preg_replace("/^\-/","",trim($tmp[1])));
258 $vendor = trim($tmp[0]);
259 $model = trim(preg_replace("/".$vendor."/","",$name));
260 }
262 /* Check if parse was successfull */
263 if(empty($name) || empty($vendor)){
264 msg_dialog::display(_("PPD error"), sprintf(_("Cannot parse PPD '%s'!"), $_PathOnHdd), ERROR_DIALOG);
265 return(false);
266 }
268 /* Prepare list of ppds */
269 if(!isset($this->ppdList[$vendor])){
270 $this->ppdList[$vendor] = array();
271 }
273 /* Create ppd file and fill in the source contents */
274 $ppdname = $vendor."/".$name.".ppd";
275 $filename = $this->pathToPPD.preg_replace("/[^a-z0-9-_\.\/]/i","_",$ppdname);
276 $filename = $this->pathToPPD.$ppdname;
277 $contents = file_get_contents($_PathOnHdd);
280 /* Check if this ppd already exists */
281 $found = false;
282 foreach($this->ppdList[$vendor] as $key => $val){
283 if(preg_match("/".$model.".*/i",$key)){
284 $found = true;
285 if(!$overwrite){
286 if(!copy($_PathOnHdd,$_PathOnHdd."_back")){
287 msg_dialog::display(_("PPD error"), msgPool::cannotReadFile($_PathOnHdd), ERROR_DIALOG);
288 }else{
289 $this->add_ppd_later = $_PathOnHdd."_back";
290 $this->add_later_msg_dialog = new msg_dialog(_("Overwrite existing PPD"),
291 _("There is already a ppd file for this kind of printer. Do you want to overwrite it?"),CONFIRM_DIALOG);
292 }
293 return;
294 }
295 }
296 }
298 /* Create the vendors path, if it doesn't exists already */
299 if(!is_dir($this->pathToPPD.$vendor)){
300 if(!(@mkdir($this->pathToPPD.$vendor))){
301 msg_dialog::display(_("PPD error"), msgPool::cannotCreateFolder($this->pathToPPD.$vendor), ERROR_DIALOG);
302 return(false);
303 }
304 }
306 /* Open file handle */
307 $fp = fopen($filename,"w+");
309 /* Check file handle & contents */
310 if(!$fp){
311 msg_dialog::display(_("PPD error"), msgPool::cannotWriteFile($filename), ERROR_DIALOG);
312 return;
313 }
314 if(empty($contents)){
315 msg_dialog::display(_("PPD error"), msgPool::incorrectUpload(_("file is empty")), ERROR_DIALOG);
316 return;
317 }
319 /* Fille file with data */
320 fputs($fp,$contents);
321 @fclose($fp);
323 /* Our job is done here */
324 return($ppdname);
325 }
328 /* This function reloads the list of available printers/vendors
329 $this->ppdListHeader
330 Compaq => 1
331 $this->ppdList
332 Compaq => Compaq IJ1200 => name => Compaq IJ1200
333 link => /var/spool/ppd/Compaq/Compaq-J1200.ppd
334 ppd => Compaq - Co
335 */
336 function getPrinterReload()
337 {
338 if(is_readable($this->pathToPPD)){
339 $tmp = @$this->ppdManager->getPrinterList(true);
341 $this->ppdListHeader = $this->ppdList = array();
343 /* Sort all available files, and create header (Vendor index) */
344 foreach($tmp as $file=>$ppd){
346 if(preg_match("#".$this->pathToModified."#",$file)) continue;
348 $tmp2 = split("\n",$ppd);
349 if(!isset($this->ppdListHeader[$tmp2[0]])){
350 $this->ppdListHeader[$tmp2[0]]=0;
351 }
352 $tmp3['name'] =preg_replace("/^ -/","",$tmp2[1]." - ".$tmp2[2]);
353 $tmp3['link'] =$file;
354 $tmp3['ppd'] =$ppd;
355 $this->ppdListHeader[$tmp2[0]]++;
356 $this->ppdList[$tmp2[0]][preg_replace("/^ -/","",$tmp2[1]." - ".$tmp2[2])]=$tmp3;
357 }
358 }
359 }
362 /* Save all options posted from ppd dialog */
363 function save_object()
364 {
365 if(!((isset($_POST['PPDDisSubmitted'])) && (is_array($this->ppdConfig)))){
366 return;
367 }
369 foreach($this->ppdConfig as $cat => $obj){
370 foreach($obj as $attr => $attributes){
371 if(isset($_POST[base64_encode($attributes['_name'])])){
372 $this->ppdConfig[$cat][$attr]['_default'] = $_POST[base64_encode($attributes['_name'])];
373 }
374 }
375 }
376 }
379 /* Save modified ppd */
380 function save_ppd()
381 {
382 if($this->ppdManager){
383 $this->ppdManager->saveProperties($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'],$this->ppdConfig);
384 }
385 }
388 /* Return selected ppd path, if none is selected then false */
389 function save()
390 {
391 /* return the selected PPD, and in future the selected options too */
392 return($this->pathToModified.$this->selectedPPD['link']);
393 }
396 /* Get Information for a single PPD entry
397 * This will be shown on top of template
398 */
399 function getPPDInformation()
400 {
401 $str = "none";
402 if(!empty($this->selectedPPD)){
403 $str = $this->ppdManager->loadDescription($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link']);
404 }
405 return($str) ;
406 }
409 /* Display all options from the selected ppd file */
410 function generateProperties()
411 {
412 /* Set Headline */
413 $str = "";
414 $feed= "";
416 $s_ppd = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
418 /* If ppd exists and is readable */
419 if((!empty($this->selectedPPD['link']))&&(file_exists($s_ppd))){
421 /* If there is no initial Configuration, load it */
422 if($this->ppdConfig == false){
423 $this->ppdConfig = $this->ppdManager->loadProperties($s_ppd);
424 }
426 /* Create a table */
427 $str .= "<div style='padding-left:30px;'><table summary=''>";
429 /* Input all data to the table */
430 foreach($this->ppdConfig as $cat => $obj){
432 /* Add new category */
433 $str .= "<tr><td colspan='2'>$feed";
434 if ($feed == ""){
435 $feed= "<br>";
436 }
437 $str .= "<b>"._("Section")." '".$cat."' </b><br>";
438 $str .= "</td></tr>";
440 /* Add attributes of the current category */
441 foreach($obj as $attr => $settings){
443 /* Skip all entries beginning with _ */
444 if($attr[0] == "_") continue;
446 /* Prepare data */
447 $values = array();
448 $name = $settings['_name'];
450 if (!isset($settings['_default'])){
451 $default = "";
452 } else {
453 $default = $settings['_default'];
454 }
456 $type = $settings['_type'];
458 /* Add name to table */
459 $str .= "<tr><td style='padding-left:40px;'>\n";
460 $str .= $name."<br>\n";
461 $str .= "</td><td>\n";
463 /* Get all values */
464 foreach( $settings as $vname => $value){
465 if($vname[0] != "_"){
466 $values[$vname]= $value;
467 }
468 }
470 /* preparing Html output
471 * Supported types are PickOne/Boolean
472 */
474 /* If type is PickOne, create a select box */
475 if(($type == "PickOne")||(($type=="Boolean")&&(count($values)>1))){
477 $str .= "<select name='".base64_encode($name)."'>\n";
478 foreach($values as $optionKey => $value){
479 $selected = "";
480 if($optionKey == $default){
481 $selected = " selected ";
482 }
483 $str .= "<option value='".$optionKey."' ".$selected.">".$value."</option>\n";
484 }
485 $str .= "</select>\n";
487 }elseif($type == "Boolean"){
489 /* If type is Boolean & no values are given */
490 $str .= "<select name='".base64_encode($name)."'>\n";
491 if($default == "False"){
492 $str .= "<option value='True' >"._("True")."</option>\n";
493 $str .= "<option value='False' selected>"._("False")."</option>\n";
494 }else{
495 $str .= "<option value='True' selected>"._("True")."</option>\n";
496 $str .= "<option value='False' >"._("False")."</option>\n";
497 }
498 $str .= "</select>\n";
500 }else{
501 msg_dialog::display(_("PPD error"), sprintf(_("PPD type '%s' is not supported!"), $type), ERROR_DIALOG);
502 }
503 $str .= "</td></tr>\n";
504 }
505 }
506 $str .= "</table></div>\n";
507 }
508 return($str);
509 }
511 function removeModifiedPPD()
512 {
513 $path = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
515 if(file_exists($path)){
516 if(is_writeable($path)){
517 if(!@unlink($path)){
518 msg_dialog::display(_("PPD error"), msgPool::cannotDeleteFile($path), ERROR_DIALOG);
519 }
520 }else{
521 msg_dialog::display(_("PPD error"), msgPool::cannotDeleteFile($path), ERROR_DIALOG);
522 }
523 }else{
524 msg_dialog::display(_("PPD error"), msgPool::cannotDeleteFile($path), ERROR_DIALOG);
525 }
526 }
528 function update_ppd_url()
529 {
530 $this->SelectPPD("modified/".$this->selectedPPD['link']);
531 return("modified/".$this->selectedPPD['link']);
532 }
534 function check()
535 {
536 $message = plugin::check();
537 if(empty($this->selectedPPD['link'])){
538 $message[] = _("Please select a valid ppd file or use 'Cancel' to go back to printer configuration.");
539 }
540 return($message);
541 }
542 }
543 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
544 ?>