Code

bae18536a97e46a1db319b41b05eec50452d40c4
[gosa.git] / gosa-plugins / goto / admin / systems / ppd / class_ppdManager.inc
1 <?php
3 class ppdManager
4 {
5         var $path= "";
6         var $cachedList= array();
7         var $timestamps = array();
9   var $useGzip  = true;
11         function ppdManager($path)
12         {
13     global $config;
14     $value =$config->get_cfg_value("ppdGzip","true");
15     if(preg_match('/false/i',$value)){
16       $this->useGzip  = false;
17     }
18   
19                 if(is_dir($path)){
20                         $this->path= $path;
21                 }elseif(is_link($path) && (is_dir(readlink($path)))) {
22                     $this->path= $path;
23                 } else {
24                         msg_dialog::display(_("PPD manager error"), sprintf(_("The specified path '%s' does not exist."),$path), ERROR_DIALOG);
25                         return (false);
26                 }
29         }
32         function findPPD($path)
33         {
34                 $list= array();
35                 $currentDir= getcwd();
37                 $dh = opendir($path);
38                 while(false !== ($file = readdir($dh))){
40                         /* Skip well known files */
41                         if( $file == '.' || $file == '..'){
42                                 continue;
43                         }
45                         /* Recurse through all "common" directories */
46                         $check_path= $path.'/'.$file;
47                         if(is_dir($check_path) || (is_link($check_path) && (is_dir(readlink($check_path))))){
48                                 $list= array_merge($list, $this->findPPD($check_path));
49                                 continue;
50                         }
52                         /* Check for PPD extension */
53                         if (preg_match('/\.ppd(.gz)?$/i', $file)){
54                                 $list[]= $path.'/'.$file;
55                         }
56                 }
58                 closedir($dh);
59                 chdir ($currentDir);
60                 return ($list);
61         }
64         function updateAttribute($file, $section, $attribute, $value)
65         {
66                 $fsection= false;
67                 $fattribute= false;
68                 $section= preg_replace('/^\*/', '', $section);
69                 $attribute= preg_replace('/^\*/', '', $attribute);
71     if($this->useGzip){
72       $rp= @gzopen($file, "r");
73       $wp= @gzopen("$file.tmp", "w");
74     }else{
75       $rp= @gzopen($file, "r");
76       $wp= @fopen("$file.tmp", "w");
77     }
79           if($this->useGzip){   
80       while (!gzeof($rp)){
81         $lines[]= gzgets($rp, 1024);
82       }
83     }else{
84       while (!feof($rp)){
85         $lines[]= fgets($rp, 1024);
86       }
87     }
89                 $ret = "";
90                 $done =false;
91                 foreach($lines as $nr => $line){
92         
93                         if (preg_match("/\*OpenGroup:*\s+\**$section\/*/", $line)){
94                 $fsection= true;
95                                 $ret .=$line; 
96                 continue;
97             }
99                         /* Change model name .. */
100                         if ((preg_match("/^\*".$attribute.":*\s+/",$line)) && ($attribute == "ModelName")){
101                                 $line= "*$attribute: \"$value\"\n";
102                                 $done =true;
103                         }
105                         if (($fsection) && ($section != "NO_SECTION")){
106                                 if (preg_match("/^\*CloseGroup:*\s+\**$section\/*/", $line)){
107                                         $fsection= false;
108                                         $ret .=$line; 
109                                         continue;
110                                 }
113                                 if (preg_match("/^\*OpenUI:*\s+\**$attribute\/*/", $line)){
114                                         $fattribute= true;
115                                         $ret .= $line; 
116                                         continue;
117                                 }
119                                 if ($fattribute){
120                                         if (preg_match("/^\*CloseUI:*\s+\**$attribute\/*/", $line)){
121                                                 $fattribute= false;
122                                                 $ret .= $line; 
123                                                 continue;
124                                         }
126                                         if (preg_match("/^\*Default$attribute:*\s+/", $line)){
127                                                 $line= "*Default$attribute: $value\n";
128                                                 $done =true;
129                                         }
130                                 }
131                         }else{
132                                 if (preg_match("/^\*OpenUI:*\s+\**$attribute\/*/", $line)){
133                                         $fattribute= true;
134                                         $ret .= $line; 
135                                         continue;
136                                 }
138                                 if ($fattribute){
139                                         if (preg_match("/^\*CloseUI:*\s+\**$attribute\/*/", $line)){
140                                                 $fattribute= false;
141                                                 $ret .= $line; 
142                                                 continue;
143                                         }
145                                         if (preg_match("/^\*Default$attribute:*\s+/", $line)){
146                                                 $line= "*Default$attribute: $value\n";
147                                                 $done =true;
148                                         }
149                                 }
150                         }
151                         $ret .=$line; 
152                 }
154     if($this->useGzip){
155       gzwrite($wp,$ret);
156       gzclose($wp);
157       gzclose($rp);
158     }else{
159      fwrite($wp,$ret);
160      fclose($wp);
161      gzclose($rp);
162     }
164                 copy("$file.tmp", "$file");
165                 unlink("$file.tmp");
166         }
169         function saveProperties($ppdFile, $properties)
170         {
171                 if(!is_readable($ppdFile)){
172                         msg_dialog::display(_("PPD manager error"), sprintf(_("Specified PPD file '%s' cannot be opened for reading."),$ppdFile), ERROR_DIALOG);
173                 }elseif(!is_writeable(preg_replace("#(^.*/).*$#","\\1",$ppdFile.".tmp"))){
174                         msg_dialog::display(_("PPD manager error"), sprintf(_("The temporary file '%s' cannot be opened for writing."),$ppdFile.".tmp"), ERROR_DIALOG);
175                 }else{
176                         if(is_array($properties)){
177                                 foreach ($properties as $name => $section){
178                                         foreach ($section as $attribute => $value){
179                                                 if (is_array($value)){
180                                                         $this->updateAttribute($ppdFile, $name, $attribute, $value['_default']);
181                                                 }
182                                         }
183                                 }
184                         }
185                 }
186         }
188         function loadProperties($ppdFile)
189         {
190                 $group= "";
191                 $option= "";
192                 $properties= array();
194                 // Check for empty files
195                 if(!filesize($ppdFile)) {
196                         trigger_error(_('Parsing PPD file failed - file is empty!'));
197                         return;
198                 }
200                 $fh= gzopen ($ppdFile, 'r');
201                 while (!gzeof($fh) && $fh){
203                         /* Read line */
204                         $line= gzgets($fh, 256);
205                         if (strlen($line) >= 256){
206                                 trigger_error(_('Parsing PPD file %s failed - line too long. Trailing characters have been ignored!'), E_USER_WARNING);
207                         }
209                         /* Trigger for option groups */
210                         if (preg_match('/^\*OpenGroup:/i', $line)){
212                                 /* Sanity checks */
213                                 if ($group != ""){
214                                         trigger_error(_('Nested groups are not supported!'), E_USER_WARNING);
215                                         continue;
216                                 }
217                                 if (in_array($group, $properties)){
218                                         trigger_error(_('Group name not unique!'), E_USER_WARNING);
219                                         continue;
220                                 }
222                                 // TODO: Symbol values are not supported yet!
223                                 if (preg_match('/\^/', $line)){
224                                         trigger_error(_('Symbol values are not supported yet!'), E_USER_WARNING);
225                                 }
226                                 $complete= preg_replace('@^\*OpenGroup:\s+(.*)$@i', '\1', $line);
227                                 $complete= trim($complete, '"');
228                                 if (preg_match('@/@', $complete)){
229                                         $group= trim(preg_replace('@^\*OpenGroup:\s+"?([^/]+)/.*$@i', '\1', $line));
230                                         $name = preg_replace('@^\*OpenGroup:\s+"?[^/]+/([^/]+).*$@i', '\1', $line);
231                                 } else {
232                                         $group= $complete;
233                                         $name = $complete;
234                                 }
235                                 $properties[$group]= array('_name' => $name);
236                                 continue;
237                         }
238                         if (preg_match("/^\*CloseGroup:\s+\"?$group\"?/i", $line)){
239                                 $group= "";
240                                 continue;
241                         }
243                         /* Trigger for options */
244                         if (preg_match('/^\*OpenUI\s+/i', $line)){
246                                 /* Sanity check */
247                                 if ($option != ""){
248                                         trigger_error(_('Nested options are not supported!'), E_USER_WARNING);
249                                         continue;
250                                 }
252                                 // TODO: Symbol values are not supported yet!
253                                 if (preg_match('/\^/', $line)){
254                                         trigger_error(_('Symbol values are not supported yet!'), E_USER_WARNING);
255                                 }
256                                 $complete= preg_replace('@^\*OpenUI\s+(.*)$@i', '\1', $line);
257                                 $complete= trim($complete, '"');
258                                 if (preg_match('@/@', $complete)){
259                                         $option= trim(preg_replace('@^\*OpenUI\s+([^/]+)/.*$@i', '\1', $line));
260                                         $name = trim(preg_replace('@^\*OpenUI\s+[^/]+/([^/]+).*$@i', '\1', $line));
261                                 } else {
262                                         $option= trim($complete);
263                                         $name  = trim($complete);
264                                 }
266                                 /* Extract option type */
267                                 $type= trim(preg_replace('/^[^:]+:\s+/', '', $line));
268                                 $name= preg_replace('/:.*$/', '', $name);
269                                 $option= preg_replace('/:.*$/', '', $option);
271                                 // TODO: PickMany is not supported yet!
272                                 if (preg_match('/PickMany/i', $type)){
273                                         trigger_error(_('PickMany is not supported yet!'), E_USER_WARNING);
274                                 }
275                                 if(empty($group)){
276                                         $properties["NO_SECTION"][$option]= array('_name' => $name, '_type' => $type);
277                                 }else{
278                                         $properties[$group][$option]= array('_name' => $name, '_type' => $type);
279                                 }
280                                 continue;
281                         }
282                         /* Show interest for option parsing */
283                         if ($option != ""){
285                                 $eoption= preg_replace('@\*@', '', $option);
287                                 /* Close section? */
288                                 if (preg_match("@^\*CloseUI:\s+\*$eoption@i", $line)){
289                                         $option= "";
290                                         continue;
291                                 }
293                                 /* Default value? */
294                                 if (preg_match("@^\*Default$eoption:@", $line)){
295                                         $c= preg_replace("@^\*Default$eoption:\s+@", "", $line);
296                                         if(empty($group)){
297                                                 $properties["NO_SECTION"][$option]['_default']= trim(trim($c, '"'));
298                                         }else{
299                                                 $properties[$group][$option]['_default']= trim(trim($c, '"'));
300                                         }
301                                         continue;
302                                 }
304                                 /* Possible value? */
305                                 if (preg_match("@^\*$eoption\s+@", $line)){
307                     // Detect what comes first, the  '/' or the ':'. 
308                     // We may have entries like this: 
309                     //  *Resolution 300dpi: "<</HWResolution [300 300] >> setpagedevice"
310                     // and
311                     //  *Resolution 300dpi/300: "<</HWResolution [300 300] >> setpagedevice"
312                     $name = $value = preg_replace("@^\*$eoption\s+([^:]+).*$@", "$1", $line);
313                     if(preg_match("/\//", $name)){
314                         list($name, $value) = preg_split("/\//", $name);
315                     }
316                                         if(empty($group)){
317                                                 $properties["NO_SECTION"][$option][$name]= $value;
318                                         }else{
319                                                 $properties[$group][$option][$name]= $value;
320                                         }
321                                         continue;
322                                 }
323                         }
324                 }
326         gzclose ($fh);
327                 return ($properties);
328         }
330         function loadDescription($ppdFile)
331         {
332                 // Check for empty files
333                 if(!filesize($ppdFile)) {
334                         trigger_error(_('Parsing PPD file failed - file is empty!'));
335                         return;
336                 }
338                 $ppdDesc = array();
339         
340                 /* Only parse complete PPD file again, if it was changed */
341                 $modified = filemtime($ppdFile);
342                 if(isset($this->cachedList[$ppdFile]) && isset($this->timestamps[$ppdFile]) && $modified == $this->timestamps[$ppdFile]){
343                         return($this->cachedList[$ppdFile]);
344                 }
346                 /* Remember modified timestamp, to speed up next request */
347                 $this->timestamps[$ppdFile] = filemtime($ppdFile);
348                 $fh= gzopen ($ppdFile, 'r');
350                 while (!gzeof($fh) && $fh){
352                         $line= gzgets($fh, 256);
353                         if (strlen($line) >= 256){
354                                 trigger_error(_('Parsing PPD file %s failed - line too long. Trailing characters have been ignored'), E_USER_WARNING);
355                         }
357                         /* Extract interesting informations */
358                         if (preg_match('/^\*Manufacturer:/i', $line)){
359         $ppdDesc['manufacturer'] = trim(preg_replace('/^\*Manufacturer:\s+"?([^"]+)"?.*$/i', '\1',    $line));
360                         }
361                         if (preg_match('/^\*ModelName:/i', $line)){
362         $ppdDesc['model'] = trim(preg_replace('/^\*ModelName:\s+"?([^"]+)"?.*$/i', '\1', $line));
363                         }
365                         /* Got everything we need? Skip rest for speed reasons... */
366       if (isset($ppdDesc['manufacturer'])  && isset($ppdDesc['model'])){
367                                 break;
368                         }
369                 }
371                 gzclose ($fh);
373     /* If model contains manufacturer strip it */
374     $ppdDesc['model'] = str_replace($ppdDesc['manufacturer']." ", '', $ppdDesc['model']);
376                 /* Write out a notice that the PPD file seems to be broken if we can't
377                    extract any usefull informations */
378     if ($ppdDesc['manufacturer'] == '' || $ppdDesc['model'] == ''){
379                         trigger_error(sprintf(_('Parsing PPD file %s failed - no information found.'), $ppdFile), E_USER_WARNING);
380                 }
382     $ppdDesc['name'] = $ppdDesc['manufacturer'] . " - " . $ppdDesc['model'];
383     return $ppdDesc;
384         }
387         function getPrinterList($reload= false)
388         {
389                 /* Load list of PPD files */
390                 if (count($this->cachedList) == 0 || $reload){
391                         $list= $this->findPPD($this->path);
393                         /* Load descriptive informations to build final printer list */
394                         $new = array();
395                         foreach ($list as $ppdFile){
396                                 $new[$ppdFile] = $this->loadDescription($ppdFile); 
397                         }
398                         $this->cachedList= $new ;
400                 }
402                 return ($this->cachedList);
403         }
406 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
407 ?>