Code

Display all available printer drivers for each model. Collect
[gosa.git] / trunk / gosa-plugins / goto / admin / systems / ppd / class_printerPPDDialog.inc
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  
20       
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($config->get_cfg_value("ppdPath") != ""){
39       $this->pathToPPD = $config->get_cfg_value("ppdPath");
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     /* Check if ppdPath is set in gosa.conf. 
49      */
50     if(empty($this->pathToPPD)){
51       msg_dialog::display(_("Configuration error"), msgPool::invalidConfigurationAttribute("ppdPath"), ERROR_DIALOG);
52     }
54     /* It seams that we have an existing PPD path, so go on */
55     if(!((!is_dir($this->pathToPPD))||(empty($this->pathToPPD)))){ 
57       /* Load all available PPD files and sort them into an array */
58       $this->ppdManager= new ppdManager($this->pathToPPD);
59       $this->getPrinterReload ();
61       /* The user has already a valid PPD assigned
62        * Get some informations about this PPD
63        * and set it as selected. 
64        * The ppdpath ['link'] should be relative from .../ppd/modified/ 
65        *     e.g. "/Compaq/Compaq-J1200.ppd" */
66       if(($ppdfile!== NULL)&&(strlen($ppdfile)>0)){
67         $ppdfile = preg_replace("#".$this->pathToModified."#","",$ppdfile);
68         if(!file_exists($this->pathToPPD.$this->pathToModified.$ppdfile)){
69           msg_dialog::display(_("PPD error"), sprintf(_("Cannot open PPD '%s'!"), $ppdfile), ERROR_DIALOG);
70         }else{
71           $ppdDesc = $this->ppdManager->loadDescription($this->pathToPPD.$this->pathToModified.$ppdfile);
72           if($ppdDesc){            
73             $selectedPPD = array(); 
74             $selectedPPD['name']   = $ppdDesc['name'];
75             $selectedPPD['link']   = $ppdfile;
76             $selectedPPD['ppd']    = $ppdDesc;
77           }    
78           $this->selectedPPD = $selectedPPD;
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", "");
95     $smarty->assign("path_valid", TRUE);
97     if(empty($this->pathToPPD)){
99         /* Print out template */
100         $smarty->assign("path_valid", FALSE);
101         $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
102         return($display);
103     }
105     /* Check these paths */
106     $paths = array($this->pathToPPD, $this->pathToPPD.$this->pathToModified);
108     /* If one of our required paths is not available, stop here and display some info */
109     foreach($paths as $path){
110     
111       /* Check if path is write/readable*/
112       $is_r = @is_readable($path);  
113       if(((!is_dir($path))||(empty($path)) || (!$is_r)) && (!@mkdir($path))){
114         msg_dialog::display(_("Configuration error"), sprintf(_("Cannot open PPD path '%s' for reading and writing!"), $path), ERROR_DIALOG);
116         /* Print out template */
117         $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
118         return($display);
119       }
120     }
122     // PPD selection / upload / dialog handling 
124     /* Is there a new PPD file uploaded ? */
125     if((isset($_FILES['NewPPDFile']))&&(isset($_POST['SubmitNewPPDFile']))){
126       $file = ($_FILES['NewPPDFile']);
127       if($file['size'] != 0 ){
128         if($name = $this->AddPPD($file['tmp_name'])){
129           $this->SelectPPD($name); 
130         }
131       }else{
132         msg_dialog::display(_("PPD error"), msgPool::incorrectUpload(_("file is empty")), ERROR_DIALOG);
133       }
134     }
136     /* Overwrite existing PPD file and select it as currently used for this object */
137     if(is_object($this->add_later_msg_dialog) && ($this->add_later_msg_dialog->is_confirmed()) && $this->add_ppd_later != ""){
138       if($name = $this->AddPPD($this->add_ppd_later,TRUE)){
139         $this->SelectPPD($name);
140       }
141       $this->add_ppd_later = "";
142       $this->add_later_msg_dialog = NULL;
143     } 
145     /* Open a dialog that allow us to select different PPDs */
146     if(isset($_POST['SelectPPD'])){
147       $this->dialog= new printerPPDSelectionDialog($this->config,$this->dn,$this->ppdList,$this->ppdListHeader,$this->selectedPPD);
148     }
150     /* The selection dialog fpr PPDs is canceled */
151     if(isset($_POST['ClosePPDSelection'])){
152       unset($this->dialog);
153       $this->dialog=FALSE;
154     }
156     /* Div Selection */ 
157     if((isset($_GET['act']))&&($_GET['act']=="use")){
158       $this->SelectPPD(base64_decode($_GET['id']));
159       unset($this->dialog);
160       $this->dialog=FALSE;
162     }
164     /* if a dialog is open, print the dialog instead of this class */
165     if(is_object($this->dialog)){
166       $display = $this->dialog->execute();
167       return($display);
168     }
170     // ENDE  PPD selection / upload / dialog handling 
172     /* Give smarty the information it needs */
173     $smarty->assign("ppdString" ,$this->getPPDInformation());
174     $tmp= $this->generateProperties();
175     if ($tmp == ""){
176       $smarty->assign("showOptions", 0);
177     } else {
178       $smarty->assign("showOptions", 1);
179       $smarty->assign("properties",$this->generateProperties());
180     }
182     /* Print out template */
183     $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
184     return($display);
185   }
188   /* Select PPD */
189   function SelectPPD($name)
190   {
191     /* Replace base path we don't need it here 
192        The path we need looks like this : "/Vendor/ModellName.ppd"; 
193        thats all */
194     $name = preg_replace("#".$this->pathToPPD."#","",$name);
196     /* Intialise some base vars */
197     $AbsoluteSourceName       = $this->pathToPPD.$name;   
198     $AbsoluteDestinationPath  = $this->pathToPPD.$this->pathToModified;
199     $Vendor                   = ""; // Vendor 
200     $Name                     = ""; // Name 
201     $Modell                   = ""; // Modell
202     $PrinterName              = ""; // The new name of the printer 
203     $PPDName                  = "";
204  
205     /* Force reload of config dialog */ 
206     $this->ppdConfig            = false;
207     $this->selectedPPD['link']  = false;
209     /* Get PPD informations and set vendor / modell / name */ 
210     if((!file_exists($AbsoluteSourceName)) || (!is_readable($AbsoluteSourceName))){
211       msg_dialog::display(_("PPD error"), msgPool::cannotReadFile($AbsoluteSourceName), ERROR_DIALOG);
212       return;
213     }
214     $ppdDesc  = $this->ppdManager->loadDescription($AbsoluteSourceName);
215     if($ppdDesc){
216       $Name   = $ppdDesc['name'];
217       $Vendor = $ppdDesc['manufacturer'];
218       $Model  = $ppdDesc['model'];
219     }    
221     $PrinterName  = $this->cn."-".preg_replace("/[^a-z0-9-_\.]/i","_",$Name);
222     $PPDName      = $Vendor."/".$PrinterName.".ppd";
223     
224     /* Create the vendors path, if it doesn't exists already */
225     if(!is_dir($AbsoluteDestinationPath.$Vendor)){
226       if(!(@mkdir($AbsoluteDestinationPath.$Vendor))){
227         msg_dialog::display(_("PPD error"), msgPool::cannotCreateFolder($AbsoluteDestinationPath.$Vendor), ERROR_DIALOG);
228         return(false);
229       }
230     }
232     /* Create destination file handle */
233     $fp = @fopen($AbsoluteDestinationPath.$PPDName,"w+");
234     if(!$fp){
235       msg_dialog::display(_("PPD error"), msgPool::cannotWriteFile($AbsoluteDestinationPath.$PPDName), ERROR_DIALOG);
236       return(false);
237     }
239     $str = file_get_contents($AbsoluteSourceName);
240     fputs($fp,$str);
241     @fclose($fp);
243     //$this->ppdManager->updateAttribute($filename,"NO_SECTION","ModelName",$printerName);
245     $tmp3['link']   =$PPDName;
246     $this->selectedPPD = $tmp3;
247     $this->getPrinterReload(); 
248     return($PPDName);
249   }
252   /* This function adds a new ppd file to the list of available ppds. 
253      All required paths and files will be created 
254       $_PathOnHdd e.g. = /tmp/PHP_tmpfile213452 */
255   function AddPPD($_PathOnHdd,$overwrite = FALSE)
256   {
257     /* Check if file exists && is readable */
258     if((!is_file($_PathOnHdd)) || (!is_readable($_PathOnHdd))){
259       msg_dialog::display(_("PPD error"), msgPool::cannotReadFile($_PathOnHdd), ERROR_DIALOG);
260       return(false);
261     }
262     
263     /* Reload list to detect changes e.g. a file has been deleted */
264     $this->getPrinterReload();
266     /* Get Description from ppd, & parse out some informations */   
267     $ppdDesc  = @$this->ppdManager->loadDescription($_PathOnHdd);
268     if($ppdDesc){
269       $name   = $ppdDesc['name'];
270       $vendor = $ppdDesc['manufacturer'];
271       $model  = $ppdDesc['model'];
272     }    
274     /* Check if parse was successfull */
275     if(empty($name) || empty($vendor)){
276       msg_dialog::display(_("PPD error"), sprintf(_("Cannot parse PPD '%s'!"), $_PathOnHdd), ERROR_DIALOG);
277       return(false);
278     }
280     /* Prepare list of ppds */
281     if(!isset($this->ppdList[$vendor])){
282       $this->ppdList[$vendor] = array();
283     }
285     /* Create ppd file and fill in the source contents */
286     $ppdname      = $vendor."/".$name.".ppd";
287     $filename     = $this->pathToPPD.preg_replace("/[^a-z0-9-_\.\/]/i","_",$ppdname);
288     $filename     = $this->pathToPPD.$ppdname;
289     $contents     = file_get_contents($_PathOnHdd);
292     /* Check if this ppd already exists */
293     $found = false;
294     foreach($this->ppdList[$vendor] as $key => $val){
295       if(preg_match("/".$model.".*/i",$key)){
296         $found = true;
297         if(!$overwrite){
298           if(!copy($_PathOnHdd,$_PathOnHdd."_back")){
299             msg_dialog::display(_("PPD error"), msgPool::cannotReadFile($_PathOnHdd), ERROR_DIALOG);
300           }else{
301             $this->add_ppd_later = $_PathOnHdd."_back";
302             $this->add_later_msg_dialog = new msg_dialog(_("Overwrite existing PPD"),
303                 _("There is already a ppd file for this kind of printer. Do you want to overwrite it?"),CONFIRM_DIALOG);
304           }
305           return;
306         }
307       }
308     }
310     /* Create the vendors path, if it doesn't exists already */
311     if(!is_dir($this->pathToPPD.$vendor)){
312       if(!(@mkdir($this->pathToPPD.$vendor))){
313         msg_dialog::display(_("PPD error"), msgPool::cannotCreateFolder($this->pathToPPD.$vendor), ERROR_DIALOG);
314         return(false);
315       }
316     }
317   
318     /* Open file handle */
319     $fp           = fopen($filename,"w+");
321     /* Check file handle & contents */
322     if(!$fp){
323       msg_dialog::display(_("PPD error"), msgPool::cannotWriteFile($filename), ERROR_DIALOG);
324       return;
325     }
326     if(empty($contents)){
327       msg_dialog::display(_("PPD error"), msgPool::incorrectUpload(_("file is empty")), ERROR_DIALOG);
328       return;
329     }
330     
331     /* Fille file with data */
332     fputs($fp,$contents);
333     @fclose($fp);
335     /* Our job is done here */
336     return($ppdname);
337   }
340   /* This function reloads the list of available printers/vendors 
341      $this->ppdListHeader 
342      Compaq        => 1
343      $this->ppdList
344      Compaq => Compaq IJ1200 => name => Compaq IJ1200 
345      link => /var/spool/ppd/Compaq/Compaq-J1200.ppd
346      ppd  => Compaq - Co    
347    */
348   function getPrinterReload()
349   {
350     if(is_readable($this->pathToPPD)){
351       $tmp = @$this->ppdManager->getPrinterList(true);
353       $this->ppdListHeader = $this->ppdList = array();
355       /* Sort all available files, and create header (Vendor index) */
356       foreach($tmp as $file=>$ppd){
357                 
358         if(preg_match("#".$this->pathToModified."#",$file)) continue;
360         if(!isset($this->ppdListHeader[$ppd['manufacturer']])){
361           $this->ppdListHeader[$ppd['manufacturer']]=0;
362         }
363        
364         $tmp3['name']   =$ppd['name'];
365         $tmp3['link']   =$file;
366         $tmp3['ppd']    =$ppd;
367         $this->ppdListHeader[$ppd['manufacturer']]++;
368         if (isset($this->ppdList[$ppd['manufacturer']][$ppd['name']])) {
370           # Printer exists already, add directory/nickname to identify it
371           
372           $tmp4 = $this->ppdList[$ppd['manufacturer']][$ppd['name']]['link'];
374           # Remove the default path (e.g. /srv/www/ppd) plus a possible debian/ directory
375           $extension = preg_replace("#".$this->pathToPPD."/(debian/)?#", "", $tmp3['link']);
377           # Remove all further directories, just keep the first level (e.g. foomatic-rip, hpijs)
378           $extension = preg_replace("#/.*#", "", $extension);
380           # Add the nickname as well to distinguish between two drivers for the same model in one directory
381           $extension = $extension." / ".$ppd['nickname'];
383           # Generate the updated extension from the original path and nickname, same way as above
384           $updated_nickname = $this->ppdList[$ppd['manufacturer']][$ppd['name']]['ppd']['nickname'];
385           $updated_extension = preg_replace("#".$this->pathToPPD."/(debian/)?#", "", $tmp4);
386           $updated_extension = preg_replace("#/.*#", "", $updated_extension);
387           $updated_extension = $updated_extension." / ".$updated_nickname;
388           $updated_name = $ppd['name']." ($updated_extension)";
390           if (!isset($this->ppdList[$ppd['manufacturer']][$updated_name]['name'])) {
391             $old_ppd = array_keys($this->ppdList[$ppd['manufacturer']][$ppd['name']]);
392             # Copy old printer attributes to new name
393             foreach($old_ppd as $entry){ 
394                $this->ppdList[$ppd['manufacturer']][$updated_name][$entry] = $this->ppdList[$ppd['manufacturer']][$ppd['name']][$entry];
395             }  
397             # Add old printer under updated name
398             $this->ppdList[$ppd['manufacturer']][$updated_name]['name'] = $updated_name;
399             $this->ppdList[$ppd['manufacturer']][$updated_name]['ppd']['name'] = $ppd['name']." ($updated_extension)";
400             $this->ppdList[$ppd['manufacturer']][$updated_name]['ppd']['model'] = $ppd['model']." ($updated_extension)";
401           }
402           
403           # Now generate name/model including extension for new printer
404           $tmp3['ppd']['name'] = $tmp3['name']." ($extension)";
405           $tmp3['ppd']['model'] = $tmp3['ppd']['model']." ($extension)";
406           $tmp3['name'] = $tmp3['name']." ($extension)";
407           $myname = $tmp3['name'];
408         }
409         $this->ppdList[$ppd['manufacturer']][$tmp3['name']]=$tmp3;
410       }
412       # Remove all non-nicknamed/directorized printers from list who have a
413       # nicknamed counterpart already, those are dupes.
414       foreach($this->ppdList as $manufacturer => $printers) {
415         foreach($printers as $ppd) {
416           $to_remove = preg_replace("/ \(.*\)$/", "", $ppd['name']); 
417           if ($to_remove != $ppd['name'] && isset($this->ppdList[$manufacturer][$to_remove])) {
418             unset($this->ppdList[$manufacturer][$to_remove]);
419           }
420         }
421       }
422     }
423   }
426   /* Save all options posted from ppd dialog */
427   function save_object()
428   {
429     if(!((isset($_POST['PPDDisSubmitted'])) && (is_array($this->ppdConfig)))){
430       return;
431     }
433     foreach($this->ppdConfig as $cat => $obj){
434       foreach($obj as $attr => $attributes){
435         if(isset($_POST[base64_encode($attributes['_name'])])){
436           $this->ppdConfig[$cat][$attr]['_default'] = $_POST[base64_encode($attributes['_name'])];
437         }
438       }
439     }
440   }
443   /* Save modified ppd */
444   function save_ppd()
445   {
446     if($this->ppdManager){
447       $this->ppdManager->saveProperties($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'],$this->ppdConfig);
448     }
449   }
452   /* Return selected ppd path, if none is selected then false */
453   function save()
454   {
455     /* return the selected PPD, and in future the selected options too */
456     return($this->pathToModified.$this->selectedPPD['link']);
457   }
460   /* Get Information for a single PPD entry 
461    * This will be shown on top of template
462    */
463   function getPPDInformation()
464   {
465     $str = "none";
466     if(!empty($this->selectedPPD)){
467       $ppdDesc = $this->ppdManager->loadDescription($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link']);
468       $str = $ppdDesc['name'];
469     }
470     return($str) ; 
471   }
473   /* Display all options from the selected ppd file */
474   function generateProperties()
475   { 
476     /* Set Headline */
477     $str = "";
478     $feed= "";
480     $s_ppd = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
482     /* If ppd exists and is readable */
483     if((!empty($this->selectedPPD['link']))&&(file_exists($s_ppd))){
485       /* If there is no initial Configuration, load it */
486       if($this->ppdConfig == false){
487         $this->ppdConfig = $this->ppdManager->loadProperties($s_ppd);
488       }
490       /* Create a table */
491       $str .= "<div style='padding-left:30px;'><table summary=''>";
493       /* Input all data to the table */
494       foreach($this->ppdConfig as $cat => $obj){
496         /* Add new category */
497         $str .= "<tr><td colspan='2'>$feed";
498         if ($feed == ""){
499           $feed= "<br>";
500         }
501         $str .= "<b>"._("Section")." '".$cat."'&nbsp;</b><br>";
502         $str .= "</td></tr>";       
504         /* Add attributes of the current category */
505         foreach($obj as $attr => $settings){
507           /* Skip all entries beginning with _ */
508           if($attr[0] == "_") continue;  
510           /* Prepare data */
511           $values   = array();
512           $name     = $settings['_name'];
514           if (!isset($settings['_default'])){
515             $default  = "";
516           } else {
517             $default  = $settings['_default'];
518           }
520           $type     = $settings['_type'];
522           /* Add name to table */ 
523           $str .= "<tr><td style='padding-left:40px;'>\n";
524           $str .= $name."<br>\n";
525           $str .= "</td><td>\n";
527           /* Get all values */ 
528           foreach( $settings as $vname => $value){
529             if($vname[0] != "_"){
530               $values[$vname]= $value;
531             }
532           }
534           /* preparing Html output
535            * Supported types are PickOne/Boolean
536            */
538           /* If type is PickOne, create a select box */
539           if(($type == "PickOne")||(($type=="Boolean")&&(count($values)>1))){
541             $str  .=  "<select name='".base64_encode($name)."'>\n";
542             foreach($values as $optionKey => $value){
543               $selected = "";
544               if($optionKey == $default){
545                 $selected = " selected ";
546               }
547               $str  .=  "<option value='".$optionKey."' ".$selected.">".$value."</option>\n";
548             }
549             $str  .=  "</select>\n";
551           }elseif($type == "Boolean"){
553             /* If type is Boolean & no values are given */
554             $str  .=  "<select name='".base64_encode($name)."'>\n";
555             if($default == "False"){
556               $str  .=    "<option value='True' >"._("True")."</option>\n";
557               $str  .=    "<option value='False' selected>"._("False")."</option>\n";
558             }else{
559               $str  .=    "<option value='True' selected>"._("True")."</option>\n";
560               $str  .=    "<option value='False' >"._("False")."</option>\n";
561             }          
562             $str  .=  "</select>\n";
564           }else{
565             msg_dialog::display(_("PPD error"), sprintf(_("PPD type '%s' is not supported!"), $type), ERROR_DIALOG);
566           }
567           $str .= "</td></tr>\n";
568         }
569       }
570       $str .= "</table></div>\n";
571     }
572     return($str);
573   }
575   function removeModifiedPPD()
576   {
577     $path = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
579     if(file_exists($path)){
580       if(is_writeable($path)){
581         if(!@unlink($path)){
582           msg_dialog::display(_("PPD error"), msgPool::cannotDeleteFile($path), ERROR_DIALOG);
583         }
584       }else{
585         msg_dialog::display(_("PPD error"), msgPool::cannotDeleteFile($path), ERROR_DIALOG);
586       }
587     }else{
588       msg_dialog::display(_("PPD error"), msgPool::cannotDeleteFile($path), ERROR_DIALOG);
589     }
590   }
592   function update_ppd_url()
593   {
594     $this->SelectPPD("modified/".$this->selectedPPD['link']);
595     return("modified/".$this->selectedPPD['link']);
596   }
597   
598   function check()
599   {  
600     $message = plugin::check();
601     if(empty($this->selectedPPD['link'])){
602       $message[] = _("Please select a valid ppd file or use 'Cancel' to go back to printer configuration.");
603     }
604     return($message); 
605   }
607 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
608 ?>