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