source: trunk/gui/shared/PrManUtl.VRS@ 50

Last change on this file since 50 was 49, checked in by Alex Taylor, 11 years ago

Updates for v0.50:
Moved much of the PPD-import logic into a shared function.
Automatically reimport previously-imported PPDs when updating to a new version of a known PostScript driver.
Ask if the user wants to update the active copy of a driver when the repository version is updated.
Fixed error in locating cupswiz.exe when the desktop object doesn't exist.
Fixed broken update of PRDESC.LST when upgrading to a new version of a known PostScript driver.

File size: 38.9 KB
Line 
1/*:VRX DriverIsInstalled
2*/
3/* Checks if a given print driver (without extension) is installed, and if so
4 * returns the path to the active files. Returns '' if the driver is not
5 * installed.
6 */
7DriverIsInstalled: PROCEDURE
8 ARG driver
9 PARSE VALUE VRGetIni('PM_DEVICE_DRIVERS', driver, 'USER') WITH drv_path '00'x .
10 IF ( drv_path <> '') THEN
11 drv_path = STREAM( drv_path, 'C', 'QUERY EXISTS')
12RETURN drv_path
13
14
15/*:VRX GetDriverSource
16*/
17/* Figure out where to look for the PrinterPak driver files used as the install
18 * source. Preference is given to the local repository (PDR_DIR); if it's not
19 * there, we look in a couple of other places where it might have ended up.
20 * Note that we don't look for the actual installed driver files under \OS2\DLL;
21 * that logic is handled in LocateDriverFiles(), which calls this routine.
22 *
23 * Various global values are assumed to be set already:
24 * - globals.!prdrv: filespec of \OS2\INSTALL\PRDRV.LST
25 * - globals.!repository: value indicated by PM_INSTALL->PDR_DIR in OS2.INI
26 *
27 * Arguments: The print driver name without path or extension
28 *
29 * Returns the path, or '' if not found. Also, 'pmdx' will be 0-9 if the
30 * driver is in the repository (indicating the repository subdirectory), or
31 * '' if the driver is not in the repository.
32 */
33GetDriverSource: PROCEDURE EXPOSE globals. pmdx
34 ARG driver
35 IF driver == '' THEN RETURN ''
36
37 drv_file = ''
38 IF globals.!repository <> '' THEN DO
39
40 /* See if the driver is defined in the local repository. (This is the
41 * directory where installable printer drivers are kept. OS/2 gets them
42 * from here when you select 'Printer driver included with OS/2'.)
43 */
44 pmdx = GetDriverPMDD( driver, globals.!prdrv )
45 IF pmdx == '' THEN DO
46 /* Hmm, the driver isn't listed in PRDRV.LST. Let's check to see if
47 * it's in the default repository location anyway.
48 */
49 IF WORDPOS( driver, 'ECUPS ECUPS-HP PSPRINT PSPRINT2') > 0 THEN
50 pmdx = '9'
51 ELSE
52 pmdx = '0'
53 drv_file = STREAM( globals.!repository'\PMDD_'pmdx'\'driver'.DRV', 'C', 'QUERY EXISTS')
54 IF drv_file <> '' THEN DO
55 /* We found the driver in the repository, even though it isn't
56 * defined as such. So let's add the proper definition to
57 * PRDRV.LST now.
58 */
59 CALL LINEOUT globals.!prdrv, LEFT( driver'.DRV', 14 ) pmdx ||,
60 ' (added automatically)'
61 CALL LINEOUT globals.!prdrv
62 END
63 ELSE
64 pmdx = ''
65 END
66 ELSE DO
67 /* The driver is listed; now make sure it's actually there.
68 */
69 drv_file = STREAM( globals.!repository'\PMDD_'pmdx'\'driver'.DRV', 'C', 'QUERY EXISTS')
70 END
71 END
72
73 IF drv_file == '' THEN DO
74 CALL LINEOUT globals.!log1, 'Driver' driver 'is not in the local repository.'
75 /* If the driver really isn't in the repository, there are a couple of
76 * other places that various install utilities might have put it...
77 */
78 PARSE VALUE VRGetIni('PM_INSTALL', driver'_DIR', 'USER') WITH drvr_dir '00'x .
79 IF drvr_dir == '' THEN
80 PARSE VALUE VRGetIni('InstPDR', 'PATH_TO_'driver, 'USER') WITH drvr_dir '00'x .
81 IF drvr_dir <> '' THEN DO
82 drv_file = drvr_dir'\'driver'.DRV'
83 CALL LINEOUT globals.!log1, 'Found driver in' drvr_dir'.'
84 END
85 END
86
87RETURN drv_file
88
89
90/*:VRX GetDriverPMDD
91*/
92/* Check to see which repository directory the specified driver resides in.
93 * Returns the number suffix of the PMDD_* subdirectory name, or '' if either
94 * the driver or the index file could not be located.
95 *
96 * Arguments: The print driver name without path or extension
97 */
98GetDriverPMDD: PROCEDURE
99 PARSE ARG driver, prdrv_lst
100
101 IF prdrv_lst <> '' THEN DO
102 CALL LINEIN prdrv_lst, 1, 0
103 DO WHILE LINES( prdrv_lst ) > 0
104 PARSE VALUE LINEIN( prdrv_lst ) WITH (driver)'.DRV' pmdx .
105 IF pmdx <> '' THEN LEAVE
106 END
107 CALL STREAM prdrv_lst, 'C', 'CLOSE'
108 END
109 ELSE pmdx = ''
110
111RETURN pmdx
112
113
114/*:VRX LocateDriverFiles
115*/
116/* Locates the source files for a PostScript-based driver that will be required in
117 * order to import a PPD using PIN. Not to be used with non-PostScript drivers,
118 * since it will fail if PIN or PPDENC are not found.
119 *
120 * Arguments: The print driver name without path or extension
121 *
122 * Returns:
123 * 0 - Driver files not found.
124 * 1 - Driver files found, path saved in 'driver_path'; 'driver_repo' will be 1
125 * if the driver is 'shipped' (i.e. defined in PRDRV.LST) or 0 otherwise.
126 * 2 - Only found installed driver files in (\OS2\DLL\xxx, saved in 'driver_path');
127 * will need to copy them somewhere for future installs.
128 */
129LocateDriverFiles: PROCEDURE EXPOSE globals. driver_path driver_repo
130 ARG driver
131 IF driver == '' THEN driver = 'PSCRIPT'
132
133 CALL LINEOUT globals.!log1, 'Looking for' driver 'files'
134
135 mustcopy = 0
136 driver_path = GetDriverSource( driver )
137
138 IF driver_path == '' THEN DO
139 /* No source found. We'll have to try copying the actual installed
140 * driver files from under \OS2\DLL.
141 */
142 CALL LINEOUT globals.!log1, 'Driver source not found. Trying installed driver.'
143 PARSE VALUE VRGetIni('PM_DEVICE_DRIVERS', driver, 'USER') WITH drv_used '00'x .
144 IF ( drv_used <> '') & VRFileExists( drv_used ) THEN
145 driver_path = drv_used
146 END
147 IF driver_path <> '' THEN DO
148 srcdir = VRParseFilePath( driver_path, 'DP')
149 pin = STREAM( srcdir'\PIN.EXE', 'C', 'QUERY EXISTS')
150 ppdenc = STREAM( srcdir'\PPDENC.EXE', 'C', 'QUERY EXISTS')
151 /* TODO should we check for all the REQUIREDDRIVER FILES as well? */
152 END
153
154 IF pmdx == '' THEN
155 driver_repo = 0
156 ELSE
157 driver_repo = 1
158
159 /* Driver (or one of its required files) was not found.
160 */
161 IF ( driver_path == '') | ( pin == '') | ( ppdenc == '') | ,
162 ( VerifyDriverEAs( driver_path ) == 0 ) THEN
163 DO
164 CALL LINEOUT globals.!log1, ' - Missing required driver files.'
165 RETURN 0
166 END
167
168 IF mustcopy THEN RETURN 2
169RETURN 1
170
171
172/*:VRX VerifyDriverEAs
173*/
174/* Make sure the driver has its extended attributes. If not, look for an
175 * accompanying .EA or .EA_ file, and join it to the driver.
176 */
177VerifyDriverEAs: PROCEDURE EXPOSE globals.
178 PARSE ARG driver
179 eas.0 = 0
180 CALL SysQueryEAList driver, 'eas.'
181 IF eas.0 == 0 THEN DO
182 ea_file = SUBSTR( driver, 1, LASTPOS('.', driver )) || 'EA'
183 IF STREAM( ea_file, 'C', 'QUERY EXISTS') == '' THEN
184 ea_file = ea_file || '_'
185 IF STREAM( ea_file, 'C', 'QUERY EXISTS') == '' THEN
186 RETURN 0
187
188 ADDRESS CMD '@UNLOCK' driver '2>NUL 1>NUL'
189 ADDRESS CMD '@EAUTIL' driver ea_file '/j /p 2>NUL 1>NUL'
190 END
191RETURN 1
192
193
194/*:VRX BldLevelVersion
195*/
196/* Parse the revision (version) number from a BLDLEVEL string
197 */
198BldLevelVersion: PROCEDURE EXPOSE globals.
199 ARG module
200 revision = ''
201
202 _nq = RXQUEUE('CREATE')
203 _oq = RXQUEUE('SET', _nq )
204
205 ADDRESS CMD '@bldlevel' module '2>&1 | RXQUEUE' _nq
206 DO QUEUED()
207 PARSE PULL _blline
208 IF LEFT( _blline, 9 ) == 'Revision:' THEN DO
209 PARSE VAR _blline 'Revision:' revision .
210 LEAVE
211 END
212 END
213
214 CALL RXQUEUE 'SET', _oq
215 CALL RXQUEUE 'DELETE', _nq
216
217 IF revision == '' THEN revision = '-'
218
219RETURN revision
220
221
222/*:VRX CopyPrinterPak
223*/
224/* Copies a printerpak driver and all its dependent files from one directory
225 * to another.
226 *
227 * driver - The fully-qualified filename of the printerpak .DRV
228 * newdrvdir - The directory where the files will be copied; must exist
229 *
230 * Returns: 1 on success, 0 on failure
231 */
232CopyPrinterPak: PROCEDURE EXPOSE globals.
233 PARSE ARG driver, newdrvdir
234
235 drv_dir = VRParseFilePath( driver, 'DP')
236 drv_name = VRParseFilePath( driver, 'NE')
237 IF drv_dir == '' THEN RETURN 0
238
239 IF VerifyDriverEAs( driver ) == 0 THEN RETURN 0
240
241 CALL LINEOUT globals.!log1, 'Copying driver files from' drv_dir 'to' newdrvdir'...'
242
243 /* Read the list of required driver files from the EAs, and copy them
244 * all to the target directory.
245 */
246 IF SysGetEA( driver, 'REQUIREDDRIVERFILES', 'reqfiles') == 0 THEN DO
247 PARSE VAR reqfiles 5 filelist
248 filelist = TRANSLATE( filelist, ' ', ',')
249 DO i = 1 TO WORDS( filelist )
250 copyfile = drv_dir'\' || WORD( filelist, i )
251 ok = VRCopyFile( copyfile, newdrvdir'\' || WORD( filelist, i ))
252 CALL LINEOUT globals.!log1, ' -' copyfile '(REQUIRED):' ok
253 END
254 DROP copyfile
255 DROP filelist
256 END
257 ELSE RETURN 0
258
259 /* If there are optional files defined as well, try to copy those also.
260 */
261 IF SysGetEA( driver, 'OPTIONALDRIVERFILES', 'reqfiles') == 0 THEN DO
262 PARSE VAR reqfiles 5 filelist
263 filelist = TRANSLATE( filelist, ' ', ',')
264 DO i = 1 TO WORDS( filelist )
265 copyfile = drv_dir'\' || WORD( filelist, i )
266 IF STREAM( copyfile, 'C', 'QUERY EXISTS') == '' THEN ITERATE
267 ok = VRCopyFile( copyfile, newdrvdir'\' || WORD( filelist, i ))
268 CALL LINEOUT globals.!log1, ' -' copyfile '(OPTIONAL):' ok
269 END
270 DROP copyfile
271 DROP filelist
272 END
273
274 /* If AUXPRINT.PAK exists, copy it as well */
275 copyfile = drv_dir'\AUXPRINT.PAK'
276 IF STREAM( copyfile, 'C', 'QUERY EXISTS') <> '' THEN DO
277 ok = VRCopyFile( copyfile, newdrvdir'\AUXPRINT.PAK')
278 CALL LINEOUT globals.!log1, ' -' copyfile ':' ok
279 END
280
281 /* Create an EA file if necessary */
282 eafile = VRParseFilePath( driver, 'N') || '.EA'
283 IF VRFileExists( newdrvdir'\'eafile ) THEN
284 CALL VRDeleteFile newdrvdir'\'eafile
285 ADDRESS CMD '@EAUTIL' newdrvdir'\'drv_name newdrvdir'\'eafile '/s /p 2>NUL 1>NUL'
286
287RETURN 1
288
289
290/*:VRX PrinterExistsInDRV
291*/
292/* Determine if the specified PrinterPak driver already contains support
293 * for the specified printer model.
294 *
295 * If so, return the name of the model as found in the driver (necessary in
296 * order to make sure the correct case is retained, which may be different
297 * from what was requested). Otherwise return ''.
298 */
299PrinterExistsInDRV: PROCEDURE EXPOSE globals.
300 PARSE UPPER ARG driver_name, printer_name
301 printer_name = TRANSLATE( printer_name, '_', '.')
302
303 printer_drv = globals.!os2dir'\DLL\'driver_name'\'driver_name'.DRV'
304 /* ?? TODO: install driver_name if not found (prompt first) ?? */
305
306 IF SysGetEA( printer_drv, '.EXPAND', 'exist_ea') <> 0 THEN RETURN 0
307 PARSE VAR exist_ea 1 _eatype 3 .
308 IF C2X( _eatype ) <> 'FDFF' THEN RETURN 0
309
310 PARSE VAR exist_ea 3 _ealen 5 exist_models
311 total_len = C2D( REVERSE( _ealen ))
312
313 /* The variable exist_models now contains a null-separated list of printer
314 * models supported by the driver (including those from previously-imported
315 * PPD files). Next we check each one against our requested printer name.
316 */
317 start = 1
318 found = ''
319 DO WHILE ( found == 0 ) & ( start < total_len )
320 _strend = POS('0'x, exist_models, start )
321 IF _strend == 0 THEN LEAVE
322 _model = SUBSTR( exist_models, start, _strend - start )
323 IF TRANSLATE( _model ) == printer_name THEN
324 found = _model
325 ELSE
326 start = _strend + 1
327 END
328
329RETURN found
330
331
332/*:VRX CreateDriverList
333*/
334/* Generate a driver listfile from the .EXPAND EA
335 */
336CreateDriverList: PROCEDURE EXPOSE globals.
337 ARG driver, listfile
338
339 IF STREAM( listfile, 'C', 'QUERY EXISTS') <> '' THEN
340 CALL SysFileDelete listfile
341
342 drv_name = FILESPEC('NAME', driver )
343 IF SysGetEA( driver, '.EXPAND', 'eaval') == 0 THEN DO
344 PARSE VAR eaval 3 ealen 5 models
345 offs = 1
346 datalen = C2D( REVERSE( ealen ))
347 DO WHILE offs <= datalen
348 start = SUBSTR( models, offs )
349 inc = POS('00'x, start )
350 IF inc > 1 THEN DO
351 current_name = STRIP( SUBSTR( start, 1, inc-1 ))
352 CALL LINEOUT listfile, current_name':' current_name '('drv_name')'
353 END
354 offs = offs + inc
355 END
356 CALL LINEOUT listfile
357 CALL LINEOUT globals.!log1, 'Created driver list' listfile 'for' driver'.'
358 END
359 ELSE
360 CALL LINEOUT globals.!log1, 'No drivers found in' driver '(missing .EXPAND extended attribute?)'
361
362RETURN 1
363
364
365/*:VRX AddPort_CUPS
366*/
367/* Adds a new CUPS port. Returns 0 on full success, 1 if the port was created
368 * but could not be configured, and an OS/2 or PM error code otherwise.
369 */
370AddPort_CUPS: PROCEDURE EXPOSE globals.
371 PARSE ARG portname, hostname, queuename
372 CALL LINEOUT globals.!log1, 'Creating new port' portname
373 ADDRESS CMD '@cupsport' portname hostname queuename '>>' globals.!log2
374 IF rc == 1 THEN DO
375 CALL VRSetIni 'PM_'portname, 'INITIALIZATION', hostname'#'queuename||'00'x, 'SYSTEM', 'NoClose'
376 CALL VRSetIni 'PM_'portname, 'DESCRIPTION', hostname':'queuename||'00'x, 'SYSTEM'
377 END
378RETURN rc
379
380
381/*:VRX DeletePort
382*/
383/* Deletes a printer port (any type).
384 */
385DeletePort: PROCEDURE EXPOSE globals.
386 PARSE ARG portname
387 CALL SysIni 'SYSTEM', 'PM_'portname, 'DELETE:'
388 CALL SysIni 'SYSTEM', 'PM_SPOOLER_PORT', portname, 'DELETE:'
389RETURN 1
390
391
392/*:VRX GetNextPortName
393*/
394/* Get the next unique (non-existing) port name for the specified port driver.
395 */
396GetNextPortName: PROCEDURE
397 ARG portdrv
398
399 maxports = 64 /* should be smarter about this if possible */
400 exists = 1
401 x = 0
402 DO WHILE ( x < maxports ) & ( exists == 1 )
403 x = x + 1
404 portname = portdrv || x
405 nextport = SysIni('SYSTEM', 'PM_SPOOLER_PORT', portname )
406 IF LEFT( nextport, 6 ) == 'ERROR:' THEN exists = 0
407 END
408 IF exists == 1 THEN
409 portname = ''
410
411RETURN portname
412
413
414/*:VRX GetPortDrivers
415*/
416/* Get the list of currently-installed port drivers. NOTE: we exclude LPRPDRVR
417 * from this list, because it has to be managed via the TCP/IP configuration
418 * program.
419 */
420GetPortDrivers: PROCEDURE EXPOSE portdrivers.
421 ok = SysIni('SYSTEM', 'PM_PORT_DRIVER', 'ALL:', 'installed.')
422 IF LEFT( ok, 6 ) == 'ERROR:' THEN RETURN 0
423 count = 0
424 DO i = 1 TO installed.0
425 IF installed.i = 'LPRPDRVR' THEN ITERATE
426 fullpath = STRIP( SysIni('SYSTEM', 'PM_PORT_DRIVER', installed.i ), 'T', '00'x )
427 IF LEFT( fullpath, 6 ) == 'ERROR:' THEN fullpath = ''
428 fullpath = STREAM( fullpath , 'C', 'QUERY EXISTS')
429 count = count + 1
430 portdrivers.count = installed.i || ' ' || fullpath
431 END
432 portdrivers.0 = count
433RETURN portdrivers.0
434
435
436/*:VRX GetQueueName
437*/
438/* Generate a unique queue name from the specified printer name.
439 */
440GetQueueName: PROCEDURE
441 ARG queuename
442
443 DO UNTIL badchar = 0
444 badchar = VERIFY( queuename, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789 ')
445 IF badchar > 0 THEN
446 queuename = OVERLAY(' ', queuename, badchar, 1 )
447 END
448 queuename = LEFT( SPACE( queuename, 0 ), 8 )
449
450 tail = 0
451 PARSE VALUE VRGetIni('PM_SPOOLER', 'DIR', 'SYSTEM') WITH spldir ';' .
452 DO WHILE VRFileExists( spldir'\'queuename ) == 1
453 tail = tail + 1
454 queuename = STRIP( LEFT( queuename, 8 - LENGTH( tail ))) || tail
455 END
456
457RETURN queuename
458
459
460/*:VRX InstallPortDriver
461*/
462/* Installs a new port driver.
463 *
464 * Returns: 0 on success, 1 on error
465 */
466InstallPortDriver: PROCEDURE EXPOSE globals.
467 ARG new_pdr
468 filename = VRParseFileName( new_pdr, 'NE')
469 IF filename == '' THEN RETURN
470 installed_pdr = TRANSLATE( globals.!os2dir'\DLL\'filename )
471 IF installed_pdr <> new_pdr THEN DO
472 ok = VRCopyFile( new_pdr, installed_pdr )
473 IF ok == 0 THEN RETURN 1
474 /* Try to copy any optional files as well */
475 IF SysGetEA( new_pdr, 'OPTIONALDRIVERFILES', 'reqfiles') == 0 THEN DO
476 drv_dir = VRParseFilePath( new_pdr, 'DP')
477 PARSE VAR reqfiles 5 filelist
478 filelist = TRANSLATE( filelist, ' ', ',')
479 DO i = 1 TO WORDS( filelist )
480 copyfile = drv_dir'\' || WORD( filelist, i )
481 IF STREAM( copyfile, 'C', 'QUERY EXISTS') == '' THEN ITERATE
482 ok = VRCopyFile( copyfile, newdrvdir'\' || WORD( filelist, i ))
483 /*CALL LINEOUT globals.!log1, ' -' copyfile '(OPTIONAL):' ok*/
484 END
485 END
486 END
487
488 key = VRParseFileName( installed_pdr, 'N')
489 CALL VRSetIni 'PM_PORT_DRIVER', key, installed_pdr||'00'x, 'SYSTEM'
490RETURN 0
491
492
493/*:VRX InstallPrintDriver
494*/
495/* 'Installs' (that is to say, registers with the spooler) an OS printer
496 * device driver/model. Installs the corresponding printerpak driver if
497 * necessary.
498 *
499 * driver - The name of the printerpak driver (without path or extension)
500 * driverfull - The fully-qualified filename of the printerpak driver
501 * model - The printer make/model name used by the driver
502 *
503 * Returns: 0 on success, 1 on error
504 */
505InstallPrintDriver: PROCEDURE EXPOSE globals.
506 PARSE ARG driver, driverfull, model
507
508 ok = 0
509 targetdir = globals.!os2dir'\DLL\'driver
510 targetdrv = targetdir'\'driver'.DRV'
511 CALL LINEOUT globals.!log1, 'Installing' driver'.'model 'from' driverfull '(target' targetdrv')'
512
513 IF ( VRFileExists( targetdrv ) == 0 ) THEN DO
514 CALL VRMkDir targetdir
515 r = CopyPrinterPak( driverfull, targetdir )
516 IF r <> 1 THEN ok = 1
517 END
518 IF ok == 0 THEN DO
519 IF VRGetIni('PM_DEVICE_DRIVERS', driver, 'USER') <> targetdrv THEN
520 CALL VRSetIni 'PM_DEVICE_DRIVERS', driver, targetdrv||'00'x, 'USER'
521 CALL VRSetIni 'PM_SPOOLER_DD', driver'.'model, driver'.DRV;;;'||'00'x, 'SYSTEM'
522 END
523RETURN ok
524
525/*:VRX DeletePrintDriver
526*/
527/* Removes (that is to say, de-registers with the spooler) a PM printer
528 * device driver/model.
529 *
530 * driver - The name of the printerpak driver (without path or extension)
531 * model - The printer make/model name used by the driver
532 *
533 * Returns: 0 on success, 1 on error
534 */
535DeletePrintDriver: PROCEDURE EXPOSE globals.
536 PARSE ARG driver, model
537
538 ok = VRDelIni('PM_SPOOLER_DD', driver'.'model, 'SYSTEM')
539RETURN ok
540
541/*:VRX CreatePrinterObject
542*/
543/* Create the specified printer using SysCreateObject (this should create the
544 * queue automatically).
545 *
546 * Returns: 0 on success or non-zero return code on error.
547 */
548CreatePrinterObject: PROCEDURE EXPOSE globals.
549 PARSE ARG driver, model, portname, queuename, printername
550
551 CALL LINEOUT globals.!log1, 'Creating new printer:' printername '('queuename')'
552 ok = RPUPrinterCreate( printername, queuename, portname, driver'.'model )
553RETURN ok
554
555/*:VRX GetNameFromPPD
556*/
557GetNameFromPPD: PROCEDURE
558 ARG ppd_file
559
560 IF STREAM( ppd_file, 'C', 'QUERY EXISTS') == '' THEN RETURN ''
561 nickname = ''
562 IF VRParseFilePath( ppd_file, 'E') == 'GZ' THEN DO
563 nq = RXQUEUE('CREATE')
564 oq = RXQUEUE('SET', nq )
565 ADDRESS CMD '@gzip -c -d' ppd_file '| RXQUEUE' nq
566 DO QUEUED()
567 PARSE PULL line
568 line = STRIP( line )
569 IF LEFT( line, 15 ) == '*ShortNickName:' THEN DO
570 PARSE VAR line . ':' _nick '0D'x .
571 nickname = STRIP( _nick )
572 nickname = STRIP( nickname, 'B', '"')
573 LEAVE
574 END
575 END
576 CALL RXQUEUE 'SET', oq
577 CALL RXQUEUE 'DELETE', nq
578 END
579 ELSE DO
580 CALL LINEIN ppd_file, 1, 0
581 DO WHILE LINES( ppd_file ) <> 0
582 line = STRIP( LINEIN( ppd_file ))
583 IF LEFT( line, 15 ) == '*ShortNickName:' THEN DO
584 PARSE VAR line . ':' _nick '0D'x .
585 nickname = STRIP( _nick )
586 nickname = STRIP( nickname, 'B', '"')
587 LEAVE
588 END
589 END
590 CALL STREAM ppd_file, 'C', 'CLOSE'
591 END
592
593RETURN nickname
594
595/*:VRX CleanPPD
596*/
597/* Clean out lines from Gutenprint and Foomatic PPD files that are known to
598 * cause problems when importing with PIN. (Partially based on work by Paul
599 * Smedley and Peter Brown).
600 */
601CleanPPD: PROCEDURE
602 PARSE ARG in_ppd, logfile
603 IF logfile <> '' THEN
604 logfile = STREAM( logfile, 'C', 'QUERY EXISTS')
605
606 out_ppd = VRParseFilePath( in_ppd, 'DPN') || '.TMP'
607 IF STREAM( out_ppd, 'C', 'QUERY EXISTS') \= '' THEN
608 CALL SysFileDelete out_ppd
609
610 IF logfile <> '' THEN
611 CALL CHAROUT logfile, 'Doing cleanup on' in_ppd '...'
612
613 skip_next = 0
614 DO WHILE LINES( in_ppd ) \= 0
615 line = LINEIN( in_ppd )
616 SELECT
617 WHEN skip_next == 1 THEN DO
618 line = STRIP( TRANSLATE( line ))
619 IF line == '*END' THEN skip_next = 0
620 END
621 WHEN LEFT( line, 11 ) == '*StpDefault' THEN NOP
622 WHEN LEFT( line, 7 ) == '*StpStp' THEN NOP
623 WHEN LEFT( line, 18 ) == '*StpResolutionMap:' THEN NOP
624 WHEN LEFT( line, 14 ) == '*OPOptionHints' THEN NOP
625 WHEN LEFT( line, 4 ) == '*da.' THEN NOP
626 WHEN LEFT( line, 4 ) == '*de.' THEN NOP
627 WHEN LEFT( line, 4 ) == '*es.' THEN NOP
628 WHEN LEFT( line, 4 ) == '*fi.' THEN NOP
629 WHEN LEFT( line, 4 ) == '*fr.' THEN NOP
630 WHEN LEFT( line, 4 ) == '*it.' THEN NOP
631 WHEN LEFT( line, 4 ) == '*ja.' THEN NOP
632 WHEN LEFT( line, 4 ) == '*ko.' THEN NOP
633 WHEN LEFT( line, 4 ) == '*nb.' THEN NOP
634 WHEN LEFT( line, 4 ) == '*nl.' THEN NOP
635 WHEN LEFT( line, 4 ) == '*pt.' THEN NOP
636 WHEN LEFT( line, 4 ) == '*sv.' THEN NOP
637 WHEN LEFT( line, 7 ) == '*zh_CN.' THEN NOP
638 WHEN LEFT( line, 7 ) == '*zh_TW.' THEN NOP
639 WHEN LEFT( line, 9 ) == '*Foomatic' THEN DO
640 line = STRIP( line )
641 IF RIGHT( line, 2 ) == '&&' THEN skip_next = 1
642 END
643 OTHERWISE DO
644 CALL LINEOUT out_ppd, line
645 skip_next = 0
646 END
647 END
648 END
649 CALL STREAM in_ppd, 'C', 'CLOSE'
650 CALL STREAM out_ppd, 'C', 'CLOSE'
651
652 ok = VRCopyFile( out_ppd, in_ppd )
653 IF logfile <> '' THEN DO
654 IF ok == 1 THEN
655 CALL LINEOUT logfile, 'OK'
656 ELSE DO
657 CALL LINEOUT logfile, 'Failed!'
658 CALL LINEOUT logfile, ' ->' VRError()
659 END
660 CALL LINEOUT logfile, ''
661 END
662 CALL SysFileDelete out_ppd
663
664RETURN
665
666/*:VRX MatchPrinterModel
667*/
668/* Find a set of printers supported by the OS/2 driver which mostly closely
669 * match the given name.
670 */
671MatchPrinterModel: PROCEDURE EXPOSE globals. models.
672 PARSE UPPER ARG driver_name, printer_name
673 printer_name = TRANSLATE( printer_name, '_', '.')
674 printer_drv = globals.!os2dir'\DLL\'driver_name'\'driver_name'.DRV'
675 models.0 = 0
676
677 IF SysGetEA( printer_drv, '.EXPAND', 'exist_ea') <> 0 THEN RETURN 0
678 PARSE VAR exist_ea 1 _eatype 3 .
679 IF C2X( _eatype ) <> 'FDFF' THEN RETURN 0
680
681 PARSE VAR exist_ea 3 _ealen 5 exist_models
682 total_len = C2D( REVERSE( _ealen ))
683
684 /* The variable exist_models now contains a null-separated list of printer
685 * models supported by the driver (including those from previously-imported
686 * PPD files). Next we check each one against our requested printer name.
687 */
688 start = 1
689 count = 0
690 best = 0
691 DO WHILE start < total_len
692 _strend = POS('0'x, exist_models, start )
693 IF _strend == 0 THEN LEAVE
694 _model = TRANSLATE( SUBSTR( exist_models, start, _strend - start ))
695 _model = TRANSLATE( _model, ' ', '-')
696 _comp = COMPARE( _model, printer_name )
697 IF WORD( _model, 1 ) == WORD( printer_name, 1 ) THEN DO
698 count = count + 1
699 IF _comp == 0 THEN DO
700 _comp = 9999
701 best = count
702 END
703 ELSE IF ( best == 0 ) & ( _comp > LENGTH( printer_name )) THEN
704 best = count
705/*
706 models.count = RIGHT( _comp, 4, '0') SUBSTR( exist_models, start, _strend - start )
707*/
708 models.count = SUBSTR( exist_models, start, _strend - start )
709 END
710 start = _strend + 1
711 END
712 models.0 = count
713
714/*
715 CALL SysStemSort 'models.', 'D', 'I',,, 1, 4
716 DO i = 1 TO count
717 models.i = SUBWORD( models.i, 2 )
718 END
719*/
720RETURN best
721
722
723/*:VRX CheckWritablePath
724*/
725CheckWritablePath: PROCEDURE EXPOSE globals.
726 ARG path
727
728 /* Make sure path exists & is a directory */
729 IF \VRIsDir( path ) THEN RETURN 1
730
731 /* Make sure the drive is accessible */
732 di = SysDriveInfo( VRParseFilePath( path, 'DP'))
733 IF di == '' THEN RETURN 2
734
735 /* Make sure the drive has a supported filesystem */
736 fs = SysFileSystemType( prdrv )
737 IF WORDPOS( fs, 'HPFS JFS FAT FAT32') == 0 THEN RETURN 3
738
739RETURN 0
740
741
742/*:VRX QueryAvailableDrivers
743*/
744/* Determine which of our supported PrinterPak drivers are currently available.
745 */
746QueryAvailableDrivers: PROCEDURE EXPOSE globals. drv_list.
747 drv_list.0 = 0
748
749 test_drivers = 'ECUPS ECUPS-HP PSPRINT'
750 DO i = 1 TO WORDS( test_drivers )
751 driver = WORD( test_drivers, i )
752 ok = GetDriverSource( driver )
753 IF ok == '' THEN
754 ok = VRGetIni('PM_DEVICE_DRIVERS', driver, 'USER')
755 IF ok <> '' THEN
756 CALL SysStemInsert 'drv_list.', drv_list.0+1, driver
757 END
758
759RETURN drv_list.0
760
761
762/*:VRX PinWrapper
763*/
764/* Wrapper for PIN, which performs the following tasks:
765 * - Create a temporary working directory & copy the PrinterPak files there.
766 * - Pre-process the PPD file to make it ready for import, and saves it in
767 * a driver-specific 'saved PPDs' directory for future use.
768 * - Uses PIN to import the PPD into our temporary working copy of the driver.
769 * - Copy the updated driver back to our installable copy.
770 * - If update_all is 1 then also do the following:
771 * - If the driver is actually installed, copy the updated driver back
772 * over the installed version as well.
773 * - If this is a 'shipped' driver (i.e. one listed in PRDRV.LST) then
774 * add the newly-defined printer to PRDESC.LST.
775 */
776PinWrapper: PROCEDURE EXPOSE globals. driver_path driver_repo
777 ARG update_all, driver, ppdfile
778
779 CALL LINEOUT globals.!log1, 'Driver source: ' driver_path
780
781 workdir = SysTempFileName( globals.!tmpdir'\PPD_????')
782 ok = VRMkDir( workdir )
783 IF ok == 1 THEN ok = VrMkDir( workdir'\OUT')
784 IF ok <> 1 THEN
785 RETURN 5 /** RC=5 failed to create directory */
786
787 CALL LINEOUT globals.!log1, 'Temporary directory: ' workdir
788
789 SELECT
790 WHEN driver == 'ECUPS' THEN ppddir = globals.!repository'\PPD_E'
791 WHEN driver == 'ECUPS-HP' THEN ppddir = globals.!repository'\PPD_EHP'
792 WHEN driver == 'PSPRINT' THEN ppddir = globals.!repository'\PPD_PS'
793 WHEN driver == 'PSPRINT2' THEN ppddir = globals.!repository'\PPD_PS2'
794 WHEN driver == 'PSCRIPT2' THEN ppddir = globals.!repository'\PPD2'
795 WHEN driver == 'GUTENPRT' THEN ppddir = globals.!repository'\PPD_GP'
796 OTHERWISE ppddir = globals.!repository'\PPD'
797 END
798
799 /* Make sure ppddir (for keeping PPD files) exists */
800 CALL SysFileTree ppddir, 'dirs.', 'DO'
801 IF dirs.0 == 0 THEN DO
802 ok = VRMkDir( ppddir )
803 IF ok <> 1 THEN
804 RETURN 5 /** RC=5 failed to create directory */
805 END
806
807 CALL LINEOUT globals.!log1, 'Directory for PPD files:' ppddir
808
809 /***
810 *** Now do the actual work.
811 ***/
812
813 /* Copy the needed driver files to our working directories.
814 */
815 drvr_dir = VRParseFileName( driver_path, 'DP')
816 drv_out = workdir'\OUT\'driver'.DRV'
817 pin_exe = workdir'\PIN.EXE'
818 ppd_exe = workdir'\PPDENC.EXE'
819 ok = VRCopyFile( driver_path, drv_out )
820 IF ok == 1 THEN ok = VRCopyFile( drvr_dir'\PIN.EXE', pin_exe )
821 IF ok == 1 THEN ok = VRCopyFile( drvr_dir'\PPDENC.EXE', ppd_exe )
822 IF ok == 0 THEN DO
823 RETURN 4 /*** RC=4 Failed to copy driver files ***/
824 END
825
826 /* Set up the output redirection.
827 */
828 nq = RXQUEUE('CREATE')
829 oq = RXQUEUE('SET', nq )
830
831 /* If we are importing a new PPD file, prep it first.
832 * (If ppdfile is undefined, it means we are reimporting a directory of
833 * previously-imported PPDs, and we can assume they are already prepped.)
834 */
835 IF ppdfile <> '' THEN DO
836
837 /* If the PPD file is compressed, uncompress it.
838 */
839 IF VRParseFilePath( ppdfile, 'E') == 'GZ' THEN DO
840 decppd = workdir'\' || VRParseFilePath( ppdfile, 'N')
841 CALL LINEOUT globals.!log1, 'Decompressing' ppdfile 'to' decppd
842 ADDRESS CMD '@'globals.!programs.!gzip '-c -d' ppdfile '| RXQUEUE' nq
843 DO QUEUED()
844 PARSE PULL line
845 CALL LINEOUT decppd, line
846 END
847 CALL LINEOUT decppd
848 ppdfile = decppd
849 END
850
851 IF VRFileExists( ppdfile ) == 0 THEN DO
852 CALL LINEOUT globals.!log1, 'PPD file' ppdfile 'could not be found.'
853 RETURN 6 /** RC=6 PPD import failed **/
854 END
855
856 ppd_use = ppddir'\' || VRParseFileName( ppdfile, 'NE')
857
858 /* Now we have to clean up and validate the PPD file so PIN can use it.
859 * First, PPDENC converts the codepage if necessary, and copies the results
860 * to our working directory.
861 */
862 CALL LINEOUT globals.!log1, 'Converting PPD with:' ppd_exe ppdfile ppd_use
863 ADDRESS CMD '@'ppd_exe ppdfile ppd_use '2>NUL | RXQUEUE' nq
864 DO QUEUED()
865 PULL output
866 CALL LINEOUT globals.!log2, output
867 END
868 CALL LINEOUT globals.!log2, ''
869 CALL LINEOUT globals.!log2
870
871 IF VRFileExists( ppd_use ) == 0 THEN DO
872 CALL LINEOUT globals.!log1, 'Hmm,' ppd_use 'was not created. Copying manually.'
873 CALL VRCopyFile ppdfile, ppd_use
874 END
875
876 /* Next we strip out some problematic PPD statements which are often
877 * encountered in (for example) CUPS-based PPD files.
878 */
879 CALL CleanPPD ppd_use, globals.!log1
880
881 END
882
883 /* Preparation complete. Now do the import.
884 */
885 count = 0
886 ADDRESS CMD '@'pin_exe 'ppd' ppddir drv_out '2>NUL | RXQUEUE' nq
887 DO QUEUED()
888 PARSE PULL output
889 CALL LINEOUT globals.!log2, output
890 PARSE VAR output . 'OK (' nickname
891 IF nickname <> '' THEN DO
892 count = count + 1
893 newprinters.count = STRIP( nickname, 'T', ')')
894 END
895 END
896 newprinters.0 = count
897 CALL LINEOUT globals.!log2, ''
898 CALL LINEOUT globals.!log2
899
900 /* End the output redirection.
901 */
902 CALL RXQUEUE 'SET', oq
903 CALL RXQUEUE 'DELETE', nq
904
905 IF newprinters.0 == 0 THEN DO
906 RETURN 6 /** RC=6 PPD import failed **/
907 END
908
909 /***
910 *** Post-import processing.
911 ***/
912
913 IF ( driver_repo == 1 ) & ( update_all <> 0 ) THEN DO
914 /* If we're working out of the repository, we need to update the
915 * driver table in PRDESC.LST to add the new driver(s).
916 */
917
918 CALL LINEOUT globals.!log1, 'Updating' globals.!prdesc 'with new entries from' drv_out
919
920/* -- This causes a SYS3175 in the .DRV for some reason...
921 ok = UpdatePrDesc( driver'.DRV', drv_out )
922 IF ok <> 0 THEN
923 CALL LINEOUT globals.!log1, 'Failed to update' globals.!prdesc '(are EAs on' drv_out ' valid?)'
924*/
925
926 count = 0
927
928 /* First, copy all lines that don't refer to the driver just updated */
929 CALL LINEIN globals.!prdesc, 1, 0
930 DO WHILE LINES( globals.!prdesc )
931 _next = LINEIN( globals.!prdesc )
932 PARSE UPPER VAR _next . ':' _rest
933 _tail = SUBSTR( _rest, LASTPOS('(', _rest ))
934 PARSE VAR _tail '('_prdrv')' .
935 IF _prdrv == driver'.DRV' THEN ITERATE
936 count = count + 1
937 defs.count = _next
938 END
939 CALL STREAM globals.!prdesc, 'C', 'CLOSE'
940
941 /* Next, create a new list for the updated driver and merge that in */
942 newlist = workdir'\'driver'.LST'
943 CALL CreateDriverList drv_out, newlist
944 DO WHILE LINES( newlist )
945 _line = LINEIN( newlist )
946 count = count + 1
947 defs.count = _line
948 END
949 CALL STREAM newlist, 'C', 'CLOSE'
950 defs.0 = count
951
952 /* Now sort the list and recreate PRDESC.LST */
953 CALL SysStemSort 'defs.',, 'I'
954 prdesc_tmp = workdir'\PRDESC.LST'
955 IF STREAM( prdesc_tmp, 'C', 'QUERY EXISTS') <> '' THEN
956 CALL VRDeleteFile prdesc_tmp
957 DO i = 1 TO defs.0
958 CALL LINEOUT prdesc_tmp, defs.i
959 END
960 CALL LINEOUT prdesc_tmp
961 ok = VRCopyFile( prdesc_tmp, globals.!prdesc )
962 IF ok == 0 THEN DO
963 RETURN 7 /** RC=7 Error updating PRDESC.LST **/
964 END
965 CALL VRDeleteFile prdesc_tmp
966
967 END
968
969 /* Finally, copy the updated driver files.
970 */
971 target = VRParseFilePath( driver_path, 'DP')
972 CALL LINEOUT globals.!log1, 'Copying files from' workdir'\OUT to' target
973 CALL PRReplaceModule target'\'driver'.DRV', '', ''
974 ok = VRCopyFile( workdir'\OUT\'driver'.DRV', target'\'driver'.DRV')
975 IF ok == 1 THEN
976 ok = VRCopyFile( workdir'\OUT\AUXPRINT.PAK', target'\AUXPRINT.PAK')
977
978 IF ( ok == 1 ) & ( update_all <> 0 ) THEN DO
979 /* Copy the updated files to \OS2\DLL\<driver>, replacing any
980 * existing copies. (This prevents problems if the OS/2 driver
981 * installation fails to copy them, which can happen under some
982 * circumstances.)
983 */
984 IF VRFileExists( globals.!os2dir'\DLL\'driver'\'driver'.DRV') THEN DO
985 CALL VRCopyFile workdir'\OUT\AUXPRINT.PAK',,
986 globals.!os2dir'\DLL\'driver'\AUXPRINT.PAK'
987 CALL PRReplaceModule globals.!os2dir'\DLL\'driver'\'driver'.DRV', '', ''
988 CALL VRCopyFile workdir'\OUT\'driver'.DRV', globals.!os2dir'\DLL\'driver'\'driver'.DRV'
989 END
990 END
991 IF ok == 0 THEN DO
992 CALL LINEOUT globals.!log1, VRError()
993 RETURN 4 /*** RC=4 Failed to copy driver files ***/
994 END
995
996 CALL LINEOUT globals.!log1, newprinters.0 'printers imported successfully.'
997 DO i = 1 TO newprinters.0
998 CALL LINEOUT globals.!log1, ' ->' newprinters.i
999 END
1000 CALL LINEOUT globals.!log1, ''
1001 CALL LINEOUT globals.!log1
1002
1003 /* Clean up our work directories.
1004 */
1005 CALL VRDeleteFile workdir'\OUT\*'
1006 CALL VRDeleteFile workdir'\*'
1007 CALL VRRmDir( workdir'\OUT')
1008 CALL VRRmDir( workdir )
1009
1010RETURN 0
1011
1012
1013/*:VRX UpdatePrDesc
1014*/
1015UpdatePrDesc: PROCEDURE EXPOSE globals.
1016 ARG driver, fqn
1017
1018 IF globals.!prdesc == '' THEN RETURN 1
1019
1020 ok = RPUEnumModels( fqn, 'newdevs.')
1021 IF ok == 0 THEN RETURN 2
1022
1023 _count = 0
1024 CALL LINEIN globals.!prdesc, 1, 0
1025 DO WHILE LINES( globals.!prdesc )
1026 _next = LINEIN( globals.!prdesc )
1027 PARSE UPPER VAR _next WITH . ':' . '('_prdrv')' .
1028 IF _prdrv == driver THEN ITERATE
1029 _count = _count + 1
1030 prdefs.count = _next
1031 END
1032 CALL STREAM globals.!prdesc, 'C', 'CLOSE'
1033
1034 DO i = 1 TO newdevs.0
1035 _count = _count + 1
1036 prdefs._count = newdevs.i':' newdevs.i '('driver')'
1037 END
1038 prdefs.0 = count
1039
1040 CALL VRSortStem 'prdefs.'
1041
1042 _prdir = VRParseFileName( globals.!prdesc, 'DP')
1043 CALL VRCopyFile globals.!prdesc, _prdir'\PRDESC.BAK'
1044 CALL VRDeleteFile globals.!prdesc
1045 DO i = 1 TO prdefs.0
1046 CALL LINEOUT globals.!prdesc, prdefs.i
1047 END
1048 CALL LINEOUT globals.!prdesc
1049
1050RETURN 0
1051
1052
1053/*:VRX NLSGetMessage
1054*/
1055/*
1056 * Gets the message text associated with the given message number from the
1057 * current language file.
1058 */
1059NLSGetMessage: PROCEDURE EXPOSE globals.
1060 PARSE ARG msgnum, .
1061 args = ARG()
1062
1063 msgfile = globals.!messages
1064 IF msgnum == '' THEN RETURN ''
1065
1066 sub_parms = ''
1067 DO i = 2 TO args
1068 sub_parms = sub_parms', "'ARG( i )'"'
1069 END
1070
1071 INTERPRET 'msgfromfile = SysGetMessage( msgnum, msgfile' sub_parms ')'
1072
1073 PARSE VAR msgfromfile message '0D'x .
1074 IF SUBSTR( message, 1, 4 ) == 'SYS0' THEN message = ''
1075
1076RETURN message
1077
1078
1079/*:VRX NLSSetText
1080*/
1081/*
1082 * Sets the specified property of the specified control to the specified
1083 * message text.
1084 */
1085NLSSetText: PROCEDURE EXPOSE globals.
1086 PARSE ARG control, property, message, substitution
1087 args = ARG()
1088
1089 success = 1
1090 IF args < 4 THEN
1091 text = NLSGetMessage( message )
1092 ELSE DO
1093 sub_parms = ''
1094 DO i = 4 TO args
1095 sub_parms = sub_parms '"'|| ARG( i ) ||'",'
1096 END
1097 sub_parms = STRIP( sub_parms, 'T', ',')
1098 INTERPRET 'text = NLSGetMessage( message, 'sub_parms')'
1099 END
1100
1101 IF text == '' THEN success = 0
1102 ELSE CALL VRSet control, property, text
1103
1104RETURN success
1105
1106/*:VRX StringTokenize
1107*/
1108StringTokenize:
1109 PARSE ARG string, separator, __stem
1110 CALL __StringTokenize string, separator, __stem
1111 DROP __stem
1112RETURN
1113
1114/*:VRX __StringTokenize
1115*/
1116__StringTokenize: PROCEDURE EXPOSE (__stem)
1117 PARSE ARG string, separator, tokens
1118
1119 /* Note: this differs slightly from my usual implementation in that
1120 * each token is STRIPped of leading and trailing spaces.
1121 */
1122
1123 IF ( string = '') THEN RETURN string
1124 IF ( separator = '') THEN separator = ' '
1125
1126 i = 0
1127 CALL VALUE tokens || '0', i
1128 DO WHILE LENGTH( string ) > 0
1129 x = 1
1130 y = POS( separator, string, x )
1131 IF y > 0 THEN DO
1132 current = SUBSTR( string, 1, y-1 )
1133 x = y + 1
1134 i = i + 1
1135 CALL VALUE tokens || 'i', STRIP( current )
1136 END
1137 ELSE DO
1138 current = STRIP( string, 'B', separator )
1139 i = i + 1
1140 CALL VALUE tokens || 'i', STRIP( current )
1141 x = LENGTH( string ) + 1
1142 END
1143 string = SUBSTR( string, x )
1144 END
1145 CALL VALUE tokens || '0', i
1146
1147RETURN
1148
Note: See TracBrowser for help on using the repository browser.