1 <?php
3 class ppdManager
4 {
5 var $path= "";
6 var $cachedList= array();
8 function ppdManager($path)
9 {
10 if(is_dir($path)){
11 $this->path= $path;
12 }else{
13 print_red(sprintf(_("PPD manager : The specified path '%s' doesn't exists."),$path));
14 return (false);
15 }
16 }
19 function findPPD($path)
20 {
21 $list= array();
22 $currentDir= getcwd();
24 $dh = opendir($path);
25 while(false !== ($file = readdir($dh))){
27 /* Skip well known files */
28 if( $file == '.' || $file == '..'){
29 continue;
30 }
32 /* Recurse through all "common" directories */
33 if(is_dir($path.'/'.$file)){
34 $list= array_merge($list, $this->findPPD($path.'/'.$file));
35 continue;
36 }
38 /* Check for PPD extension */
39 if (preg_match('/\.ppd$/i', $file)){
40 $list[]= $path.'/'.$file;
41 }
42 }
44 closedir($dh);
45 chdir ($currentDir);
46 return ($list);
47 }
50 function updateAttribute($file, $section, $attribute, $value)
51 {
52 $fsection= false;
53 $fattribute= false;
54 $section= preg_replace('/^\*/', '', $section);
55 $attribute= preg_replace('/^\*/', '', $attribute);
57 $rp= fopen($file, "r");
58 $wp= fopen("$file.tmp", "w");
60 while (!feof($rp)){
61 $line= fgets($rp, 1024);
63 if (preg_match("/\*OpenGroup:*\s+\**$section\/*/", $line)){
64 $fsection= true;
65 fwrite ($wp, $line);
66 continue;
67 }
69 if ($fsection){
70 if (preg_match("/^\*CloseGroup:*\s+\**$section\/*/", $line)){
71 $fsection= false;
72 fwrite ($wp, $line);
73 continue;
74 }
76 if (preg_match("/^\*OpenUI:*\s+\**$attribute\/*/", $line)){
77 $fattribute= true;
78 fwrite ($wp, $line);
79 continue;
80 }
82 if ($fattribute){
83 if (preg_match("/^\*CloseUI:*\s+\**$attribute\/*/", $line)){
84 $fattribute= false;
85 fwrite ($wp, $line);
86 continue;
87 }
89 if (preg_match("/^\*Default$attribute:*\s+/", $line)){
90 $line= "*Default$attribute: $value\n";
91 }
92 }
93 }
94 fwrite ($wp, $line);
95 }
97 fclose($wp);
98 fclose($rp);
100 copy("$file.tmp", "$file");
101 unlink("$file.tmp");
102 }
105 function saveProperties($ppdFile, $properties)
106 {
107 foreach ($properties as $name => $section){
108 foreach ($section as $attribute => $value){
109 if (is_array($value)){
110 $this->updateAttribute($ppdFile, $name, $attribute, $value['_default']);
111 }
112 }
113 }
114 }
117 function loadProperties($ppdFile)
118 {
119 $group= "";
120 $option= "";
121 $properties= array();
123 $fh= fopen ($ppdFile, 'r');
124 while (!feof($fh)) {
126 /* Read line */
127 $line= fgets($fh, 256);
128 if (strlen($line) >= 256){
129 trigger_error(_('Parsing PPD file %s failed - line too long. Trailing characters have been ignored'), E_USER_WARNING);
130 }
132 /* Trigger for option groups */
133 if (preg_match('/^\*OpenGroup:/i', $line)){
135 /* Sanity checks */
136 if ($group != ""){
137 trigger_error(_('Nested groups are not supported!'), E_USER_WARNING);
138 continue;
139 }
140 if (in_array($group, $properties)){
141 trigger_error(_('Group name not unique!'), E_USER_WARNING);
142 continue;
143 }
145 // TODO: Symbol values are not supported yet!
146 if (preg_match('/\^/', $line)){
147 trigger_error(_('Symbol values are not supported yet!'), E_USER_WARNING);
148 }
149 $complete= preg_replace('@^\*OpenGroup:\s+(.*)$@i', '\1', $line);
150 $complete= trim($complete, '"');
151 if (preg_match('@/@', $complete)){
152 $group= trim(preg_replace('@^\*OpenGroup:\s+"?([^/]+)/.*$@i', '\1', $line));
153 $name = preg_replace('@^\*OpenGroup:\s+"?[^/]+/([^/]+).*$@i', '\1', $line);
154 } else {
155 $group= $complete;
156 $name = $complete;
157 }
158 $properties[$group]= array('_name' => $name);
159 continue;
160 }
161 if (preg_match("/^\*CloseGroup:\s+\"?$group\"?/i", $line)){
162 $group= "";
163 continue;
164 }
166 /* Trigger for options */
167 if (preg_match('/^\*OpenUI\s+/i', $line)){
169 /* Sanity check */
170 if ($option != ""){
171 trigger_error(_('Nested options are not supported!'), E_USER_WARNING);
172 continue;
173 }
175 // TODO: Symbol values are not supported yet!
176 if (preg_match('/\^/', $line)){
177 trigger_error(_('Symbol values are not supported yet!'), E_USER_WARNING);
178 }
179 $complete= preg_replace('@^\*OpenUI\s+(.*)$@i', '\1', $line);
180 $complete= trim($complete, '"');
181 if (preg_match('@/@', $complete)){
182 $option= trim(preg_replace('@^\*OpenUI\s+([^/]+)/.*$@i', '\1', $line));
183 $name = trim(preg_replace('@^\*OpenUI\s+[^/]+/([^/]+).*$@i', '\1', $line));
184 } else {
185 $option= trim($complete);
186 $name = trim($complete);
187 }
189 /* Extract option type */
190 $type= trim(preg_replace('/^[^:]+:\s+/', '', $line));
191 $name= preg_replace('/:.*$/', '', $name);
192 $option= preg_replace('/:.*$/', '', $option);
194 // TODO: PickMany is not supported yet!
195 if (preg_match('/PickMany/i', $type)){
196 trigger_error(_('PickMany is not supported yet!'), E_USER_WARNING);
197 }
199 $properties[$group][$option]= array('_name' => $name, '_type' => $type);
200 continue;
201 }
202 /* Show interest for option parsing */
203 if ($option != ""){
205 $eoption= preg_replace('@\*@', '', $option);
207 /* Close section? */
208 if (preg_match("@^\*CloseUI:\s+\*$eoption@i", $line)){
209 $option= "";
210 continue;
211 }
213 /* Default value? */
214 if (preg_match("@^\*Default$eoption:@", $line)){
215 $c= preg_replace("@^\*Default$eoption:\s+@", "", $line);
216 $properties[$group][$option]['_default']= trim(trim($c, '"'));
217 continue;
218 }
220 /* Possible value? */
221 if (preg_match("@^\*$eoption\s+@", $line)){
222 #*PageSize Letter/US Letter: "<>setpagedevice"
223 $c= preg_replace("@^\*$eoption\s+([^/]+).*$@", "$1", $line);
224 $d= preg_replace("@^\*$eoption\s+[^/]+/([^:]+).*$@", "$1", $line);
225 $properties[$group][$option][trim($c)]= trim($d);
226 continue;
227 }
228 }
230 }
231 fclose ($fh);
233 return ($properties);
234 }
236 function loadDescription($ppdFile)
237 {
238 $model= "";
239 $manufacturer= "";
241 $fh= fopen ($ppdFile, 'r');
242 while ((!feof($fh))&&($fh)) {
244 /* Read line */
245 $line= fgets($fh, 256);
246 if (strlen($line) >= 256){
247 trigger_error(_('Parsing PPD file %s failed - line too long. Trailing characters have been ignored'), E_USER_WARNING);
248 }
250 /* Extract interesting informations */
251 if (preg_match('/^\*Manufacturer:/i', $line)){
252 $manufacturer= preg_replace('/^\*Manufacturer:\s+"?([^"]+)"?.*$/i', '\1', $line);
253 }
254 if (preg_match('/^\*ModelName:/i', $line)){
255 $model= preg_replace('/^\*ModelName:\s+"?([^"]+)"?.*$/i', '\1', $line);
256 }
258 /* Got everything we need? Skip rest for speed reasons... */
259 if ($model != '' && $manufacturer != ''){
260 break;
261 }
262 }
263 fclose ($fh);
265 /* Write out a notice that the PPD file seems to be broken if we can't
266 extract any usefull informations */
267 if ($model == '' || $manufacturer == ''){
268 trigger_error(sprintf(_('Parsing PPD file %s failed - no information found.'), $ppdFile), E_USER_WARNING);
269 }
271 return ($manufacturer.' - '.$model);
272 }
275 function getPrinterList($reload= false)
276 {
277 /* Load list of PPD files */
278 if (count($this->cachedList) == 0 || $reload){
279 $list= $this->findPPD($this->path);
281 /* Load descriptive informations to build final printer list */
282 $this->cachedList= array();
283 foreach ($list as $ppdFile){
284 $this->cachedList[$ppdFile]= $this->loadDescription($ppdFile);
285 }
287 }
289 return ($this->cachedList);
290 }
292 }
294 ?>