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 $dialog = NULL; // Contains sub dialogs
25 function printerPPDDialog ($config, $dn= NULL,$ppdfile=NULL )
26 {
27 plugin::plugin ($config, $dn);
28 $this->depselect = $this->config->current['BASE'];
30 /* Get PPD path and remove double //, and add trailing / */
31 if(isset($_SESSION['config']->data['MAIN']['PPD_PATH'])){
32 $this->pathToPPD = $_SESSION['config']->data['MAIN']['PPD_PATH'];
33 $this->pathToPPD= preg_replace("/\/\//", "/", $this->pathToPPD);
34 if(!preg_match("/\/$/",$this->pathToPPD)){
35 $this->pathToPPD = $this->pathToPPD."/";
36 }
37 }else{
38 $this->pathToPPD = "";
39 }
41 /* It seams that we have an existing PPD path, so go on */
42 if(!((!is_dir($this->pathToPPD))||(empty($this->pathToPPD)))){
44 /* Load all available PPD files and sort them into an array */
45 require_once ("class_ppdManager.inc");
46 $this->ppdManager= new ppdManager($this->pathToPPD);
47 $this->getPrinterReload ();
49 /* The user has already a valid PPD assigned
50 * Get some informations about this PPD
51 * and set it as selected.
52 * The ppdpath ['link'] should be relative from .../ppd/modified/
53 * e.g. "/Compaq/Compaq-J1200.ppd" */
54 if(($ppdfile!= NULL)&&(strlen($ppdfile)>0)){
55 $ppdfile = preg_replace("#".$this->pathToModified."#","",$ppdfile);
56 if(!file_exists($this->pathToPPD.$this->pathToModified.$ppdfile)){
57 print_red(sprintf(_("Can't open '%s', ppd settings resetted."),$ppdfile));
58 }else{
59 $res = $this->ppdManager->loadDescription($this->pathToPPD.$this->pathToModified.$ppdfile);
60 if($res){
61 $tmp = split("\n",$res);
62 $tmp3 = array();
63 $tmp3['name'] = trim(preg_replace("/^\-/","",trim($tmp[1])));
64 $tmp3['link'] = $ppdfile;
65 $tmp3['ppd'] = $res;
66 }
67 $this->selectedPPD = $tmp3;
68 }
69 }
70 }
71 }
74 function execute()
75 {
76 /* Call parent execute */
77 plugin::execute();
79 /* Fill templating stuff */
80 $display= "";
81 $smarty= get_smarty();
82 $smarty->assign("ppdString", _("Can't get ppd informations."));
83 $smarty->assign("showOptions", "");
85 /* Check these paths */
86 $paths = array($this->pathToPPD, $this->pathToPPD.$this->pathToModified);
88 /* If one of our required paths is not available, stop here and display some info */
89 foreach($paths as $path){
91 /* Check if path is write/readable*/
92 $is_r = @is_readable($path);
93 if(((!is_dir($path))||(empty($path)) || (!$is_r)) && (!@mkdir($path))){
94 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));
95 /* Print out template */
96 $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
97 return($display);
98 }
99 }
101 // PPD selection / upload / dialog handling
103 /* Is there a new PPD file uploaded ? */
104 if((isset($_FILES['NewPPDFile']))&&(isset($_POST['SubmitNewPPDFile']))){
105 $file = ($_FILES['NewPPDFile']);
106 if($file['size'] != 0 ){
107 if($name = $this->AddPPD($file['tmp_name'])){
108 $this->SelectPPD($name);
109 }
110 }else{
111 print_red(_("Please specify a valid ppd file."));
112 }
113 }
115 /* Open a dialog that allow us to select different PPDs */
116 if(isset($_POST['SelectPPD'])){
117 $this->dialog= new printerPPDSelectionDialog($this->config,$this->dn,$this->ppdList,$this->ppdListHeader,$this->selectedPPD);
118 }
120 /* The selection dialog fpr PPDs is canceled */
121 if(isset($_POST['ClosePPDSelection'])){
122 unset($this->dialog);
123 $this->dialog=NULL;
124 }
126 /* Div Selection */
127 if((isset($_GET['act']))&&($_GET['act']=="use")){
128 $this->SelectPPD(base64_decode($_GET['id']));
129 unset($this->dialog);
130 $this->dialog=NULL;
132 }
134 /* if a dialog is open, print the dialog instead of this class */
135 if($this->dialog!=NULL){
136 $display = $this->dialog->execute();
137 return($display);
138 }
140 // ENDE PPD selection / upload / dialog handling
142 /* Give smarty the information it needs */
143 $smarty->assign("ppdString" ,$this->getPPDInformation());
144 $tmp= $this->generateProperties();
145 if ($tmp == ""){
146 $smarty->assign("showOptions", 0);
147 } else {
148 $smarty->assign("showOptions", 1);
149 $smarty->assign("properties",$this->generateProperties());
150 }
152 /* Print out template */
153 $display.= $smarty->fetch(get_template_path('printerPPDDialog.tpl', TRUE,dirname(__FILE__)));
154 return($display);
155 }
158 /* Select PPD */
159 function SelectPPD($name)
160 {
161 /* Replace base path we don't need it here
162 The path we need looks like this : "/Vendor/ModellName.ppd";
163 thats all */
164 $name = preg_replace("#".$this->pathToPPD."#","",$name);
166 /* Intialise some base vars */
167 $AbsoluteSourceName = $this->pathToPPD.$name;
168 $AbsoluteDestinationPath = $this->pathToPPD.$this->pathToModified;
169 $Vendor = ""; // Vendor
170 $Name = ""; // Name
171 $Modell = ""; // Modell
172 $PrinterName = ""; // The new name of the printer
173 $PPDName = "";
175 /* Force reload of config dialog */
176 $this->ppdConfig = false;
177 $this->selectedPPD['link'] = false;
179 /* Get PPD informations and set vendor / modell / name */
180 if((!file_exists($AbsoluteSourceName)) || (!is_readable($AbsoluteSourceName))){
181 print_red(sprintf(_("Can't select PPD file '%s', the file is not readable"),$AbsoluteSourceName));
182 return;
183 }
184 $res = $this->ppdManager->loadDescription($AbsoluteSourceName);
185 if($res){
186 $tmp = split("\n",$res);
187 $Name = trim(preg_replace("/^\-/","",trim($tmp[1])));
188 $Vendor = trim($tmp[0]);
189 $Model = trim(preg_replace("/".$Vendor."/","",$Name));
190 }
192 $PrinterName = $this->cn."-".$Name;
193 $PPDName = $Vendor."/".$PrinterName.".ppd";
195 /* Create the vendors path, if it doesn't exists already */
196 if(!is_dir($AbsoluteDestinationPath.$Vendor)){
197 if(!(@mkdir($AbsoluteDestinationPath.$Vendor))){
198 print_red(sprintf(_("Can't create folder '%s' for the uploaded ppd file."),$AbsoluteDestinationPath.$Vendor));
199 return(false);
200 }
201 }
203 /* Create destination file handle */
204 $fp = @fopen($AbsoluteDestinationPath.$PPDName,"w+");
205 if(!$fp){
206 print_red(sprintf(_("Can't create file '%s' to store modifed ppd informations."),$AbsoluteDestinationPath.$PPDName));
207 return(false);
208 }
210 $str = file_get_contents($AbsoluteSourceName);
211 fputs($fp,$str);
212 @fclose($fp);
214 //$this->ppdManager->updateAttribute($filename,"NO_SECTION","ModelName",$printerName);
216 $tmp3['link'] =$PPDName;
217 $this->selectedPPD = $tmp3;
218 $this->getPrinterReload();
219 return($PPDName);
220 }
223 /* This function adds a new ppd file to the list of available ppds.
224 All required paths and files will be created
225 $_PathOnHdd e.g. = /tmp/PHP_tmpfile213452 */
226 function AddPPD($_PathOnHdd)
227 {
228 /* Check if file exists && is readable */
229 if((!is_file($_PathOnHdd)) || (!is_readable($_PathOnHdd))){
230 print_red(sprintf(_("Can't add new ppd file, the source file '%s' is not accessible."),$_PathOnHdd));
231 return(false);
232 }
234 /* Reload list to detect changes e.g. a file has been deleted */
235 $this->getPrinterReload();
237 /* Get Description from ppd, & parse out some informations */
238 $res = @$this->ppdManager->loadDescription($_PathOnHdd);
239 if($res){
240 $tmp = split("\n",$res);
241 $name = trim(preg_replace("/^\-/","",trim($tmp[1])));
242 $vendor = trim($tmp[0]);
243 $model = trim(preg_replace("/".$vendor."/","",$name));
244 }
246 /* Check if parse was successfull */
247 if(empty($name) || empty($vendor)){
248 print_red(sprintf(_("The given ppd file '%s' seams to be invalid, can't get any modell or vendor informations."),$_PathOnHdd));
249 return(false);
250 }
252 /* Prepare list of ppds */
253 if(!isset($this->ppdList[$vendor])){
254 $this->ppdList[$vendor] = array();
255 }
257 /* Check if this ppd already exists */
258 $found = false;
259 foreach($this->ppdList[$vendor] as $key => $val){
260 if(preg_match("/".$model.".*/i",$key)){
261 $found = true;
262 print_red(sprintf(_("There is already a ppd file for this kind of printer.")));
263 return;
264 }
265 }
267 /* Create the vendors path, if it doesn't exists already */
268 if(!is_dir($this->pathToPPD.$vendor)){
269 if(!(@mkdir($this->pathToPPD.$vendor))){
270 print_red(sprintf(_("Can't create folder '%s' for the uploaded ppd file."),$this->pathToPPD.$vendor));
271 return(false);
272 }
273 }
275 /* Create ppd file and fill in the source contents */
276 $ppdname = $vendor."/".$name.".ppd";
277 $filename = $this->pathToPPD.$ppdname;
278 $fp = fopen($filename,"w+");
279 $contents = file_get_contents($_PathOnHdd);
281 /* Check file handle & contents */
282 if(!$fp){
283 print_red(sprintf(_("Can't save file '%s'."),$filename));
284 return;
285 }
286 if(empty($contents)){
287 print_red(_("Uploaded ppd file is empty, can't create new ppd file."));
288 return;
289 }
291 /* Fille file with data */
292 fputs($fp,$contents);
293 @fclose($fp);
295 /* Our job is done here */
296 return($ppdname);
297 }
300 /* This function reloads the list of available printers/vendors
301 $this->ppdListHeader
302 Compaq => 1
303 $this->ppdList
304 Compaq => Compaq IJ1200 => name => Compaq IJ1200
305 link => /var/spool/ppd/Compaq/Compaq-J1200.ppd
306 ppd => Compaq - Co
307 */
308 function getPrinterReload()
309 {
310 if(is_readable($this->pathToPPD)){
311 $tmp = $this->ppdManager->getPrinterList(true);
313 $this->ppdListHeader = $this->ppdList = array();
315 /* Sort all available files, and create header (Vendor index) */
316 foreach($tmp as $file=>$ppd){
318 if(preg_match("#".$this->pathToModified."#",$file)) continue;
320 $tmp2 = split("\n",$ppd);
321 if(!isset($this->ppdListHeader[$tmp2[0]])){
322 $this->ppdListHeader[$tmp2[0]]=0;
323 }
324 $tmp3['name'] =preg_replace("/^ -/","",$tmp2[1]." - ".$tmp2[2]);
325 $tmp3['link'] =$file;
326 $tmp3['ppd'] =$ppd;
327 $this->ppdListHeader[$tmp2[0]]++;
328 $this->ppdList[$tmp2[0]][preg_replace("/^ -/","",$tmp2[1]." - ".$tmp2[2])]=$tmp3;
329 }
330 }
331 }
334 /* Save all options posted from ppd dialog */
335 function save_object()
336 {
337 if(!((isset($_POST['PPDDisSubmitted'])) && (is_array($this->ppdConfig)))){
338 return;
339 }
341 foreach($this->ppdConfig as $cat => $obj){
342 foreach($obj as $attr => $attributes){
343 if(isset($_POST[base64_encode($attributes['_name'])])){
344 $this->ppdConfig[$cat][$attr]['_default'] = $_POST[base64_encode($attributes['_name'])];
345 }
346 }
347 }
348 }
351 /* Save modified ppd */
352 function save_ppd(){
353 if($this->ppdManager){
354 $this->ppdManager->saveProperties($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'],$this->ppdConfig);
355 }
356 }
359 /* Return selected ppd path, if none is selected then false */
360 function save()
361 {
362 /* return the selected PPD, and in future the selected options too */
363 return($this->pathToModified.$this->selectedPPD['link']);
364 }
367 /* Get Information for a single PPD entry
368 * This will be shown on top of template
369 */
370 function getPPDInformation()
371 {
372 $str = "none";
373 if(!empty($this->selectedPPD)){
374 $str = $this->ppdManager->loadDescription($this->pathToPPD.$this->pathToModified.$this->selectedPPD['link']);
375 }
376 return($str) ;
377 }
380 /* Display all options from the selected ppd file */
381 function generateProperties()
382 {
383 /* Set Headline */
384 $str = "";
385 $feed= "";
387 $s_ppd = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
389 /* If ppd exists and is readable */
390 if((!empty($this->selectedPPD['link']))&&(file_exists($s_ppd))){
392 /* If there is no initial Configuration, load it */
393 if($this->ppdConfig == false){
394 $this->ppdConfig = $this->ppdManager->loadProperties($s_ppd);
395 }
397 /* Create a table */
398 $str .= "<div style='padding-left:30px;'><table summary=''>";
400 /* Input all data to the table */
401 foreach($this->ppdConfig as $cat => $obj){
403 /* Add new category */
404 $str .= "<tr><td colspan='2'>$feed";
405 if ($feed == ""){
406 $feed= "<br>";
407 }
408 $str .= "<b>"._("Section")." '".$cat."' </b><br>";
409 $str .= "</td></tr>";
411 /* Add attributes of the current category */
412 foreach($obj as $attr => $settings){
414 /* Skip all entries beginning with _ */
415 if($attr[0] == "_") continue;
417 /* Prepare data */
418 $values = array();
419 $name = $settings['_name'];
420 if (!isset($settings['_default'])){
421 $default = "";
422 } else {
423 $default = $settings['_default'];
424 }
425 $type = $settings['_type'];
427 /* Add name to table */
428 $str .= "<tr><td style='padding-left:40px;'>\n";
429 $str .= $name."<br>\n";
430 $str .= "</td><td>\n";
432 /* Get all values */
433 foreach( $settings as $vname => $value){
434 if($vname[0] != "_"){
435 $values[$vname]= $value;
436 }
437 }
439 /* preparing Html output
440 * Supported types are PickOne/Boolean
441 */
443 /* If type is PickOne, create a select box */
444 if(($type == "PickOne")||(($type=="Boolean")&&(count($values)>1))){
446 $str .= "<select name='".base64_encode($name)."'>\n";
447 foreach($values as $optionKey => $value){
448 $selected = "";
449 if($optionKey == $default){
450 $selected = " selected ";
451 }
452 $str .= "<option value='".$optionKey."' ".$selected.">".$value."</option>\n";
453 }
454 $str .= "</select>\n";
456 }elseif($type == "Boolean"){
458 /* If type is Boolean & no values are given */
459 $str .= "<select name='".base64_encode($name)."'>\n";
460 if($default == "False"){
461 $str .= "<option value='True' >"._("True")."</option>\n";
462 $str .= "<option value='False' selected>"._("False")."</option>\n";
463 }else{
464 $str .= "<option value='True' selected>"._("True")."</option>\n";
465 $str .= "<option value='False' >"._("False")."</option>\n";
466 }
467 $str .= "</select>\n";
469 }else{
470 print_red(sprintf(_("Unsupported ppd type '%s' used for '%s' "),$type,$name));
471 }
472 $str .= "</td></tr>\n";
473 }
474 }
475 $str .= "</table></div>\n";
476 }
477 return($str);
478 }
480 function removeModifiedPPD()
481 {
482 $path = $this->pathToPPD.$this->pathToModified.$this->selectedPPD['link'];
484 if(file_exists($path)){
485 if(is_writeable($path)){
486 if(!@unlink($path)){
487 print_red(sprintf(_("Removing old ppd file '%s' failed."),$path));
488 }
489 }else{
490 print_red(sprintf(_("Removing old ppd file '%s' failed. File is not accessible."),$path));
491 }
492 }else{
493 print_red(sprintf(_("Removing old ppd file '%s' failed. File does not exists or is not accessible."),$path));
494 }
495 }
497 function check()
498 {
499 $message = plugin::check();
500 if(empty($this->selectedPPD['link'])){
501 $message[] = _("Please select a valid ppd file or use 'Cancel' to go back to printer configuration.");
502 }
503 return($message);
504 }
505 }
506 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
507 ?>