Index: trunk/gui/printer/manager/PRINTOOL.RC
===================================================================
--- trunk/gui/printer/manager/PRINTOOL.RC	(revision 33)
+++ trunk/gui/printer/manager/PRINTOOL.RC	(revision 33)
@@ -0,0 +1,11 @@
+ICON 1  PRELOAD program.ico
+ICON 2  PRELOAD tango_printer.ico
+/*
+ICON 3  PRELOAD tango_printer_remote.ico
+ICON 4  PRELOAD file.ico
+ICON 5  PRELOAD port_generic.ico
+ICON 6  PRELOAD port_network.ico
+ICON 7  PRELOAD port_usb.ico
+ICON 10  PRELOAD port_cups.ico
+*/
+ICON 20  PRELOAD create.ico
Index: trunk/gui/printer/manager/PRINTOOL.VRP
===================================================================
--- trunk/gui/printer/manager/PRINTOOL.VRP	(revision 33)
+++ trunk/gui/printer/manager/PRINTOOL.VRP	(revision 33)
@@ -0,0 +1,22 @@
+VX-REXX OS/2 V2.14 Build B3
+VRX: PRINTOOL.VRX
+VXOFile: VROBJEX
+MacroPath: VRM:G:\netlabs\svn\ecups\trunk\gui\printer\manager
+EXEPath: G:\netlabs\svn\ecups\trunk\gui\printer\manager\PRINTMAN.EXE
+RunParameters:
+RunDirectory:
+VRXWindow: __VREMainWindow,1,494,3999,6697,8106
+VRXWindow: __VRESectionListWindow,1,1710,13731,4204,4059
+VRXWindow: __VREToolsWindow,1,1710,11997,4963,1669
+VRXWindow: __VREWindListWindow,1,6035,13731,3385,4059
+UserFile: 1
+UserWindow: WN_MAIN,1
+UserWindow: SW_WIZARD,1
+UserWindow: SW_PRINTERS,1
+UserWindow: SW_PRINTERPAKS,1
+UserWindow: SW_DEVICES,1
+UserWindow: SW_PORTS,1
+UserWindow: SW_ABOUT,1
+UserWindow: SW_PORT_ADD,1
+UserWindow: SW_MODELS,1
+UserWindow: SW_IMPORT,1
Index: trunk/gui/printer/manager/PRINTOOL.VRX
===================================================================
--- trunk/gui/printer/manager/PRINTOOL.VRX	(revision 33)
+++ trunk/gui/printer/manager/PRINTOOL.VRX	(revision 33)
@@ -0,0 +1,2378 @@
+/*:VRX         Main
+*/
+/*  Main
+*/
+Main:
+/*  Process the arguments.
+    Get the parent window.
+*/
+    parse source . calledAs .
+    parent = ""
+    argCount = arg()
+    argOff = 0
+    if( calledAs \= "COMMAND" )then do
+        if argCount >= 1 then do
+            parent = arg(1)
+            argCount = argCount - 1
+            argOff = 1
+        end
+    end; else do
+        call VROptions 'ImplicitNames'
+        call VROptions 'NoEchoQuit'
+    end
+    InitArgs.0 = argCount
+    if( argCount > 0 )then do i = 1 to argCount
+        InitArgs.i = arg( i + argOff )
+    end
+    drop calledAs argCount argOff
+
+/*  Load the windows
+*/
+    call VRInit
+    parse source . . spec
+    _VREPrimaryWindowPath = ,
+        VRParseFileName( spec, "dpn" ) || ".VRW"
+    _VREPrimaryWindow = ,
+        VRLoad( parent, _VREPrimaryWindowPath )
+    drop parent spec
+    if( _VREPrimaryWindow == "" )then do
+        call VRMessage "", "Cannot load window:" VRError(), ,
+            "Error!"
+        _VREReturnValue = 32000
+        signal _VRELeaveMain
+    end
+
+/*  Process events
+*/
+    call Init
+    signal on halt
+    do while( \ VRGet( _VREPrimaryWindow, "Shutdown" ) )
+        _VREEvent = VREvent()
+        interpret _VREEvent
+    end
+_VREHalt:
+    _VREReturnValue = Fini()
+    call VRDestroy _VREPrimaryWindow
+_VRELeaveMain:
+    call VRFini
+exit _VREReturnValue
+
+VRLoadSecondary:
+    __vrlsWait = abbrev( 'WAIT', translate(arg(2)), 1 )
+    if __vrlsWait then do
+        call VRFlush
+    end
+    __vrlsHWnd = VRLoad( VRWindow(), VRWindowPath(), arg(1) )
+    if __vrlsHWnd = '' then signal __vrlsDone
+    if __vrlsWait \= 1 then signal __vrlsDone
+    call VRSet __vrlsHWnd, 'WindowMode', 'Modal'
+    __vrlsTmp = __vrlsWindows.0
+    if( DataType(__vrlsTmp) \= 'NUM' ) then do
+        __vrlsTmp = 1
+    end
+    else do
+        __vrlsTmp = __vrlsTmp + 1
+    end
+    __vrlsWindows.__vrlsTmp = VRWindow( __vrlsHWnd )
+    __vrlsWindows.0 = __vrlsTmp
+    do while( VRIsValidObject( VRWindow() ) = 1 )
+        __vrlsEvent = VREvent()
+        interpret __vrlsEvent
+    end
+    __vrlsTmp = __vrlsWindows.0
+    __vrlsWindows.0 = __vrlsTmp - 1
+    call VRWindow __vrlsWindows.__vrlsTmp
+    __vrlsHWnd = ''
+__vrlsDone:
+return __vrlsHWnd
+
+/*:VRX         __VXREXX____APPENDS__
+*/
+__VXREXX____APPENDS__:
+/*
+#append ..\..\Shared\PrManUtl.VRS
+*/
+return
+/*:VRX         CheckPrograms
+*/
+CheckPrograms: PROCEDURE EXPOSE globals.
+
+    /* See if CUPSLPR.EXE (required by CUPS.PDR) is installed.
+     */
+    tcpipbin = SysSearchPath('PATH', 'inetd.exe')
+    IF tcpipbin <> '' THEN
+        tcpipbin = VRParseFileName( tcpipbin, 'DP')
+    ELSE
+        tcpipbin = globals.!bootdrv'\TCPIP\BIN'
+    globals.!programs.!cupslpr = STREAM( tcpipbin'\cupslpr.exe', 'C', 'QUERY EXISTS')
+    IF globals.!programs.!cupslpr == '' THEN
+        globals.!programs.!cupslpr = SysSearchPath('PATH', 'cupslpr.exe')
+    IF globals.!programs.!cupslpr == '' THEN
+        globals.!programs.!cupslpr = STREAM( globals.!mydir'\cupslpr.exe', 'C', 'QUERY EXISTS')
+
+    /* See if GZIP.EXE is installed (required for unpacking CUPS PPDs).
+     */
+    globals.!programs.!gzip = SysSearchPath('PATH', 'gzip.exe')
+    IF globals.!programs.!gzip == '' THEN
+        globals.!programs.!gzip = SysSearchPath('PATH', 'gunzip.exe')
+    IF globals.!programs.!gzip == '' THEN
+        globals.!programs.!gzip = STREAM( globals.!mydir'\gzip.exe', 'C', 'QUERY EXISTS')
+
+RETURN
+
+/*:VRX         CN_DEVICES_ContextMenu
+*/
+CN_DEVICES_ContextMenu:  PROCEDURE EXPOSE globals.
+
+    _record = VRInfo("Record")
+    IF _record <> '' THEN DO
+        CALL VRMethod 'CN_DEVICES', 'SetRecordAttr', _record, 'Selected', 1
+        CALL VRMethod 'MN_DRIVERS', 'Popup'
+    END
+    ELSE
+        CALL VRMethod 'MN_VIEW', 'Popup'
+
+RETURN
+
+/*:VRX         CN_PORTS_ContextMenu
+*/
+CN_PORTS_ContextMenu: PROCEDURE EXPOSE globals.
+
+    _record = VRInfo("Record")
+    IF _record <> '' THEN DO
+        CALL VRMethod 'CN_PORTS', 'SetRecordAttr', _record, 'Selected', 1
+        CALL VRMethod 'MN_PORT', 'Popup'
+    END
+    ELSE DO
+        CALL VRMethod 'MN_VIEW', 'Popup'
+    END
+
+RETURN
+
+/*:VRX         CN_PRINTERPAKS_ContextMenu
+*/
+CN_PRINTERPAKS_ContextMenu: PROCEDURE EXPOSE globals.
+    _record = VRInfo("Record")
+    IF _record <> '' THEN DO
+        CALL VRMethod 'CN_PRINTERPAKS', 'SetRecordAttr', _record, 'Selected', 1
+        CALL VRMethod 'MN_PRINTERPAK', 'Popup'
+    END
+RETURN
+
+/*:VRX         CN_PRINTERS_ContextMenu
+*/
+CN_PRINTERS_ContextMenu: PROCEDURE EXPOSE globals.
+
+    _record = VRInfo("Record")
+    IF _record <> '' THEN DO
+        CALL VRMethod 'CN_PRINTERS', 'SetRecordAttr', _record, 'Selected', 1
+        _flags = VRMethod('CN_PRINTERS', 'GetFieldData', _record, globals.!hcfPrinters.!flags )
+        IF POS('D', _flags ) > 0 THEN
+            CALL VRSet 'MI_PRINTER_DEFAULT', 'Checked', 1
+        ELSE
+            CALL VRSet 'MI_PRINTER_DEFAULT', 'Checked', 0
+        IF POS('P', _flags ) > 0 THEN
+            CALL VRSet 'MI_PRINTER_HOLD', 'Checked', 1
+        ELSE
+            CALL VRSet 'MI_PRINTER_HOLD', 'Checked', 0
+        CALL VRMethod 'MN_PRINTER', 'Popup'
+    END
+    ELSE
+        CALL VRMethod 'MN_VIEW', 'Popup'
+
+RETURN
+
+/*:VRX         CN_PRINTERS_DoubleClick
+*/
+CN_PRINTERS_DoubleClick:
+    CALL PrinterOpen VRInfo("Record")
+RETURN
+
+/*:VRX         DriverAdd
+*/
+DriverAdd: PROCEDURE EXPOSE globals.
+
+RETURN
+
+/*:VRX         DriverDelete
+*/
+DriverDelete: PROCEDURE EXPOSE globals
+
+RETURN
+
+/*:VRX         Fini
+*/
+Fini:
+    window = VRWindow()
+    call VRSet window, "Visible", 0
+    drop window
+return 0
+
+/*:VRX         GetPrinterPaks
+*/
+GetPrinterPaks: PROCEDURE EXPOSE globals.
+    IF globals.!prdrv  == '' THEN RETURN 0
+
+    IF globals.!is_ecs == 1 THEN _osname = 'eComStation'
+    ELSE _osname = 'OS/2'
+
+    CALL VRSet 'WN_MAIN', 'Pointer', 'WAIT'
+
+    _count = 0
+    DO WHILE LINES( globals.!prdrv ) > 0
+        /* Read the driver definition from PRDRV.LST
+         */
+        _ppdef = STRIP( LINEIN( globals.!prdrv ))
+        IF _ppdef == '' THEN ITERATE
+        PARSE VAR _ppdef _ppdriver _ppdisk _ppdesc
+        IF _ppdisk == '' THEN ITERATE
+        _ppdesc = STRIP( _ppdesc )
+        _pppath = globals.!repository'\PMDD_'_ppdisk
+
+        /* Check to see if the driver is installed/active.
+         */
+        _flags = 'R'
+        PARSE UPPER VAR _ppdriver _basename'.DRV' .
+        PARSE VALUE VRGetIni('PM_DEVICE_DRIVERS', _basename, 'USER') WITH used_drv '00'x .
+        IF ( used_drv <> '') & VRFileExists( used_drv ) THEN DO
+            _ppicon = '$1:'used_drv
+            _ppstatus = NLSGetMessage( 177, _osname ) NLSGetMessage( 180 )
+            _flags = 'I'
+        END
+        ELSE IF VRFileExists( _pppath'\'_ppdriver ) THEN DO
+            _ppicon = '$1:'_pppath'\'_ppdriver
+            _ppstatus = NLSGetMessage( 177, _osname )
+        END
+        ELSE ITERATE
+
+        _pprev = BldLevelVersion( _pppath'\'_ppdriver )
+
+        /* Driver found, add the record.
+         */
+        _count = _count + 1
+        _fielddata = globals.!hcfPaks.!icon';'_ppicon';' ||,
+                     globals.!hcfPaks.!name';'_ppdriver';' ||,
+                     globals.!hcfPaks.!status';'_ppstatus';' ||,
+                     globals.!hcfPaks.!path';'_pppath';' ||,
+                     globals.!hcfPaks.!version';'_pprev';' ||,
+                     globals.!hcfPaks.!desc';'_ppdesc';' ||,
+                     globals.!hcfPaks.!flags';'_flags';'
+        ppaks._count = ';'_ppdriver';'_ppicon';;;'_fielddata
+    END
+    CALL STREAM globals.!prdrv, 'C', 'CLOSE'
+
+    /* Now look for some known third-party drivers.
+     */
+    PARSE UPPER VALUE VRGetIni('PrinterManager', 'ThirdParty', 'USER') WITH known_3p '00'x .
+    IF known_3p == '' THEN
+        known_3p = 'ECUPS ECUPS-HP GUTENPRT PSPRINT'
+    DO i = 1 TO WORDS( known_3p )
+        _basename = WORD( known_3p, i )
+        _ppini = VRGetIni('PM_INSTALL', _basename'_DIR', 'USER')
+        IF _ppini == '' THEN ITERATE
+        PARSE VAR _ppini _pppath '00'x .
+
+        /* Check to see if the driver is installed/active.
+         */
+        _flags = ''
+        _ppdriver = _basename'.DRV'
+        PARSE VALUE VRGetIni('PM_DEVICE_DRIVERS', _basename, 'USER') WITH used_drv '00'x .
+        IF ( used_drv <> '') & VRFileExists( used_drv ) THEN DO
+            _ppicon = '$1:'used_drv
+            _ppstatus = NLSGetMessage( 178 ) NLSGetMessage( 180 )
+            _flags = 'I'
+        END
+        ELSE IF VRFileExists( _pppath'\'_ppdriver ) THEN DO
+            _ppicon = '$1:'_pppath'\'_ppdriver
+            _ppstatus = NLSGetMessage( 178 )
+        END
+        ELSE ITERATE
+
+        _pprev = BldLevelVersion( _pppath'\'_ppdriver )
+
+        /* Driver found, add the record.
+         */
+        _count = _count + 1
+        _fielddata = globals.!hcfPaks.!icon';'_ppicon';' ||,
+                     globals.!hcfPaks.!name';'_ppdriver';' ||,
+                     globals.!hcfPaks.!status';'_ppstatus';' ||,
+                     globals.!hcfPaks.!path';'_pppath';'  ||,
+                     globals.!hcfPaks.!version';'_pprev';' ||,
+                     globals.!hcfPaks.!flags';'_flags';'
+        ppaks._count = ';'_ppdriver';'_ppicon';;;'_fielddata
+    END
+
+    ppaks.0 = _count
+    CALL VRMethod 'CN_PRINTERPAKS', 'AddRecordList',, 'Last', 'ppaks.'
+
+    CALL VRSet 'WN_MAIN', 'Pointer', '<default>'
+
+RETURN _count
+
+/*:VRX         Halt
+*/
+Halt:
+    signal _VREHalt
+return
+
+/*:VRX         ImportPPD
+*/
+/* Import a new PPD file into a PostScript driver.  This is unfortunately rather
+ * complicated, all the more so because we need to deal with a large number of
+ * possible situations.
+ */
+ImportPPD: PROCEDURE EXPOSE globals.
+    ARG driver, ppdfile
+    IF driver == '' THEN driver = 'PSCRIPT'
+
+    CALL LINEOUT globals.!log1, 'Going to import PPD file into driver' driver'.'
+
+    status = LocateDriverFiles( driver )
+
+    SELECT
+
+        /* An installable copy of the driver was found.  No special action is
+         * required; we can proceed with the import logic below.
+         */
+        WHEN status == 1 THEN NOP
+
+        /* An installable (working) copy of the driver could not be located, but
+         * we found an installed (in use) version whence we can grab the files.
+         */
+        WHEN status == 2 THEN DO
+            /* We need somewhere for the installable copies to live.  We ask
+             * the user to confirm this path, as they'll have to specify the
+             * directory later on if they install the driver from PM.
+             */
+            _btn.1 = NLSGetMessage( 2 )
+            _btn.2 = NLSGetMessage( 3 )
+            _btn.3 = NLSGetMessage( 188 )
+            _btn.0 = 3
+            _prompt = NLSGetMessage( 232, driver ) ||,
+                      '0a0a0a'x || NLSGetMessage( 187, driver )
+
+            /* Try and determine a suitable default directory */
+            PARSE VALUE VRGetIni('PM_INSTALL', driver'_DIR', 'USER') WITH drvr_dir '00'x .
+            IF drvr_dir == '' THEN
+                PARSE VALUE VRGetIni('InstPDR', 'PATH_TO_'driver, 'USER') WITH drvr_dir '00'x .
+            IF drvr_dir == '' THEN
+                drvr_dir = globals.!repository'\'driver
+
+            /* Now prompt the user to confirm the path */
+            DO UNTIL _select <> 3
+                _select = VRPrompt( VRWindow(), _prompt, 'drvr_dir',,
+                                    NLSGetMessage( 189 ), '_btn.', 1, 2 )
+                IF _select == 3 THEN
+                    drv_dir = VRXDirectoryDialog( VRWindow(), drvr_dir, NLSGetMessage( 189 ))
+            END
+            IF drvr_dir == '' THEN RETURN 1                                     /** RC=1 cancelled */
+            drvr_dir = VRExpandFileName( drvr_dir )
+            IF drvr_dir == '' THEN RETURN 3                                     /** RC=3 bad path */
+
+            /* Create the new directory if necessary */
+            IF \VRIsDir( drvr_dir ) THEN
+                IF VRMkDir( drvr_dir ) == 0 THEN RETURN 5                       /** RC=5 failed to create directory */
+
+            /* Now copy the driver files */
+            IF CopyPrinterPak( driver_path, drvr_dir ) == 0 THEN RETURN 3       /** RC=4 failed to copy driver files */
+            CALL VRSetIni 'PM_INSTALL', driver'_DIR', drvr_dir||'00'x, 'USER'
+
+            /* Point to the copied driver files as our new working copy */
+            driver_path = drvr_dir'\'driver'.DRV'
+        END
+
+        OTHERWISE DO                    /* Driver was not found */
+            CALL VRMessage VRWindow(), NLSGetMessage( 231, driver ),,
+                           NLSGetMessage( 13 ), 'E'
+            RETURN 2                                                            /** RC=2 driver not found */
+        END
+
+    END
+
+    /* OK, we should now have an acceptable 'installable' copy of the
+     * PrinterPak files.  Next, we will:
+     *  - Create a temporary working directory & copy the PrinterPak files there
+     *  - Pre-process the PPD file to make it ready for import, and also copy it
+     *    to a driver-specific 'saved PPDs' directory for future use
+     *  - Use PIN to import the PPD into into our temporary working copy
+     *  - Copy the updated driver back to our installable copy
+     *  - If the driver is actually installed, copy the updated driver back over
+     *    the installed version as well.
+     *  - If this is a 'shipped' driver (i.e. one listed in PRDRV.LST) then add
+     *    the newly-defined printer to PRDESC.LST.
+     */
+
+    /** TODO should move all below this into a new shared function **/
+
+    CALL LINEOUT globals.!log1, 'Driver source:          ' driver_path
+
+    workdir = SysTempFileName( globals.!tmpdir'\PPD_????')
+    ok = VRMkDir( workdir )
+    IF ok == 1 THEN ok = VrMkDir( workdir'\OUT')
+    IF ok <> 1 THEN
+        RETURN 5                        /** RC=5 failed to create directory */
+
+    CALL LINEOUT globals.!log1, 'Temporary directory:    ' workdir
+
+    SELECT
+        WHEN driver == 'ECUPS'    THEN ppddir = globals.!repository'\PPD_E'
+        WHEN driver == 'ECUPS-HP' THEN ppddir = globals.!repository'\PPD_EHP'
+        WHEN driver == 'PSPRINT'  THEN ppddir = globals.!repository'\PPD_PS'
+        WHEN driver == 'PSPRINT2' THEN ppddir = globals.!repository'\PPD_PS2'
+        WHEN driver == 'PSCRIPT2' THEN ppddir = globals.!repository'\PPD2'
+        WHEN driver == 'GUTENPRT' THEN ppddir = globals.!repository'\PPD_GP'
+        OTHERWISE                      ppddir = globals.!repository'\PPD'
+    END
+
+    /* Make sure ppddir (for keeping PPD files) exists */
+    CALL SysFileTree ppddir, 'dirs.', 'DO'
+    IF dirs.0 == 0 THEN DO
+        ok = VRMkDir( ppddir )
+        IF ok <> 1 THEN
+            RETURN 5                    /** RC=5 failed to create directory */
+    END
+
+    CALL LINEOUT globals.!log1, 'Directory for PPD files:' ppddir
+
+    /***
+     *** Now do the actual work.
+     ***/
+
+
+    /* Copy the needed driver files to our working directories.
+     */
+    drvr_dir = VRParseFileName( driver_path, 'DP')
+    drv_out  = workdir'\OUT\'driver'.DRV'
+    pin_exe  = workdir'\PIN.EXE'
+    ppd_exe  = workdir'\PPDENC.EXE'
+    ok = VRCopyFile( driver_path, drv_out )
+    IF ok == 1 THEN ok = VRCopyFile( drvr_dir'\PIN.EXE', pin_exe )
+    IF ok == 1 THEN ok = VRCopyFile( drvr_dir'\PPDENC.EXE', ppd_exe )
+    IF ok == 0 THEN DO
+        RETURN 4                        /*** RC=4  Failed to copy driver files ***/
+    END
+
+    /* Set up the output redirection.
+     */
+    nq = RXQUEUE('CREATE')
+    oq = RXQUEUE('SET', nq )
+
+    /* If the PPD file is compressed, uncompress it.
+     */
+    IF VRParseFilePath( ppdfile, 'E') == 'GZ' THEN DO
+        decppd = workdir'\' || VRParseFilePath( ppdfile, 'N')
+        CALL LINEOUT globals.!log1, 'Decompressing' ppdfile 'to' decppd
+        ADDRESS CMD '@'globals.!programs.!gzip '-c -d' ppdfile '| RXQUEUE' nq
+        DO QUEUED()
+            PARSE PULL line
+            CALL LINEOUT decppd, line
+        END
+        CALL LINEOUT decppd
+        ppdfile = decppd
+    END
+
+    IF VRFileExists( ppdfile ) == 0 THEN DO
+        CALL LINEOUT globals.!log1, 'PPD file' ppdfile 'could not be found.'
+        RETURN 6                        /** RC=6  PPD import failed **/
+    END
+
+    ppd_use = ppddir'\' || VRParseFileName( ppdfile, 'NE')
+
+    /* Now we have to clean up and validate the PPD file so PIN can use it.
+     * First, PPDENC converts the codepage if necessary, and copies the results
+     * to our working directory.
+     */
+    CALL LINEOUT globals.!log1, 'Converting PPD with:' ppd_exe ppdfile ppd_use
+    ADDRESS CMD '@'ppd_exe ppdfile ppd_use '2>NUL | RXQUEUE' nq
+    DO QUEUED()
+        PULL output
+        CALL LINEOUT globals.!log2, output
+    END
+    CALL LINEOUT globals.!log2, ''
+    CALL LINEOUT globals.!log2
+
+    IF VRFileExists( ppd_use ) == 0 THEN DO
+        CALL LINEOUT globals.!log1, 'Hmm,' ppd_use 'was not created.  Copying manually.'
+        CALL VRCopyFile ppdfile, ppd_use
+    END
+
+    /* Next we strip out some problematic PPD statements which are often
+     * encountered in (for example) CUPS-based PPD files.
+     */
+    CALL CleanPPD ppd_use, globals.!log1
+
+    /* Preparation complete.  Now do the import.
+     */
+    count = 0
+    ADDRESS CMD '@'pin_exe 'ppd' ppddir drv_out '2>NUL | RXQUEUE' nq
+    DO QUEUED()
+        PARSE PULL output
+        CALL LINEOUT globals.!log2, output
+        PARSE VAR output . 'OK (' nickname
+        IF nickname <> '' THEN DO
+            count = count + 1
+            newprinters.count = STRIP( nickname, 'T', ')')
+        END
+    END
+    newprinters.0 = count
+    CALL LINEOUT globals.!log2, ''
+    CALL LINEOUT globals.!log2
+
+    /* End the output redirection.
+     */
+    CALL RXQUEUE 'SET',    oq
+    CALL RXQUEUE 'DELETE', nq
+
+
+    /***
+     *** Post-import processing.
+     ***/
+
+    IF newprinters.0 == 0 THEN DO
+        RETURN 6                        /** RC=6  PPD import failed **/
+    END
+
+    IF driver_repo == 1 THEN DO
+        /* If we're working out of the repository, we need to update the
+         * driver table in PRDESC.LST to add the new driver(s).
+         */
+
+        CALL LINEOUT globals.!log1, 'Updating' globals.!prdesc 'with new entries from' drv_out
+
+/* -- This causes a SYS3175 in the .DRV for some reason...
+        ok = UpdatePrDesc( driver'.DRV', drv_out )
+        IF ok <> 0 THEN
+            CALL LINEOUT globals.!log1, 'Failed to update' globals.!prdesc '(are EAs on' drv_out ' valid?)'
+*/
+
+        count = 0
+
+        /* First, copy all lines that don't refer to the driver just updated */
+        CALL LINEIN globals.!prdesc, 1, 0
+        DO WHILE LINES( globals.!prdesc )
+            _next = LINEIN( globals.!prdesc )
+            PARSE UPPER VAR _next WITH . ':' . '('_prdrv')' .
+            IF _prdrv == driver'.DRV' THEN ITERATE
+            count = count + 1
+            defs.count = _next
+        END
+        CALL STREAM globals.!prdesc, 'C', 'CLOSE'
+
+        /* Next, create a new list for the updated driver and merge that in */
+        newlist = workdir'\'driver'.LST'
+        CALL CreateDriverList drv_out, newlist
+        DO WHILE LINES( newlist )
+            _line = LINEIN( newlist )
+            count = count + 1
+            defs.count = _line
+        END
+        CALL STREAM newlist, 'C', 'CLOSE'
+        defs.0 = count
+
+        /* Now sort the list and recreate PRDESC.LST */
+        CALL SysStemSort 'defs.',, 'I'
+        prdesc_tmp = workdir'\PRDESC.LST'
+        IF STREAM( prdesc_tmp, 'C', 'QUERY EXISTS') <> '' THEN
+            CALL VRDeleteFile prdesc_tmp
+        DO i = 1 TO defs.0
+            CALL LINEOUT prdesc_tmp, defs.i
+        END
+        CALL LINEOUT prdesc_tmp
+        ok = VRCopyFile( prdesc_tmp, globals.!prdesc )
+        IF ok == 0 THEN DO
+            RETURN 7                    /** RC=7  Error updating PRDESC.LST **/
+        END
+        CALL VRDeleteFile prdesc_tmp
+
+    END
+
+    /* Finally, copy the updated driver files.
+     */
+    target = VRParseFilePath( driver_path, 'DP')
+    CALL LINEOUT globals.!log1, 'Copying files from' workdir'\OUT to' target
+    CALL PRReplaceModule target'\'driver'.DRV', '', ''
+    ok = VRCopyFile( workdir'\OUT\'driver'.DRV', target'\'driver'.DRV')
+    IF ok == 1 THEN
+        ok = VRCopyFile( workdir'\OUT\AUXPRINT.PAK', target'\AUXPRINT.PAK')
+    IF ok == 1 THEN DO
+        /* Copy the updated files to \OS2\DLL\<driver>, replacing any
+         * existing copies.  (This prevents problems if the OS/2 driver
+         * installation doesn't/fails to copy them, which can happen under
+         * some circumstances.)
+         */
+        IF VRFileExists( globals.!os2dir'\DLL\'driver'.DRV') THEN DO
+            CALL VRCopyFile workdir'\OUT\AUXPRINT.PAK',,
+                            globals.!os2dir'\DLL\'driver'\AUXPRINT.PAK'
+            CALL PRReplaceModule globals.!os2dir'\DLL\'driver'\'driver'.DRV', '', ''
+            CALL VRCopyFile workdir'\OUT\'driver'.DRV', globals.!os2dir'\DLL\'driver'\'driver'.DRV'
+        END
+    END
+    IF ok == 0 THEN DO
+        CALL LINEOUT globals.!log1, VRError()
+        RETURN 4                        /*** RC=4  Failed to copy driver files ***/
+    END
+
+    CALL LINEOUT globals.!log1, newprinters.0 'printers imported successfully.'
+    DO i = 1 TO newprinters.0
+        CALL LINEOUT globals.!log1, ' ->' newprinters.i
+    END
+    CALL LINEOUT globals.!log1, ''
+    CALL LINEOUT globals.!log1
+
+    /* Clean up our work directories.
+     */
+    CALL VRDeleteFile workdir'\OUT\*'
+    CALL VRDeleteFile workdir'\*'
+    CALL VRRmDir( workdir'\OUT')
+    CALL VRRmDir( workdir )
+
+RETURN 0
+
+/*:VRX         Init
+*/
+Init:
+
+    CALL RxFuncAdd 'SysLoadFuncs',     'REXXUTIL', 'SysLoadFuncs'
+    CALL SysLoadFuncs
+    CALL RxFuncAdd 'RPULoadFuncs',     'RXPRTUTL', 'RPULoadFuncs'
+    CALL RPULoadFuncs
+    CALL RxFuncAdd 'PRLoadFuncs',      'PR1UTIL', 'PRLoadFuncs'
+    CALL PRLoadFuncs
+    CALL RxFuncAdd 'WPToolsLoadFuncs', 'WPTOOLS',  'WPToolsLoadFuncs'
+    CALL WPToolsLoadFuncs
+    CALL RxFuncAdd 'VRXLoadFuncs',     'VROBJEX',  'VRXLoadFuncs'
+    CALL VRXLoadFuncs
+
+    globals.!wizard = 0
+    globals.!debug  = 0
+    globals.!initstate = 0
+
+    DO i = 1 TO InitArgs.0
+        PARSE UPPER VAR InitArgs.i _arg
+        SELECT
+            WHEN _arg == '/CREATE' THEN globals.!wizard = 1
+            WHEN LEFT( _arg, 2 ) == '/D' THEN globals.!debug = 1
+            OTHERWISE NOP
+        END
+    END
+
+    CALL LoadSettings
+    CALL SetLanguage
+    CALL CheckPrograms
+
+    window = VRWindow()
+    call VRMethod window, "CenterWindow"
+    call VRMethod window, "Activate"
+    IF globals.!wizard THEN DO
+        CALL VRMethod 'Application', 'PostQueue', 0, 1, 'CALL PB_PRINTER_ADD_Click'
+    END
+    ELSE
+        CALL VRSet window, "Visible", 1
+    drop window
+
+RETURN
+
+/*:VRX         LoadSettings
+*/
+LoadSettings: PROCEDURE EXPOSE globals.
+
+    globals.!version = '0.21'
+    globals.!copyright = '2013'
+
+    me = VRGet('Application', 'Program')
+    IF me == '' THEN PARSE SOURCE . . me
+    globals.!mydir = VRParseFilePath( me, 'DP')
+
+    /* Get CUPS paths.
+     */
+    PARSE VALUE VRGetIni('eCups', 'CUPS', 'USER') WITH cupsdrv '00'x .
+    IF cupsdrv == '' THEN
+        cupsdrv = VRParseFilePath( me, 'D') || ':'
+    ELSE
+        cupsdrv = STRIP( cupsdrv, 'T', '\')
+    globals.!cupsdir = cupsdrv'\cups'
+
+    /** TODO Identify if CUPS and/or CUPS.PDR is installed */
+    globals.!hascups = 1
+
+    /* Get system paths.
+     */
+    globals.!bootdrv = SysBootDrive()
+    IF globals.!bootdrv == '' THEN
+        globals.!bootdrv = FILESPEC('DRIVE', VALUE('OS2_SHELL',,'OS2ENVIRONMENT'))
+    globals.!os2dir = globals.!bootdrv'\OS2'
+    globals.!tmpdir = VALUE('TMP',,'OS2ENVIRONMENT')
+    IF globals.!tmpdir == '' THEN
+        globals.!tmpdir = VALUE('TEMP',,'OS2ENVIRONMENT')
+    IF globals.!tmpdir == '' THEN
+        globals.!tmpdir = globals.!mydir
+    globals.!logdir = VALUE('LOGFILES',,'OS2ENVIRONMENT')
+    IF globals.!logdir == '' THEN
+        globals.!logdir = globals.!mydir
+
+    globals.!log1 = globals.!logdir'\printmgr.l1'
+    globals.!log2 = globals.!logdir'\printmgr.l2'
+
+    /* Get printer-related paths.
+     */
+    PARSE VALUE VRGetIni('PM_INSTALL', 'PDR_DIR', 'USER') WITH repos_dir '00'x .
+    globals.!repository = repos_dir
+    globals.!prdrv      = STREAM( globals.!os2dir'\install\prdrv.lst',  'C', 'QUERY EXISTS')
+    globals.!prdesc     = STREAM( globals.!os2dir'\install\prdesc.lst', 'C', 'QUERY EXISTS')
+
+    /* Set the language file name.
+     */
+    globals.!nlsname = 'printm_'
+
+    /* Determine the OS.
+     */
+    IF VRFileExists( globals.!os2dir'\INSTALL\SYSLEVEL.ECS') THEN
+        globals.!is_ecs = 1
+    ELSE
+        globals.!is_ecs = 0
+
+    globals.!create_mode = ''
+
+RETURN
+
+/*:VRX         MI_ABOUT_Click
+*/
+MI_ABOUT_Click:
+    CALL VRLoadSecondary 'SW_ABOUT', 'W'
+RETURN
+
+/*:VRX         MI_DETAILVIEW_Click
+*/
+MI_DETAILVIEW_Click: PROCEDURE EXPOSE globals.
+
+    _page = VRGet('TDL_MAIN', 'Selected')
+    _pagewin = VRMethod('TDL_MAIN', 'GetPageWindow', _page )
+    _cnr = VRGet( _pagewin, 'UserData')
+    IF _cnr == '' THEN RETURN
+
+    CALL VRSet _cnr, 'Source', 0
+    _set = VRGet('MI_DETAILVIEW', 'Checked')
+    IF _set == 1 THEN RETURN
+
+    CALL VRSet _cnr, 'View', 'Detail'
+    CALL VRSet _cnr, 'MiniIcons', 1
+
+    CALL VRSet 'MI_ICONVIEW',   'Checked', 0
+    CALL VRSet 'MI_DETAILVIEW', 'Checked', 1
+
+RETURN
+
+/*:VRX         MI_DRIVERS_INSTALL_Click
+*/
+MI_DRIVERS_INSTALL_Click:
+    CALL DriverAdd
+return
+
+/*:VRX         MI_DRIVERS_REMOVE_Click
+*/
+MI_DRIVERS_REMOVE_Click:
+    CALL DriverDelete
+return
+
+/*:VRX         MI_ICONVIEW_Click
+*/
+MI_ICONVIEW_Click: PROCEDURE EXPOSE globals.
+
+    _page = VRGet('TDL_MAIN', 'Selected')
+    _pagewin = VRMethod('TDL_MAIN', 'GetPageWindow', _page )
+    _cnr = VRGet( _pagewin, 'UserData')
+    IF _cnr == '' THEN RETURN
+
+    CALL VRSet _cnr, 'Source', 0
+    _set = VRGet('MI_ICONVIEW', 'Checked')
+    IF _set == 1 THEN RETURN
+
+    CALL VRSet _cnr, 'View', 'Icon'
+    CALL VRSet _cnr, 'MiniIcons', 0
+
+    CALL VRSet 'MI_ICONVIEW',   'Checked', 1
+    CALL VRSet 'MI_DETAILVIEW', 'Checked', 0
+
+RETURN
+
+/*:VRX         MI_IMPORT_Click
+*/
+MI_IMPORT_Click: PROCEDURE EXPOSE globals. new_ppd
+
+    /* Prompt the user for the PPD file to import.
+     */
+    new_ppd = VRFileDialog( VRWindow(), NLSGetMessage( 230 ), 'O', '*.PPD')
+    IF new_ppd == '' THEN RETURN 0
+
+    /* Let the user select the Postscript driver to update.
+     */
+    CALL VRLoadSecondary 'SW_IMPORT', 'W'
+
+RETURN ok
+
+/*:VRX         MI_MANAGE_Click
+*/
+MI_MANAGE_Click: PROCEDURE EXPOSE globals.
+    CALL VRLoadSecondary 'SW_PRINTERPAKS', 'W'
+RETURN
+
+/*:VRX         MI_PORT_CREATE_Click
+*/
+MI_PORT_CREATE_Click:
+    CALL PortAdd
+return
+
+/*:VRX         MI_PORT_DELETE_Click
+*/
+MI_PORT_DELETE_Click:
+    CALL PortDelete
+return
+
+/*:VRX         MI_PORT_PROPS_Click
+*/
+MI_PORT_PROPS_Click:
+    CALL PortProperties
+RETURN
+
+/*:VRX         MI_PPAK_COPY_Click
+*/
+MI_PPAK_COPY_Click:
+    ok = VRMethod( "CN_PRINTERPAKS", "GetRecordList", "Selected", "recs." )
+    IF ok == 0 | recs.0 < 1 THEN RETURN
+    record = recs.1
+
+    _path = VRMethod('CN_PRINTERPAKS', 'GetFieldData', record, globals.!hcfPaks.!path )
+    CALL VRMethod 'Application', 'PutClipboard', _path
+
+    CALL VRMethod 'CN_PRINTERPAKS', 'SetRecordAttr', record, 'Source', 0
+RETURN
+
+/*:VRX         MI_PPAK_MODELS_Click
+*/
+MI_PPAK_MODELS_Click: PROCEDURE EXPOSE globals.
+
+    ok = VRMethod( "CN_PRINTERPAKS", "GetRecordList", "Selected", "recs." )
+    IF ok == 0 | recs.0 < 1 THEN RETURN
+    CALL VRMethod 'CN_PRINTERPAKS', 'SetRecordAttr', recs.1, 'Source', 0
+
+    CALL VRLoadSecondary 'SW_MODELS', 'W'
+
+RETURN
+
+/*:VRX         MI_PRINTER_CREATE_Click
+*/
+MI_PRINTER_CREATE_Click:
+    ok = VRMethod( "CN_PRINTERS", "GetRecordList", "Selected", "recs." )
+    IF ok == 1 & recs.0 > 0 THEN
+        CALL VRMethod 'CN_PRINTERS', 'SetRecordAttr', recs.1, 'Source', 0
+    CALL PrinterWizard
+RETURN
+
+/*:VRX         MI_PRINTER_DEFAULT_Click
+*/
+MI_PRINTER_DEFAULT_Click:
+    CALL PrinterSetDefault
+RETURN
+
+/*:VRX         MI_PRINTER_DELETE_Click
+*/
+MI_PRINTER_DELETE_Click:
+    CALL PrinterDelete
+RETURN
+
+/*:VRX         MI_PRINTER_HOLD_Click
+*/
+MI_PRINTER_HOLD_Click:
+    CALL PrinterHold
+return
+
+/*:VRX         MI_PRINTER_OPEN_Click
+*/
+MI_PRINTER_OPEN_Click:
+    CALL PrinterOpen
+RETURN
+
+/*:VRX         MI_PRINTER_PROPS_Click
+*/
+MI_PRINTER_PROPS_Click:
+    CALL PrinterProperties
+RETURN
+
+/*:VRX         MI_QUIT_Click
+*/
+MI_QUIT_Click:
+    CALL Quit
+return
+
+/*:VRX         MI_REFRESH_Click
+*/
+MI_REFRESH_Click: PROCEDURE EXPOSE globals.
+
+    _page = VRGet('TDL_MAIN', 'Selected')
+    _pagewin = VRMethod('TDL_MAIN', 'GetPageWindow', _page )
+    _cnr = VRGet( _pagewin, 'UserData')
+    IF _cnr == '' THEN RETURN
+
+    CALL VRSet _cnr, 'Source', 0
+
+    SELECT
+        WHEN _cnr == 'CN_PRINTERS' THEN CALL RefreshPrinters
+        WHEN _cnr == 'CN_PORTS' THEN CALL RefreshPorts
+        WHEN _cnr == 'CN_DEVICES' THEN CALL RefreshDevices
+        OTHERWISE NOP
+    END
+
+RETURN
+
+/*:VRX         New_CUPS
+*/
+New_CUPS: PROCEDURE EXPOSE globals.
+    PARSE ARG ppd_file
+
+    IF WPToolsQueryObject('<ECUPS_WIZARD>',,,'SetupString') == 1 THEN DO
+        PARSE VAR SetupString . 'EXENAME='cupswiz';' .
+        PARSE VAR SetupString . 'STARTUPDIR='_workdir';' .
+        PARSE VAR SetupString . 'PARAMETERS='_parms';' .
+        IF _workdir == '' THEN _workdir = VRParseFilePath( cupswiz, 'DP')
+    END
+    ELSE DO
+        cupswiz = Stream( globals.!cupsdir'\cups\cupswiz.exe', 'C', 'QUERY EXISTS')
+        _workdir = VRParseFilePath( cupswiz, 'DP')
+        _parms = ''
+    END
+    IF cupswiz <> '' THEN DO
+        od = DIRECTORY()
+        CALL DIRECTORY _workdir
+        IF ppd_file <> '' & VRFileExists( ppd_file ) THEN 
+            _parms = _parms ppd_file
+        ADDRESS CMD 'start' cupswiz _parms
+        CALL DIRECTORY od
+    END
+
+RETURN
+
+/*:VRX         New_LAN
+*/
+New_LAN: PROCEDURE EXPOSE globals.
+
+    ok = OpenPrinterTemplate('WPRPrinter')
+
+RETURN ok
+
+/*:VRX         New_Standard
+*/
+New_Standard: PROCEDURE EXPOSE globals.
+
+    ok = OpenPrinterTemplate('WPPrinter')
+
+RETURN ok
+
+/*:VRX         OpenPrinterTemplate
+*/
+OpenPrinterTemplate: PROCEDURE EXPOSE globals.
+    PARSE ARG _class
+
+    ok = 0
+    IF WPToolsFolderContent('<WP_TEMPS>', '_temps.', 'F') THEN
+    DO i = 1 TO _temps.0
+        IF WPToolsQueryObject( _temps.i, 'szClass') THEN DO
+            IF szClass == _class THEN DO
+                ok = WPToolsSetObjectData( _temps.i, 'OPEN=DEFAULT;')
+                LEAVE
+            END
+        END
+    END
+
+    IF ok == 0 THEN DO
+        IF SysCreateObject( _class, _class, globals.!tmpdir,,
+                            'OBJECTID=<TEMP_PRT>;TAKEDEFAULTS=NO;TEMPLATE=YES', 'R') THEN
+        DO
+            ok = SysSetObjectData '<TEMP_PRT>','OPEN=DEFAULT;'
+            CALL SysDestroyObject '<TEMP_PRT>'
+        END
+    END
+
+RETURN ok
+
+/*:VRX         PB_ABOUT_OK_Click
+*/
+PB_ABOUT_OK_Click:
+    CALL SW_ABOUT_Close
+RETURN
+
+/*:VRX         PB_ADDPORT_CANCEL_Click
+*/
+PB_ADDPORT_CANCEL_Click:
+    CALL SW_PORT_ADD_Close
+RETURN
+
+/*:VRX         PB_ADDPORT_OK_Click
+*/
+PB_ADDPORT_OK_Click: PROCEDURE EXPOSE globals. updated
+
+    ok = VRMethod('CN_ADDPORT', 'GetRecordList', 'Selected', 'recs.')
+    IF ok == 0 | recs.0 < 1 THEN RETURN
+    record = recs.1
+
+    _name = VRMethod('CN_ADDPORT', 'GetFieldData', record, 'NAME')
+    btns.0 = 2
+    btns.1 = NLSGetMessage( 14 )
+    btns.2 = NLSGetMessage( 15 )
+    ok = VRMessage('SW_PORT_ADD', NLSGetMessage( 205, _name ), NLSGetMessage( 200 ), 'Q', 'btns.', 1, 2 )
+    IF ok == 1 THEN DO
+        _portname = GetNextPortName( _name )
+        ok = RPUPortInstall( _name, _portname )
+        IF ok <> 1 THEN
+            CALL VRMessage 'SW_PORT_ADD', NLSGetMessage( 167 ) RPUERROR, NLSGetMessage( 13 ), 'E'
+        ELSE DO
+            CALL RPUPortDialog _name, _portname
+            CALL SW_PORT_ADD_Close
+            updated = 1
+        END
+    END
+
+RETURN ok
+
+/*:VRX         PB_DEVICE_ADD_Click
+*/
+PB_DEVICE_ADD_Click:
+    CALL DriverAdd
+RETURN
+
+/*:VRX         PB_DEVICE_REMOVE_Click
+*/
+PB_DEVICE_REMOVE_Click:
+    CALL DriverDelete
+RETURN
+
+/*:VRX         PB_IMPORTCANCEL_Click
+*/
+PB_IMPORTCANCEL_Click:
+    CALL SW_IMPORT_Close
+return
+
+/*:VRX         PB_IMPORTOK_Click
+*/
+PB_IMPORTOK_Click: PROCEDURE EXPOSE globals. new_ppd
+
+    IF VRGet('RB_IMPORTCUPS', 'Set') == 1 THEN DO
+        CALL New_CUPS new_ppd
+        CALL SW_IMPORT_Close
+        RETURN
+    END
+    driver = VRGet('DDCB_IMPORTDRV', 'Value')
+    ok = ImportPPD( driver, new_ppd )
+
+    SELECT
+        /* Check the return code from ImportPPD and display an appropriate message.
+         */
+
+        WHEN ok == 0 THEN DO            /* Success! */
+            _message = NLSGetMessage( 238 )
+            _mbtitle = NLSGetMessage( 16 )
+            _mbicon  = 'I'
+        END
+
+        /* Note: Error codes 1 & 2 are ignored here.
+         *       1 means the user cancelled, so no message is required.
+         *       For 2, ImportPPD itself already displayed the error message.
+         */
+
+        WHEN ok == 3 THEN DO            /* Invalid path specified */
+            _message = NLSGetMessage( 222 )
+            _mbtitle = NLSGetMessage( 13 )
+            _mbicon  = 'E'
+        END
+        WHEN ok == 4 THEN DO            /* Failed to copy driver files */
+            _message = NLSGetMessage( 220 )
+            _mbtitle = NLSGetMessage( 13 )
+            _mbicon  = 'E'
+        END
+        WHEN ok == 5 THEN DO            /* Failed to create directory */
+            _message = NLSGetMessage( 221 )
+            _mbtitle = NLSGetMessage( 13 )
+            _mbicon  = 'E'
+        END
+        WHEN ok == 6 THEN DO            /* PPD import failed */
+            _message = NLSGetMessage( 223 )
+            _mbtitle = NLSGetMessage( 13 )
+            _mbicon  = 'E'
+        END
+        WHEN ok == 7 THEN DO            /* Error updating PRDESC.LST */
+            _message = NLSGetMessage( 224, globals.!prdesc )
+            _mbtitle = NLSGetMessage( 13 )
+            _mbicon  = 'E'
+        END
+
+        OTHERWISE DO
+            _message = ''
+            _mbtitle = ''
+            _mbicon  = 'N'
+        END
+    END
+
+    IF message <> '' THEN
+        CALL VRMessage VRWindow(), _message, _mbtitle, _mbicon
+
+    CALL SW_IMPORT_Close
+RETURN
+
+/*:VRX         PB_MODELS_CLOSE_Click
+*/
+PB_MODELS_CLOSE_Click:
+    CALL SW_MODELS_Close
+return
+
+/*:VRX         PB_OTHERPORT_Click
+*/
+PB_OTHERPORT_Click: PROCEDURE EXPOSE globals.
+    _new_pdr = VRFileDialog('SW_PORT_ADD', NLSGetMessage( 165 ), 'O', '*.PDR')
+    IF _new_pdr == '' THEN RETURN 0
+
+    ok = InstallPortDriver( _new_pdr )
+    IF ok == 0 THEN DO
+        _name = VRParseFileName( _new_pdr, 'N')
+        _rec = VRMethod('CN_ADDPORT', 'AddRecord',,, _name, _new_pdr )
+        CALL VRMethod 'CN_ADDPORT', 'SetFieldData', _rec, 'NAME', _name, 'PATH', _new_pdr
+    END
+    ELSE
+        CALL VRMessage 'SW_PORT_ADD', NLSGetMessage( 166 ) || '0a0a'x || VRError(), NLSGetMessage( 13 ), 'E'
+RETURN ok
+
+/*:VRX         PB_PORT_ADD_Click
+*/
+PB_PORT_ADD_Click:
+    CALL PortAdd
+RETURN
+
+/*:VRX         PB_PORT_DELETE_Click
+*/
+PB_PORT_DELETE_Click:
+    CALL PortDelete
+return
+
+/*:VRX         PB_PPCLOSE_Click
+*/
+PB_PPCLOSE_Click:
+    CALL SW_PRINTERPAKS_Close
+return
+
+/*:VRX         PB_PPUPDATE_Click
+*/
+PB_PPUPDATE_Click: PROCEDURE EXPOSE globals.
+
+    /* Let the user select the driver .DRV to install.
+     */
+    new_drv = VRFileDialog( VRWindow(), NLSGetMessage( 182 ), 'O', '*.DRV')
+    IF new_drv == '' THEN RETURN 0
+
+    drv_stem   = TRANSLATE( VRParseFileName( new_drv, 'N'))
+    drv_name   = TRANSLATE( VRParseFileName( new_drv, 'NE'))
+    drv_source = TRANSLATE( VRParseFileName( new_drv, 'DP'))
+
+    /* See if this is the same as an existing driver (compared by filename).
+     */
+    existing = 0
+    skip_repo = 0
+    ok = VRMethod('CN_PRINTERPAKS', 'GetRecordList', 'All', 'recs.')
+    DO i = 1 TO recs.0
+        _ppname = VRMethod('CN_PRINTERPAKS', 'GetFieldData', recs.i, globals.!hcfPaks.!name )
+        IF TRANSLATE( _ppname ) == TRANSLATE( new_name ) THEN DO
+            existing = 1
+            _pppath = VRMethod('CN_PRINTERPAKS', 'GetFieldData', recs.i, globals.!hcfPaks.!path )
+            LEAVE
+        END
+    END
+
+    PARSE UPPER VALUE VRGetIni('PrinterManager', 'ThirdParty', 'USER') WITH known_3p '00'x .
+    IF known_3p == '' THEN
+        known_3p = 'ECUPS ECUPS-HP GUTENPRT PSPRINT'
+
+    IF existing THEN DO
+        drv_target = TRANSLATE( _pppath )
+        IF drv_source == drv_target ) THEN DO
+            CALL VRMessage VRWindow(), NLSGetMessage( 183 ), NLSGetMessage( 13 ), 'E'
+            RETURN 1
+        END
+        IF CheckWritablePath( drv_target ) <> 0 THEN DO
+            existing = 0
+            _msg.1 = NLSGetMessage( 185, drv_target )
+            _msg.2 = ''
+            _msg.3 = NLSGetMessage( 186, drv_name )
+            _msg.0 = 3
+            _btns.1 = NLSGetMessage( 2 )
+            _btns.2 = NLSGetMessage( 3 )
+            _btns.0 = 2
+            _select = VRMessageStem( VRWindow(), '_msg.', NLSGetMessage( 184 ),
+                                     'I', '_btns.', 1, 2 )
+            IF _select == 2 THEN skip_repo = 1
+        END
+    END
+
+    IF \skip_repo THEN DO
+        IF \existing THEN DO
+            /* If we already know about this driver, try and get its saved location. */
+            drv_target = ''
+            IF WORDPOS( drv_stem, known_3p ) > 0 THEN
+                PARSE UPPER VALUE VRGetIni('PM_INSTALL', drv_stem'_DIR', 'USER') WITH drv_target '00'x .
+            ELSE DO
+                known_3p = known_3p drv_stem
+                CALL VRSetIni 'PrinterManager', 'ThirdParty', known_3p || '00'x, 'USER'
+            END
+            IF drv_target == '' THEN DO
+                drv_target = globals.!repository'\'drv_target
+                _btns.1 = NLSGetMessage( 2 )
+                _btns.2 = NLSGetMessage( 3 )
+                _btns.3 = NLSGetMessage( 188 )
+                _btns.0 = 3
+                DO UNTIL _select <> 3
+                    _select = VRPrompt( VRWindow(), NLSGetMessage( 187, drv_name ),,
+                                        'drv_target', NLSGetMessage( 189 ), '_btns.', 1, 2 )
+                    IF _select == 3 THEN
+                        drv_target = VRXDirectoryDialog( VRWindow(), drv_target, NLSGetMessage( 189 ))
+                END
+                IF _select == 2 THEN
+                    skip_repo = 1
+                ELSE
+                    CALL VRSetIni 'PM_INSTALL', drv_stem'_DIR', TRANSLATE( drv_target ) || '00'x, 'USER'
+            END
+        END
+
+        IF \skip_repo THEN DO
+            IF VRFileExists( drv_target ) THEN DO
+                /* Clear any RHS attributes on existing files */
+                CALL SysFileTree drv_target'\*', '_ignore.',,, '**---'
+                CALL PRReplaceModule drv_target'\'drv_name, '', ''
+            END
+            ELSE
+                /* Create the target directory if necessary */
+                ok = VRMkDir( drv_target )
+
+            ok = CopyPrinterPak( new_drv, drv_target )
+            IF existing & ok == 1 THEN DO
+                CALL UpdatePrDesc new_drv, drv_target'\'new_drv
+            END
+            IF ok == 0 THEN DO
+                CALL VRMessage VRWindow(), NLSGetMessage( 220 ), NLSGetMessage( 13 ), 'E'
+                RETURN 2
+            END
+            ELSE
+                CALL VRMessage VRWindow(), NLSGetMessage( 193 ), NLSGetMessage( 16 ), 'I'
+        END
+    END
+
+    PARSE VALUE VRGetIni('PM_DEVICE_DRIVERS', drv_stem, 'USER') WITH drv_used '00'x .
+    IF ( drv_used <> '') & VRFileExists( drv_used ) THEN DO
+        /* Driver is currently installed; ask if the user wants to update the
+         * in-use copy as well.
+         */
+        _btns.1 = NLSGetMessage( 14 )
+        _btns.2 = NLSGetMessage( 15 )
+        _btns.0 = 2
+        _select = VRMessage( VRWindow(), NLSGetMessage( 190 ), NLSGetMessage( 191 ), 'Q', '_btns.', 1, 2 )
+        IF _select == 1 THEN DO
+            CALL PRSetFileAttr drv_used , 'rsh'
+            CALL PRReplaceModule drv_used, '', ''
+            used_target = VRParseFileName( drv_used, 'DP')
+            ok = CopyPrinterPak( new_drv, used_target )
+            IF ok == 0 THEN DO
+                CALL VRMessage VRWindow(), NLSGetMessage( 220 ), NLSGetMessage( 13 ), 'E'
+                RETURN 2
+            END
+            ELSE
+                CALL VRMessage VRWindow(), NLSGetMessage( 192 ), NLSGetMessage( 16 ), 'I'
+        END
+    END
+
+RETURN 0
+
+/*:VRX         PB_PRINTER_ADD_Click
+*/
+PB_PRINTER_ADD_Click:
+    CALL PrinterWizard
+RETURN
+
+/*:VRX         PB_PRINTER_DEL_Click
+*/
+PB_PRINTER_DEL_Click:
+    CALL PrinterDelete
+return
+
+/*:VRX         PB_PRINTER_OPEN_Click
+*/
+PB_PRINTER_OPEN_Click:
+    CALL PrinterOpen
+RETURN
+
+/*:VRX         PB_WIZARD_CANCEL_Click
+*/
+PB_WIZARD_CANCEL_Click:
+
+    CALL SW_WIZARD_Close
+
+return
+
+/*:VRX         PB_WIZARD_NEXT_Click
+*/
+PB_WIZARD_NEXT_Click: PROCEDURE EXPOSE globals.
+    SELECT
+        WHEN VRGet('RB_CREATE_CUPS', 'Set') == 1 THEN DO
+            globals.!create_mode = 'C'
+            CALL New_CUPS
+        END
+        WHEN ( VRGet('RB_CREATE_LEGACY', 'Set') == 1 ) & ( VRGet('RB_CREATE_STANDARD', 'Set') == 1 ) THEN DO
+            globals.!create_mode = 'S'
+            CALL New_Standard
+        END
+        WHEN ( VRGet('RB_CREATE_LEGACY', 'Set') == 1 ) & ( VRGet('RB_CREATE_LAN', 'Set') == 1 ) THEN DO
+            globals.!create_mode = 'L'
+            CALL New_LAN
+        END
+        OTHERWISE DO
+            globals.!create_mode = ''
+            globals.!wizard = 0
+        END
+    END
+    CALL SW_WIZARD_Fini
+
+RETURN
+
+/*:VRX         PortAdd
+*/
+PortAdd: PROCEDURE EXPOSE globals.
+
+    updated = 0
+    CALL VRLoadSecondary 'SW_PORT_ADD', 'W'
+    IF updated == 1 THEN
+        CALL RefreshPorts
+
+RETURN
+
+/*:VRX         PortDelete
+*/
+PortDelete: PARSE ARG record
+    IF record == '' THEN DO
+        ok = VRMethod( "CN_PORTS", "GetRecordList", "Selected", "recs." )
+        IF ok == 0 | recs.0 < 1 THEN RETURN
+        record = recs.1
+    END
+
+    _name = VRMethod('CN_PORTS', 'GetFieldData', record, globals.!hcfPorts.!name )
+    IF _name == '' THEN RETURN
+    _btns.0 = 2
+    _btns.1 = NLSGetMessage( 14 )
+    _btns.2 = NLSGetMessage( 15 )
+    _confirm = VRMessage('WN_MAIN', NLSGetMessage( 202, _name ), NLSGetMessage( 200 ), 'Q', '_btns.', 2, 2 )
+    IF _confirm == 1 THEN DO
+        success = RPUPortDelete( _name )
+        IF success == 1 THEN CALL RefreshPorts
+    END
+
+    CALL VRMethod 'CN_PRINTERS', 'SetRecordAttr', record, 'Source', 0
+
+RETURN
+
+/*:VRX         PortProperties
+*/
+PortProperties: PROCEDURE EXPOSE globals.
+    PARSE ARG record
+    IF record == '' THEN DO
+        ok = VRMethod( "CN_PORTS", "GetRecordList", "Selected", "recs." )
+        IF ok == 0 | recs.0 < 1 THEN RETURN
+        record = recs.1
+    END
+
+    _name   = VRMethod('CN_PORTS', 'GetFieldData', record, globals.!hcfPorts.!name )
+    _module = VRMethod('CN_PORTS', 'GetFieldData', record, globals.!hcfPorts.!driver )
+    IF _module == '' THEN DO
+        CALL VRMessage VRWindow(), NLSGetMessage( 211, _name ), NLSGetMessage( 210 ), 'N'
+        RETURN
+    END
+
+    CALL RPUPortDialog _module, _name
+
+    CALL VRMethod 'CN_PORTS', 'SetRecordAttr', record, 'Source', 0
+RETURN
+
+/*:VRX         PrinterDelete
+*/
+PrinterDelete: PROCEDURE EXPOSE globals.
+    PARSE ARG record
+    IF record == '' THEN DO
+        ok = VRMethod( "CN_PRINTERS", "GetRecordList", "Selected", "recs." )
+        IF ok == 0 | recs.0 < 1 THEN RETURN 0
+        record = recs.1
+    END
+
+    success = 0
+    _title = VRMethod('CN_PRINTERS', 'GetFieldData', record, globals.!hcfPrinters.!title )
+    _queue = VRMethod('CN_PRINTERS', 'GetFieldData', record, globals.!hcfPrinters.!queue )
+    _btns.0 = 2
+    _btns.1 = NLSGetMessage( 14 )
+    _btns.2 = NLSGetMessage( 15 )
+    _confirm = VRMessage('WN_MAIN', NLSGetMessage( 201, _title ), NLSGetMessage( 200 ), 'Q', '_btns.', 2, 2 )
+    IF _confirm == 1 THEN DO
+        success = RPUPrinterDelete( _queue )
+    END
+
+    CALL VRMethod 'CN_PRINTERS', 'SetRecordAttr', record, 'Source', 0
+RETURN success
+
+/*:VRX         PrinterHold
+*/
+PrinterHold: PROCEDURE EXPOSE globals.
+    PARSE ARG record
+    IF record == '' THEN DO
+        ok = VRMethod( "CN_PRINTERS", "GetRecordList", "Selected", "recs." )
+        IF ok == 0 | recs.0 < 1 THEN RETURN
+        record = recs.1
+    END
+    _queue = VRMethod('CN_PRINTERS', 'GetFieldData', record, globals.!hcfPrinters.!queue )
+    _flags = VRMethod('CN_PRINTERS', 'GetFieldData', record, globals.!hcfPrinters.!flags )
+    _p = POS('P', _flags )
+    IF _p > 0 THEN DO
+        ok = RPUQueueHold( _queue, 'N')
+        IF ok == 1 THEN DO
+            CALL VRSet 'MI_PRINTER_HOLD', 'Checked', 0
+            _flags = DELSTR( _flags, _p, 1 )
+            CALL VRMethod 'CN_PRINTERS', 'SetFieldData', record, globals.!hcfPrinters.!flags, _flags
+        END
+    END
+    ELSE DO
+        ok = RPUQueueHold( _queue, 'Y')
+        IF ok == 1 THEN DO
+            CALL VRSet 'MI_PRINTER_HOLD', 'Checked', 1
+            _flags = _flags'P'
+            CALL VRMethod 'CN_PRINTERS', 'SetFieldData', record, globals.!hcfPrinters.!flags, _flags
+        END
+    END
+
+    CALL VRMethod 'CN_PRINTERS', 'SetRecordAttr', record, 'Source', 0
+RETURN
+
+/*:VRX         PrinterOpen
+*/
+PrinterOpen: PROCEDURE EXPOSE globals.
+    PARSE ARG record
+    IF record == '' THEN DO
+        ok = VRMethod( "CN_PRINTERS", "GetRecordList", "Selected", "recs." )
+        IF ok == 0 | recs.0 < 1 THEN RETURN
+        record = recs.1
+    END
+
+    _queue = VRMethod('CN_PRINTERS', 'GetFieldData', record, globals.!hcfPrinters.!queue )
+    IF _queue <> '' THEN
+        CALL RPUOpenView _queue, 'O'
+
+    CALL VRMethod 'CN_PRINTERS', 'SetRecordAttr', record, 'Source', 0
+RETURN
+
+/*:VRX         PrinterProperties
+*/
+PrinterProperties: PROCEDURE EXPOSE globals.
+    PARSE ARG record
+    IF record == '' THEN DO
+        ok = VRMethod( "CN_PRINTERS", "GetRecordList", "Selected", "recs." )
+        IF ok == 0 | recs.0 < 1 THEN RETURN
+        record = recs.1
+    END
+
+    _queue = VRMethod('CN_PRINTERS', 'GetFieldData', record, globals.!hcfPrinters.!queue )
+    IF _queue <> '' THEN
+        CALL RPUOpenView _queue, 'S'
+
+    CALL VRMethod 'CN_PRINTERS', 'SetRecordAttr', record, 'Source', 0
+RETURN
+
+/*:VRX         PrinterSetDefault
+*/
+PrinterSetDefault: PROCEDURE EXPOSE globals.
+    PARSE ARG record
+    IF record == '' THEN DO
+        ok = VRMethod( "CN_PRINTERS", "GetRecordList", "Selected", "recs." )
+        IF ok == 0 | recs.0 < 1 THEN RETURN 0
+        record = recs.1
+    END
+    _queue = VRMethod('CN_PRINTERS', 'GetFieldData', record, globals.!hcfPrinters.!queue )
+    ok = RPUQueueDefault( _queue )
+/*
+    IF ok == 1 THEN DO
+        CALL VRSet 'MI_PRINTER_DEFAULT', 'Checked', 1
+        _flags = VRMethod('CN_PRINTERS', 'GetFieldData', record, globals.!hcfPrinters.!flags )
+        IF POS( _flags, 'D') == 0 THEN DO
+            _flags = 'D'_flags
+            CALL VRMethod 'CN_PRINTERS', 'SetFieldData', record, globals.!hcfPrinters.!flags, _flags
+        END
+    END
+*/
+    CALL VRMethod 'CN_PRINTERS', 'SetRecordAttr', record, 'Source', 0
+RETURN ok
+
+/*:VRX         PrinterWizard
+*/
+PrinterWizard: PROCEDURE EXPOSE globals.
+    CALL VRLoadSecondary 'SW_WIZARD', 'N'
+RETURN
+
+/*:VRX         Quit
+*/
+Quit:
+    window = VRWindow()
+    call VRSet window, "Shutdown", 1
+    drop window
+return
+
+/*:VRX         RB_ADVANCED_Click
+*/
+RB_ADVANCED_Click: PROCEDURE
+    CALL VRSet 'RB_CREATE_STANDARD', 'Enabled', 0
+    CALL VRSet 'RB_CREATE_LAN',      'Enabled', 0
+RETURN
+
+/*:VRX         RB_CREATE_CUPS_Click
+*/
+RB_CREATE_CUPS_Click: PROCEDURE
+    CALL VRSet 'RB_CREATE_STANDARD', 'Enabled', 0
+    CALL VRSet 'RB_CREATE_LAN',      'Enabled', 0
+RETURN
+
+/*:VRX         RB_CREATE_LEGACY_Click
+*/
+RB_CREATE_LEGACY_Click: PROCEDURE
+    CALL VRSet 'RB_CREATE_STANDARD', 'Enabled', 1
+    CALL VRSet 'RB_CREATE_LAN',      'Enabled', 1
+RETURN
+
+/*:VRX         RefreshDevices
+*/
+RefreshDevices: PROCEDURE EXPOSE globals.
+
+    ok = RPUEnumDrivers('drivers.')
+    IF rc <> 0 THEN DO
+        CALL VRSet 'CN_DEVICES', 'Painting', 0
+        CALL VRMethod 'CN_DEVICES', 'RemoveRecord', 'All'
+        DO i = 1 TO drivers.0
+            PARSE VAR drivers.i _pdrv'.'_model
+            IF _pdrv == 'IBMNULL' & _model == '' THEN
+                _model = NLSGetMessage( 106 )
+            ELSE IF _model == '' THEN
+                _model = '-'
+            PARSE VALUE VRGetIni('PM_DEVICE_DRIVERS', _pdrv, 'USER') WITH _drvspec '00'x .
+            driverinfo.i = ';'drivers.i';'_drvspec';;;'globals.!hcfDevices.!icon';'_drvspec';'globals.!hcfDevices.!model';'_model';'globals.!hcfDevices.!driver';'_pdrv
+        END
+        driverinfo.0 = drivers.0
+        ok = VRMethod( "CN_DEVICES", "AddRecordList",,, "driverinfo.")
+        DROP drivers.
+        DROP driverinfo.
+        CALL VRSet 'CN_DEVICES', 'Painting', 1
+    END
+
+RETURN
+
+/*:VRX         RefreshPorts
+*/
+RefreshPorts: PROCEDURE EXPOSE globals.
+
+    ok = RPUEnumPorts('ports.')
+    IF rc <> 0 THEN DO
+        CALL VRSet 'CN_PORTS', 'Painting', 0
+        CALL VRMethod 'CN_PORTS', 'RemoveRecord', 'All'
+        DO i = 1 TO ports.0
+            PARSE VAR ports.i _name _driver _path
+            SELECT
+                WHEN _name == 'FILE'       THEN _icon = '$24,PMWP'
+                WHEN _driver == 'USBPRT'   THEN _icon = '$7001,'_path
+                WHEN _driver == 'SERIAL'   THEN _icon = '$7001,'_path
+                WHEN _driver == 'PARALLEL' THEN _icon = '$7001,'_path
+                WHEN _driver == 'SLPR'     THEN _icon = '$7001,'_path
+                WHEN _driver == 'LPRPDRVR' THEN _icon = '$256,'_path
+/*
+                WHEN _driver == 'USBPRT'   THEN _icon = '$7'
+                WHEN _driver == 'SMB'      THEN _icon = '$6'
+                WHEN _driver == 'SLPR'     THEN _icon = '$6'
+                WHEN _driver == 'LPR32'    THEN _icon = '$6'
+                WHEN _driver == 'LPRPDRVR' THEN _icon = '$6'
+                WHEN _driver == 'CUPS'     THEN _icon = '$10'
+                OTHERWISE _icon = '$5'
+*/
+                OTHERWISE _icon = _path
+            END
+
+            portinfo.i = ';'_name';'_icon';;;'globals.!hcfPorts.!icon';'_icon';'globals.!hcfPorts.!name';'_name';'globals.!hcfPorts.!driver';'_driver';'
+        END
+        portinfo.0 = ports.0
+        ok = VRMethod( "CN_PORTS", "AddRecordList",,, "portinfo.")
+        DROP ports.
+        DROP portinfo.
+        CALL VRSet 'CN_PORTS', 'Painting', 1
+    END
+
+RETURN
+
+/*:VRX         RefreshPrinters
+*/
+RefreshPrinters: PROCEDURE EXPOSE globals.
+    ok = RPUEnumPrinters('printers.')
+    IF ok <> 0 THEN DO
+        CALL VRSet 'CN_PRINTERS', 'Painting', 0
+        CALL VRMethod 'CN_PRINTERS', 'RemoveRecord', 'All'
+
+        DO i = 1 TO printers.0
+            _title = TRANSLATE( printers.i.!description, '  ', '0d0a'x)
+            ok = RPUPrinterQuery( printers.i.!name, 'details.')
+            IF ok == 0 THEN DO
+                _driver = '?'
+                _port   = '?'
+            END
+            ELSE DO
+                PARSE VAR details.!drivers _driver ',' .
+                _port = details.!port
+            END
+            IF printers.i.!host <> '' THEN
+                _icon = '$65,PMWP'
+            ELSE IF _driver <> '?' THEN DO
+                PARSE VAR _driver _pdrv'.'_model
+                PARSE VALUE VRGetIni('PM_DEVICE_DRIVERS', _pdrv, 'USER') WITH _icon '00'x .
+            END
+            ELSE _icon = '$2'
+
+            printerinfo.i = ';'printers.i.!description';'_icon';;;' ||,
+                                globals.!hcfPrinters.!title';'_title';'              ||,
+                                globals.!hcfPrinters.!icon';'_icon';'                ||,
+                                globals.!hcfPrinters.!name';'printers.i.!name';'     ||,
+                                globals.!hcfPrinters.!queue';'printers.i.!queue';'   ||,
+                                globals.!hcfPrinters.!host';'printers.i.!host';'     ||,
+                                globals.!hcfPrinters.!port';'_port';'                ||,
+                                globals.!hcfPrinters.!driver';'_driver';'            ||,
+                                globals.!hcfPrinters.!flags';'printers.i.!flags';'   ||,
+                                globals.!hcfPrinters.!handle';'printers.i.!handle';'
+        END
+        printerinfo.0 = printers.0
+        ok = VRMethod( "CN_PRINTERS", "AddRecordList",,, "printerinfo.")
+        DROP printers.
+        DROP printerinfo.
+        DROP details.
+
+        CALL VRSet 'CN_PRINTERS', 'Painting', 1
+    END
+
+RETURN
+
+/*:VRX         SetLanguage
+*/
+SetLanguage: PROCEDURE EXPOSE globals.
+    PARSE ARG locale
+
+    /*
+     * This function locates the proper language files, and uses the message
+     * file to sets all UI text.  If the language could not be determined, we
+     * default to English.
+     */
+    execPath = VRGet('Application', 'Program')
+    execDir  = VRParseFileName( execPath, 'DP')
+
+    /*
+     * First, figure out what language/message file to use.
+     */
+    IF locale <> '' THEN
+        syslanguage = locale
+    ELSE
+        syslanguage = VALUE('LANG',,'OS2ENVIRONMENT')
+
+    SELECT
+        WHEN TRANSLATE( syslanguage ) == 'ZH_TW' THEN nlv = 'tw'
+        WHEN TRANSLATE( syslanguage ) == 'ZH_CN' THEN nlv = 'cx'
+        OTHERWISE                                PARSE VAR syslanguage nlv '_' .
+    END
+    nlvfile = globals.!nlsname || nlv
+    IF ( STREAM( execDir'\'nlvfile'.msg', 'C', 'QUERY EXISTS') \= '') | ( SysSearchPath('DPATH', nlvfile'.msg') \= '') THEN DO
+        globals.!messages = nlvfile'.msg'
+        helpfile          = nlvfile'.hlp'
+        CALL VRSet 'WN_MAIN', 'HelpFile', helpfile
+    END
+    ELSE DO
+        globals.!messages = globals.!nlsname || 'en.msg'
+        helpfile          = globals.!nlsname || 'en.hlp'
+        CALL VRSet 'WN_MAIN', 'HelpFile', helpfile
+    END
+
+    /*
+     * If the message file is missing or unreadable, display an error and then exit.
+     */
+    IF NLSGetMessage( 1 ) == '' THEN DO
+        CALL VRMessage VRWindow(), 'Language file' TRANSLATE( globals.!messages ) 'could not be loaded.', 'Cannot Continue', 'E'
+        RETURN 0
+    END
+
+    /*
+     * Now set the captions for the UI controls on the main window, according
+     * to the specified language.
+     */
+    CALL NLSSetText 'WN_MAIN', 'Caption', 1
+    CALL VRMethod 'TDL_MAIN', 'SetTabText', 1, NLSGetMessage( 100 )
+    CALL VRMethod 'TDL_MAIN', 'SetTabText', 2, NLSGetMessage( 101 )
+    CALL VRMethod 'TDL_MAIN', 'SetTabText', 3, NLSGetMessage( 102 )
+
+    CALL NLSSetText 'MN_PROGRAM', 'Caption', 20
+    CALL NLSSetText 'MI_MANAGE',  'Caption', 21
+    CALL NLSSetText 'MI_IMPORT',  'Caption', 22
+    CALL NLSSetText 'MI_QUIT',    'Caption', 29
+
+    CALL NLSSetText 'MN_PRINTER',         'Caption', 30
+    CALL NLSSetText 'MI_PRINTER_OPEN',    'Caption', 31
+    CALL NLSSetText 'MI_PRINTER_PROPS',   'Caption', 32
+    CALL NLSSetText 'MI_PRINTER_HOLD',    'Caption', 33
+    CALL NLSSetText 'MI_PRINTER_DEFAULT', 'Caption', 34
+    CALL NLSSetText 'MI_PRINTER_CREATE',  'Caption', 35
+    CALL NLSSetText 'MI_PRINTER_DELETE',  'Caption', 36
+
+    CALL NLSSetText 'MN_PORT',        'Caption', 40
+    CALL NLSSetText 'MI_PORT_CREATE', 'Caption', 41
+    CALL NLSSetText 'MI_PORT_DELETE', 'Caption', 42
+    CALL NLSSetText 'MI_PORT_PROPS',  'Caption', 43
+
+    CALL NLSSetText 'MN_DRIVERS',         'Caption', 50
+    CALL NLSSetText 'MI_DRIVERS_INSTALL', 'Caption', 51
+    CALL NLSSetText 'MI_DRIVERS_REMOVE',  'Caption', 52
+
+    CALL NLSSetText 'MN_VIEW',       'Caption', 60
+    CALL NLSSetText 'MI_DETAILVIEW', 'Caption', 61
+    CALL NLSSetText 'MI_ICONVIEW',   'Caption', 62
+    CALL NLSSetText 'MI_REFRESH',    'Caption', 63
+
+    CALL NLSSetText 'MN_PRINTERPAK',  'Caption', 70
+    CALL NLSSetText 'MI_PPAK_MODELS', 'Caption', 71
+    CALL NLSSetText 'MI_PPAK_COPY',   'Caption', 72
+
+    CALL NLSSetText 'MN_HELP',         'Caption', 80
+    CALL NLSSetText 'MI_HELP_GENERAL', 'Caption', 81
+    CALL NLSSetText 'MI_ABOUT',        'Caption', 89
+
+RETURN 1
+
+/*:VRX         SW_ABOUT_Close
+*/
+SW_ABOUT_Close:
+    call SW_ABOUT_Fini
+return
+
+/*:VRX         SW_ABOUT_Create
+*/
+SW_ABOUT_Create:
+    call SW_ABOUT_Init
+return
+
+/*:VRX         SW_ABOUT_Fini
+*/
+SW_ABOUT_Fini:
+    window = VRInfo( "Window" )
+    call VRDestroy window
+    drop window
+return
+/*:VRX         SW_ABOUT_Init
+*/
+SW_ABOUT_Init:
+
+    IF globals.!is_ecs == 1 THEN
+        _platform = 'eComStation'
+    ELSE
+        _platform = 'PM'
+
+    CALL NLSSetText 'SW_ABOUT',     'Caption', 130
+    CALL NLSSetText 'DT_PRODUCT',   'Caption', 131, _platform
+    CALL NLSSetText 'DT_VERSION',   'Caption', 132, globals.!version
+    CALL NLSSetText 'DT_COPYRIGHT', 'Caption', 133, globals.!copyright
+    CALL NLSSetText 'PB_ABOUT_OK',  'Caption', 2
+
+    PARSE VERSION _rexxver
+    PARSE VALUE VRVersion('VROBJ.DLL') WITH _vrver .
+    PARSE VALUE RPUVersion() WITH _rpuver .
+    PARSE VALUE VRXVersion() WITH _vrxver .
+    _pr1ver = PRVersion()
+    _wptver = WPToolsVersion()
+    _bullet = NLSGetMessage( 135 )
+    CALL VRSet 'MLE_LICENSES', 'Value', NLSGetMessage( 134, _rexxver ) || '0a'x ,
+                                        _bullet 'IBM REXXUTIL' SysUtilVersion() || '0a'x ,
+                                        _bullet 'VX-REXX VROBJ' _vrver || '0a'x ,
+                                        _bullet 'VX-REXX Extras (VROBJEX)' _vrxver || '0a'x ,
+                                        _bullet 'RXPRTUTL' _rpuver || '0a'x ,
+                                        _bullet 'WPTOOLS' _wptver || '0a'x ,
+                                        _bullet _pr1ver || '0a'x||' ----- '||'0a'x || ,
+                                        NLSGetMessage( 137 ) || '0a'x' ----- '||'0a'x || ,
+                                        NLSGetMessage( 138 )
+
+    window = VRInfo( "Object" )
+    if( \VRIsChildOf( window, "Notebook" ) ) then do
+        call VRMethod window, "CenterWindow"
+        call VRSet window, "Visible", 1
+        call VRMethod window, "Activate"
+    end
+    drop window
+return
+
+/*:VRX         SW_DEVICES_Close
+*/
+SW_DEVICES_Close:
+    call SW_DEVICES_Fini
+return
+
+/*:VRX         SW_DEVICES_Create
+*/
+SW_DEVICES_Create:
+    call SW_DEVICES_Init
+return
+
+/*:VRX         SW_DEVICES_Fini
+*/
+SW_DEVICES_Fini:
+    window = VRInfo( "Window" )
+    call VRDestroy window
+    drop window
+return
+/*:VRX         SW_DEVICES_Init
+*/
+SW_DEVICES_Init: PROCEDURE EXPOSE globals.
+
+    globals.!hcfDevices.!icon   = VRMethod( "CN_DEVICES", "AddField", "Icon",   "" )
+    globals.!hcfDevices.!model  = VRMethod( "CN_DEVICES", "AddField", "String", NLSGetMessage( 111 ))
+    globals.!hcfDevices.!driver = VRMethod( "CN_DEVICES", "AddField", "String", NLSGetMessage( 116 ))
+
+    CALL VRSet "CN_DEVICES", "DetailSort", globals.!hcfDevices.!model
+    ok = VRMethod( "CN_DEVICES", "SetFieldAttr", globals.!hcfDevices.!icon, "HorizSeparator", "0" )
+
+    CALL NLSSetText 'CN_DEVICES',       'Caption', 104
+    CALL NLSSetText 'PB_DEVICE_ADD',    'Caption', 8
+    CALL NLSSetText 'PB_DEVICE_REMOVE', 'Caption', 9
+
+    CALL RefreshDevices
+
+    window = VRInfo( "Object" )
+    if( \VRIsChildOf( window, "TabbedDialog" ) ) then do
+        call VRMethod window, "CenterWindow"
+        call VRSet window, "Visible", 1
+        call VRMethod window, "Activate"
+    end
+
+    CALL VRSet window, 'UserData', 'CN_DEVICES'
+    drop window
+/*
+    globals.!initstate = globals.!initstate + 1
+    IF globals.!initstate == 3 THEN CALL VRSet 'TM_REFRESH', 'Enabled', 1
+*/
+RETURN
+
+/*:VRX         SW_IMPORT_Close
+*/
+SW_IMPORT_Close:
+    call SW_IMPORT_Fini
+return
+
+/*:VRX         SW_IMPORT_Create
+*/
+SW_IMPORT_Create:
+    call SW_IMPORT_Init
+return
+
+/*:VRX         SW_IMPORT_Fini
+*/
+SW_IMPORT_Fini:
+    window = VRInfo( "Window" )
+    call VRDestroy window
+    drop window
+return
+/*:VRX         SW_IMPORT_Init
+*/
+SW_IMPORT_Init: PROCEDURE EXPOSE globals. new_ppd
+
+    CALL NLSSetText 'SW_IMPORT',       'Caption', 236
+    CALL NLSSetText 'DT_IMPORT',       'Caption', 233
+    CALL NLSSetText 'RB_IMPORTCUPS',   'Caption', 234
+    CALL NLSSetText 'RB_IMPORTLEGACY', 'Caption', 235
+    CALL NLSSetText 'PB_IMPORTOK',     'Caption', 2
+    CALL NLSSetText 'PB_IMPORTCANCEL', 'Caption', 3
+
+    _count = 0
+    IF ( DriverIsInstalled('PSCRIPT') <> '') | ( GetDriverSource('PSCRIPT') <> '') THEN DO
+        _count = _count + 1
+        psdrv._count = 'PSCRIPT'
+    END
+    IF ( DriverIsInstalled('PSCRIPT2') <> '') | ( GetDriverSource('PSCRIPT2') <> '') THEN DO
+        _count = _count + 1
+        psdrv._count = 'PSCRIPT2'
+    END
+    IF ( DriverIsInstalled('PSPRINT') <> '') | ( GetDriverSource('PSPRINT') <> '') THEN DO
+        _count = _count + 1
+        psdrv._count = 'PSPRINT'
+    END
+    IF ( DriverIsInstalled('PSPRINT2') <> '') | ( GetDriverSource('PSPRINT2') <> '') THEN DO
+        _count = _count + 1
+        psdrv._count = 'PSPRINT2'
+    END
+    IF ( DriverIsInstalled('ECUPS') <> '') | ( GetDriverSource('ECUPS') <> '') THEN DO
+        _count = _count + 1
+        psdrv._count = 'ECUPS'
+    END
+    IF ( DriverIsInstalled('ECUPS-HP') <> '') | ( GetDriverSource('ECUPS-HP') <> '') THEN DO
+        _count = _count + 1
+        psdrv._count = 'ECUPS-HP'
+    END
+    IF DriverIsInstalled('GUTENPRT') <> '' THEN DO
+        _count = _count + 1
+        psdrv._count = 'GUTENPRT'
+    END
+
+    IF _count < 1 THEN DO
+        IF globals.!hascups == 0 THEN DO
+            CALL VRMessage VRWindow(), NLSGetMessage( 237 ), NLSGetMessage( 13 ), 'E'
+            CALL SW_IMPORT_Close
+        END
+        CALL VRSet 'RB_IMPORTCUPS',   'Set',     1
+        CALL VRSet 'RB_IMPORTLEGACY', 'Enabled', 0
+        CALL VRSet 'DDCB_IMPORTDRV',  'Enabled', 0
+    END
+    ELSE IF \globals.!hascups THEN DO
+        CALL VRSet 'RB_IMPORTCUPS',   'Enabled', 0
+    END
+
+    psdrv.0 = _count
+    CALL VRMethod 'DDCB_IMPORTDRV', 'AddStringList', 'psdrv.'
+    CALL VRSet 'DDCB_IMPORTDRV', 'Selected', 1
+
+    window = VRInfo( "Object" )
+    if( \VRIsChildOf( window, "Notebook" ) ) then do
+        call VRMethod window, "CenterWindow"
+        call VRSet window, "Visible", 1
+        call VRMethod window, "Activate"
+    end
+    drop window
+RETURN
+
+/*:VRX         SW_MODELS_Close
+*/
+SW_MODELS_Close:
+    call SW_MODELS_Fini
+return
+
+/*:VRX         SW_MODELS_Create
+*/
+SW_MODELS_Create:
+    call SW_MODELS_Init
+return
+
+/*:VRX         SW_MODELS_Fini
+*/
+SW_MODELS_Fini:
+    window = VRInfo( "Window" )
+    call VRDestroy window
+    drop window
+return
+/*:VRX         SW_MODELS_Init
+*/
+SW_MODELS_Init: PROCEDURE EXPOSE globals.
+
+    ok = VRMethod( "CN_PRINTERPAKS", "GetRecordList", "Selected", "recs." )
+    IF ok == 0 | recs.0 < 1 THEN RETURN
+    record = recs.1
+
+    _name = VRMethod('CN_PRINTERPAKS', 'GetFieldData', record, globals.!hcfPaks.!name )
+    _path = VRMethod('CN_PRINTERPAKS', 'GetFieldData', record, globals.!hcfPaks.!path )
+    _ver  = VRMethod('CN_PRINTERPAKS', 'GetFieldData', record, globals.!hcfPaks.!version )
+    IF _ver == '-' THEN _ver = '??'
+    driver = _path'\'_name
+
+    CALL NLSSetText 'SW_MODELS', 'Caption', 194
+    CALL NLSSetText 'PB_MODELS_CLOSE', 'Caption', 12
+
+    CALL VRSet 'WN_MAIN', 'Pointer', 'WAIT'
+    ok = RPUEnumModels( driver, 'models.')
+    IF ok == 1 THEN
+        CALL VRMethod 'LB_MODELS', 'AddStringList', 'models.'
+    CALL VRSet 'WN_MAIN', 'Pointer', '<default>'
+
+    CALL NLSSetText 'DT_MODELS', 'Caption', 195, _name, models.0
+
+    window = VRInfo( "Object" )
+    if( \VRIsChildOf( window, "Notebook" ) ) then do
+        call VRMethod window, "CenterWindow"
+        call VRSet window, "Visible", 1
+        call VRMethod window, "Activate"
+    end
+    drop window
+
+RETURN
+
+/*:VRX         SW_PORT_ADD_Close
+*/
+SW_PORT_ADD_Close:
+    call SW_PORT_ADD_Fini
+return
+
+/*:VRX         SW_PORT_ADD_Create
+*/
+SW_PORT_ADD_Create:
+    call SW_PORT_ADD_Init
+return
+
+/*:VRX         SW_PORT_ADD_Fini
+*/
+SW_PORT_ADD_Fini:
+    window = VRInfo( "Window" )
+    call VRDestroy window
+    drop window
+return
+/*:VRX         SW_PORT_ADD_Init
+*/
+SW_PORT_ADD_Init: PROCEDURE EXPOSE globals. updated
+
+    fld_name = VRMethod('CN_ADDPORT', 'AddField', 'String',, 'NAME')
+    fld_path = VRMethod('CN_ADDPORT', 'AddField', 'String',, 'PATH')
+
+    CALL NLSSetText 'SW_PORT_ADD',  'Caption', 160
+    CALL NLSSetText 'DT_ADDPORT',   'Caption', 161
+    CALL NLSSetText 'CN_ADDPORT',   'Caption', 162
+    CALL NLSSetText 'DT_OTHERPORT', 'Caption', 163
+    CALL NLSSetText 'PB_OTHERPORT', 'Caption', 164
+
+    CALL NLSSetText 'PB_ADDPORT_OK',     'Caption', 2
+    CALL NLSSetText 'PB_ADDPORT_CANCEL', 'Caption', 3
+
+    IF GetPortDrivers() > 0 THEN DO
+        objects.0 = portdrivers.0
+        DO i = 1 TO portdrivers.0
+            PARSE VAR portdrivers.i _name _path
+            SELECT
+                WHEN _name == 'FILE'     THEN _icon = '$24,PMWP'
+                WHEN _name == 'USBPRT'   THEN _icon = '$7001,'_path
+                WHEN _name == 'SERIAL'   THEN _icon = '$7001,'_path
+                WHEN _name == 'PARALLEL' THEN _icon = '$7001,'_path
+                WHEN _name == 'SLPR'     THEN _icon = '$7001,'_path
+                WHEN _name == 'LPRPDRVR' THEN _icon = '$256,'_path
+                OTHERWISE _icon = _path
+            END
+            objects.i = ';'_name';'_icon';;;'fld_name';'_name';'fld_path';'_path
+        END
+        CALL VRMethod 'CN_ADDPORT', 'AddRecordList',,, 'objects.'
+    END
+
+    window = VRInfo( "Object" )
+    if( \VRIsChildOf( window, "Notebook" ) ) then do
+        call VRMethod window, "CenterWindow"
+        call VRSet window, "Visible", 1
+        call VRMethod window, "Activate"
+    end
+    drop window
+RETURN
+
+/*:VRX         SW_PORTS_Close
+*/
+SW_PORTS_Close:
+    call SW_PORTS_Fini
+return
+
+/*:VRX         SW_PORTS_Create
+*/
+SW_PORTS_Create:
+    call SW_PORTS_Init
+return
+
+/*:VRX         SW_PORTS_Fini
+*/
+SW_PORTS_Fini:
+    window = VRInfo( "Window" )
+    call VRDestroy window
+    drop window
+return
+/*:VRX         SW_PORTS_Init
+*/
+SW_PORTS_Init: PROCEDURE EXPOSE globals.
+
+    globals.!hcfPorts.!icon   = VRMethod( "CN_PORTS", "AddField", "Icon",   "" )
+    globals.!hcfPorts.!name   = VRMethod( "CN_PORTS", "AddField", "String", NLSGetMessage( 111 ))
+    globals.!hcfPorts.!driver = VRMethod( "CN_PORTS", "AddField", "String", NLSGetMessage( 119 ))
+
+    CALL VRSet "CN_PORTS", "DetailSort", globals.!hcfPorts.!name
+    ok = VRMethod( "CN_PORTS", "SetFieldAttr", globals.!hcfPorts.!icon, "HorizSeparator", "0" )
+
+    CALL NLSSetText 'CN_PORTS',       'Caption', 105
+    CALL NLSSetText 'PB_PORT_ADD',    'Caption', 5
+    CALL NLSSetText 'PB_PORT_DELETE', 'Caption', 6
+
+    CALL RefreshPorts
+
+    window = VRInfo( "Object" )
+    if( \VRIsChildOf( window, "TabbedDialog" ) ) then do
+        call VRMethod window, "CenterWindow"
+        call VRSet window, "Visible", 1
+        call VRMethod window, "Activate"
+    end
+
+    CALL VRSet window, 'UserData', 'CN_PORTS'
+    drop window
+/*
+    globals.!initstate = globals.!initstate + 1
+    IF globals.!initstate == 3 THEN CALL VRSet 'TM_REFRESH', 'Enabled', 1
+*/
+RETURN
+
+/*:VRX         SW_PRINTERPAKS_Close
+*/
+SW_PRINTERPAKS_Close:
+    call SW_PRINTERPAKS_Fini
+return
+
+/*:VRX         SW_PRINTERPAKS_Create
+*/
+SW_PRINTERPAKS_Create:
+    call SW_PRINTERPAKS_Init
+return
+
+/*:VRX         SW_PRINTERPAKS_Fini
+*/
+SW_PRINTERPAKS_Fini:
+    window = VRInfo( "Window" )
+    call VRDestroy window
+    drop window
+return
+/*:VRX         SW_PRINTERPAKS_Init
+*/
+SW_PRINTERPAKS_Init: PROCEDURE EXPOSE globals.
+
+    globals.!hcfPaks.!icon   = VRMethod( "CN_PRINTERPAKS", "AddField", "Icon",   "" )
+    globals.!hcfPaks.!name   = VRMethod( "CN_PRINTERPAKS", "AddField", "String", NLSGetMessage( 173 ))
+    globals.!hcfPaks.!version= VRMethod( "CN_PRINTERPAKS", "AddField", "String", NLSGetMessage( 181 ))
+    globals.!hcfPaks.!status = VRMethod( "CN_PRINTERPAKS", "AddField", "String", NLSGetMessage( 176 ))
+    globals.!hcfPaks.!path   = VRMethod( "CN_PRINTERPAKS", "AddField", "String", NLSGetMessage( 175 ))
+    globals.!hcfPaks.!desc   = VRMethod( "CN_PRINTERPAKS", "AddField", "String", NLSGetMessage( 174 ))
+    globals.!hcfPaks.!flags  = VRMethod( "CN_PRINTERPAKS", "AddField", "String", 'FLAGS')
+
+    CALL VRSet "CN_PRINTERPAKS", "DetailSort", globals.!hcfPaks.!name
+    ok = VRMethod( "CN_PRINTERPAKS", "SetFieldAttr", globals.!hcfPaks.!icon,  "HorizSeparator", "0" )
+    ok = VRMethod( "CN_PRINTERPAKS", "SetFieldAttr", globals.!hcfPaks.!flags, "Visible", "0" )
+
+    CALL NLSSetText 'SW_PRINTERPAKS', 'Caption', 170
+    CALL NLSSetText 'DT_PRINTERPAKS', 'Caption', 171
+    CALL NLSSetText 'PB_PPUPDATE',    'Caption', 179
+    CALL NLSSetText 'PB_PPCLOSE',     'Caption', 12
+
+    CALL GetPrinterPaks
+
+    window = VRInfo( "Object" )
+    if( \VRIsChildOf( window, "TabbedDialog" ) ) then do
+        call VRMethod window, "CenterWindow"
+        call VRSet window, "Visible", 1
+        call VRMethod window, "Activate"
+    end
+    drop window
+return
+
+/*:VRX         SW_PRINTERS_Close
+*/
+SW_PRINTERS_Close:
+    call SW_PRINTERS_Fini
+return
+
+/*:VRX         SW_PRINTERS_Create
+*/
+SW_PRINTERS_Create:
+    call SW_PRINTERS_Init
+return
+
+/*:VRX         SW_PRINTERS_Fini
+*/
+SW_PRINTERS_Fini:
+    window = VRInfo( "Window" )
+    call VRDestroy window
+    drop window
+return
+/*:VRX         SW_PRINTERS_Init
+*/
+SW_PRINTERS_Init: PROCEDURE EXPOSE globals.
+
+    CALL NLSSetText 'CN_PRINTERS',     'Caption', 103
+    CALL NLSSetText 'PB_PRINTER_ADD',  'Caption', 5
+    CALL NLSSetText 'PB_PRINTER_DEL',  'Caption', 6
+    CALL NLSSetText 'PB_PRINTER_OPEN', 'Caption', 7
+
+    globals.!hcfPrinters.!icon   = VRMethod( "CN_PRINTERS", "AddField", "Icon", "" )
+    globals.!hcfPrinters.!title  = VRMethod( "CN_PRINTERS", "AddField", "String", NLSGetMessage( 110 ))
+    globals.!hcfPrinters.!name   = VRMethod( "CN_PRINTERS", "AddField", "String", NLSGetMessage( 112 ))
+    globals.!hcfPrinters.!queue  = VRMethod( "CN_PRINTERS", "AddField", "String", NLSGetMessage( 113 ))
+    globals.!hcfPrinters.!host   = VRMethod( "CN_PRINTERS", "AddField", "String", NLSGetMessage( 115 ))
+    globals.!hcfPrinters.!driver = VRMethod( "CN_PRINTERS", "AddField", "String", NLSGetMessage( 116 ))
+    globals.!hcfPrinters.!port   = VRMethod( "CN_PRINTERS", "AddField", "String", NLSGetMessage( 117 ))
+    globals.!hcfPrinters.!flags  = VRMethod( "CN_PRINTERS", "AddField", "String", NLSGetMessage( 118 ))
+    globals.!hcfPrinters.!handle = VRMethod( "CN_PRINTERS", "AddField", "String", "HANDLE" )
+
+    CALL VRSet 'CN_PRINTERS', 'DetailSort', globals.!hcfPrinters.!title
+    CALL VRSet 'CN_PRINTERS', 'LastSplitField', globals.!hcfPrinters.!host
+    CALL VRSet 'CN_PRINTERS', 'SplitBarLeft', 3000
+
+    ok = VRMethod( "CN_PRINTERS", "SetFieldAttr", globals.!hcfPrinters.!icon, "HorizSeparator", "0" )
+    ok = VRMethod( "CN_PRINTERS", "SetFieldAttr", globals.!hcfPrinters.!handle, "Visible", "0" )
+/*    ok = VRMethod( "CN_PRINTERS", "SetFieldAttr", globals.!hcfPrinters.!flags,  "Visible", "0" ) */
+
+    CALL RefreshPrinters
+
+    window = VRInfo( "Object" )
+    if( \VRIsChildOf( window, "TabbedDialog" ) ) then do
+        call VRMethod window, "CenterWindow"
+        call VRSet window, "Visible", 1
+        call VRMethod window, "Activate"
+    end
+
+    CALL VRSet window, 'UserData', 'CN_PRINTERS'
+    drop window
+/*
+    globals.!initstate = globals.!initstate + 1
+    IF globals.!initstate == 3 THEN CALL VRSet 'TM_REFRESH', 'Enabled', 1
+*/
+
+RETURN
+
+/*:VRX         SW_PRINTERS_Resize
+*/
+SW_PRINTERS_Resize:
+
+return
+
+/*:VRX         SW_WIZARD_Close
+*/
+SW_WIZARD_Close:
+    call SW_WIZARD_Fini
+return
+
+/*:VRX         SW_WIZARD_Create
+*/
+SW_WIZARD_Create:
+    call SW_WIZARD_Init
+return
+
+/*:VRX         SW_WIZARD_Fini
+*/
+SW_WIZARD_Fini:
+    window = VRInfo( "Window" )
+    call VRDestroy window
+    drop window
+
+    IF globals.!wizard THEN CALL Quit
+    ELSE DO
+        call VRSet 'WN_MAIN', "Visible", 1
+        IF globals.!create_mode == '' THEN
+            call VRMethod 'WN_MAIN', "Activate"
+    END
+RETURN
+/*:VRX         SW_WIZARD_Init
+*/
+SW_WIZARD_Init:
+
+    CALL NLSSetText 'SW_WIZARD',          'Caption', 140
+    IF globals.!wizard THEN
+        CALL NLSSetText 'DT_WIZARD',      'Caption', 142
+    ELSE
+        CALL NLSSetText 'DT_WIZARD',      'Caption', 141
+    CALL NLSSetText 'RB_CREATE_CUPS',     'Caption', 143
+    CALL NLSSetText 'RB_CREATE_LEGACY',   'Caption', 144
+    CALL NLSSetText 'RB_CREATE_STANDARD', 'Caption', 145
+    CALL NLSSetText 'RB_CREATE_LAN',      'Caption', 146
+    CALL NLSSetText 'RB_ADVANCED',        'Caption', 147
+    CALL NLSSetText 'PB_WIZARD_NEXT',     'Caption', 11
+    CALL NLSSetText 'PB_WIZARD_CANCEL',   'Caption', 3
+    CALL NLSSetText 'PB_WIZARD_HELP',     'Caption', 4
+
+    IF globals.!wizard THEN CALL VRSet 'RB_ADVANCED', 'Visible', 1
+    window = VRInfo( "Object" )
+    if( \VRIsChildOf( window, "Notebook" ) ) then do
+        call VRMethod window, "CenterWindow"
+        call VRSet window, "Visible", 1
+        call VRMethod window, "Activate"
+    end
+    drop window
+
+    globals.!create_mode = ''
+
+RETURN
+
+/*:VRX         TDL_MAIN_PageSelected
+*/
+TDL_MAIN_PageSelected: PROCEDURE EXPOSE globals.
+    _pageidx = VRInfo("Page")
+    _pagewin = VRMethod( "TDL_MAIN", "GetPageWindow", _pageidx )
+    _cnr = VRGet( _pagewin, "UserData")
+    IF _cnr == '' THEN RETURN
+
+    _view = VRGet( _cnr, "View")
+    IF _view == 'Detail' THEN DO
+        CALL VRSet 'MI_ICONVIEW',   'Checked', 0
+        CALL VRSet 'MI_DETAILVIEW', 'Checked', 1
+    END
+    ELSE DO
+        CALL VRSet 'MI_ICONVIEW',   'Checked', 1
+        CALL VRSet 'MI_DETAILVIEW', 'Checked', 0
+    END
+
+    SELECT
+        WHEN _cnr == 'CN_PRINTERS' THEN DO
+        END
+        WHEN _cnr == 'CN_PORTS' THEN DO
+        END
+        WHEN _cnr == 'CN_DEVICES' THEN DO
+        END
+        OTHERWISE DO
+        END
+    END
+
+RETURN
+
+/*:VRX         TM_REFRESH_Trigger
+*/
+TM_REFRESH_Trigger: PROCEDURE EXPOSE globals.
+    CALL RefreshPrinters
+    CALL RefreshPorts
+    CALL RefreshDevices
+RETURN
+
+/*:VRX         WN_MAIN_Close
+*/
+WN_MAIN_Close:
+    call Quit
+return
+
+/*:VRX         xxUpdatePrDesc
+*/
+xxUpdatePrDesc: PROCEDURE EXPOSE globals.
+    ARG driver, fqn
+
+    IF globals.!prdesc == '' THEN RETURN 1
+
+    ok = RPUEnumModels( fqn, 'newdevs.')
+    IF ok == 0 THEN RETURN 2
+
+    _count = 0
+    CALL LINEIN globals.!prdesc, 1, 0
+    DO WHILE LINES( globals.!prdesc )
+        _next = LINEIN( globals.!prdesc )
+        PARSE UPPER VAR _next WITH . ':' . '('_prdrv')' .
+        IF _prdrv == driver THEN ITERATE
+        _count = _count + 1
+        prdefs.count = _next
+    END
+    CALL STREAM prdesc, 'C', 'CLOSE'
+
+    DO i = 1 TO devs.0
+        _count = _count + 1
+        prdefs._count = newdevs.i':' newdevs.i '('driver')'
+    END
+    prdefs.0 = count
+
+    CALL VRSortStem 'prdefs.'
+
+    _prdir = VRParseFileName( globals.!prdesc, 'DP')
+    CALL VRCopyFile globals.!prdesc, _prdir'\PRDESC.BAK'
+    CALL VRDeleteFile globals.!prdesc
+    DO i = 1 TO prdefs.0
+        CALL LINEOUT globals.!prdesc, prdefs.i
+    END
+    CALL LINEOUT globals.!prdesc
+
+RETURN 0
+
Index: trunk/gui/printer/manager/printm_en.txt
===================================================================
--- trunk/gui/printer/manager/printm_en.txt	(revision 33)
+++ trunk/gui/printer/manager/printm_en.txt	(revision 33)
@@ -0,0 +1,254 @@
+; Message file for Printer Manager
+; English version
+PTM
+; ------- [1-19]: Common strings used throughout the program
+PTM0001I: Manage Printers
+PTM0002I: OK
+PTM0003I: Cancel
+PTM0004I: Help
+PTM0005I: ~New
+PTM0006I: ~Delete
+PTM0007I: ~Open
+PTM0008I: ~Install
+PTM0009I: ~Remove
+PTM0010I: ~Properties
+PTM0011I: Next ~>
+PTM0012I: ~Close
+PTM0013I: Error
+PTM0014I: Yes
+PTM0015I: No
+PTM0016I: Operation Successful
+PTM0017I: Continue
+PTM0018?:
+PTM0019?:
+; ------- [20-99]: Menus
+; - (Some of these are duplicated so that they can use different shortcut keys)
+PTM0020I: ~File
+PTM0021I: ~Manage presentation drivers...
+PTM0022I: ~Import PPD...
+PTM0023?:
+PTM0024?:
+PTM0025?:
+PTM0026?:
+PTM0027?:
+PTM0028?:
+PTM0029I: E~xit
+PTM0030I: ~Printer
+PTM0031I: ~Open
+PTM0032I: ~Properties...
+PTM0033I: Pause ~queue
+PTM0034I: ~Default printer
+PTM0035I: ~Create new
+PTM0036I: Dele~te
+PTM0037?:
+PTM0038?:
+PTM0039?:
+PTM0040I: P~ort
+PTM0041I: ~Add new
+PTM0042I: ~Delete
+PTM0043I: ~Properties...
+PTM0044?:
+PTM0045?:
+PTM0046?:
+PTM0047?:
+PTM0048?:
+PTM0049?:
+PTM0050I: ~Driver
+PTM0051I: ~Install
+PTM0052I: ~Remove
+PTM0053?:
+PTM0054?:
+PTM0055?:
+PTM0056?:
+PTM0057?:
+PTM0058?:
+PTM0059?:
+PTM0060I: ~View
+PTM0061I: ~Details
+PTM0062I: ~Icon
+PTM0063I: ~Refresh
+PTM0064?:
+PTM0065?:
+PTM0066?:
+PTM0067?:
+PTM0068?:
+PTM0069?:
+PTM0070I: P~rinterPak
+PTM0071I: ~Supported devices...
+PTM0072I: ~Copy path
+PTM0073?:
+PTM0074?:
+PTM0075?:
+PTM0076?:
+PTM0077?:
+PTM0078?:
+PTM0079?:
+PTM0080I: ~Help
+PTM0081I: General help
+PTM0082?:
+PTM0083?:
+PTM0084?:
+PTM0085?:
+PTM0086?:
+PTM0087?:
+PTM0088?:
+PTM0089I: ~Product information
+PTM0090?:
+PTM0091?:
+PTM0092?:
+PTM0093?:
+PTM0094?:
+PTM0095?:
+PTM0096?:
+PTM0097?:
+PTM0098?:
+PTM0099?:
+; ------- [100-109]: Text on the main notebook pages
+PTM0100I: Printers
+PTM0101I: Drivers
+PTM0102I: Ports
+PTM0103I: Installed Printers
+PTM0104I: Installed Printer Drivers
+PTM0105I: Installed Ports
+PTM0106I: (Passthrough Driver)
+PTM0107?:
+PTM0108?:
+PTM0109?:
+; Container column titles
+PTM0110I: Title
+PTM0111I: Name
+PTM0112I: Real Name
+PTM0113I: PM Queue Name
+PTM0114I: CUPS Queue Name
+PTM0115I: Remote Host
+PTM0116I: Driver
+PTM0117I: Port
+PTM0118I: Flags
+PTM0119I: Port Driver
+PTM0120?:
+PTM0121?:
+PTM0122?:
+PTM0123?:
+PTM0124?:
+PTM0125?:
+PTM0126?:
+PTM0127?:
+PTM0128?:
+PTM0129?:
+; ------- Text on the Product Information dialog
+PTM0130I: Product Information
+PTM0131I: %1 Printer Manager
+PTM0132I: Version %1
+PTM0133I: (C) %1 Alexander Taylor. All rights reserved.
+PTM0134I: Using %1 with:
+; 135 is a bullet character - use something language- and codepage-appropriate
+PTM0135I: 
+PTM0136I: (by %1)
+PTM0137I: Includes graphics based on the Tango icon set by Rodney Dawes et al, licensed under the Creative Commons Attribution-ShareAlike License: http://creativecommons.org/licenses/by-sa/2.5/
+PTM0138I: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+PTM0139?:
+; ------- Printer creation wizard
+PTM0140I: Install Printer
+PTM0141I: Select the type of printer you wish to install.
+PTM0142I: Select the action you wish to perform.
+PTM0143I: Install a local or network printer (CUPS-based)
+PTM0144I: Install a printer using legacy drivers:
+PTM0145I: Standard printer
+PTM0146I: IBM Peer or LAN Server printer
+PTM0147I: Advanced printer management
+PTM0148?:
+PTM0149?:
+PTM0150?:
+PTM0151?:
+PTM0152?:
+PTM0153?:
+PTM0154?:
+PTM0155?:
+PTM0156?:
+PTM0157?:
+PTM0158?:
+PTM0159?:
+; ------- Port creation dialog
+PTM0160I: Add New Port
+PTM0161I: Select the type of port to add.
+PTM0162I: Installed Port Drivers
+PTM0163I: To install a type of port which is not shown here, choose "Other" and then select the appropriate port driver file.
+PTM0164I: Other...
+PTM0165I: Select Port Driver
+PTM0166I: Failed to install port driver.
+PTM0167I: Failed to create port:
+PTM0168?:
+PTM0169?:
+; ------- PrinterPak management dialog
+PTM0170I: Manage Presentation Drivers
+PTM0171I: The following printer presentation drivers (PrinterPaks) are available:
+PTM0172I: Local repository path:  %1
+PTM0173I: Name
+PTM0174I: Comment
+PTM0175I: Installable From
+PTM0176I: Status
+PTM0177I: Included with %1
+PTM0178I: Third-party driver
+PTM0179I: ~Add/Update...
+PTM0180I: (installed)
+PTM0181I: Version
+PTM0182I: Select PrinterPak Driver
+PTM0183I: The source and target directories are the same.
+PTM0184I: Local Repository Not Accessible
+PTM0185I: The system-defined driver path (%1) is either unavailable or non-writable.  (The system may be configured to install shipped drivers from CD.)
+PTM0186I: If you want to make this updated driver available for future printer installations, %1 needs to be treated as a third-party driver.  This means that it will be copied to a new local directory, and you will need to manually select it (using the 'other' option) when installing a new printer model.  If this is acceptable, select 'OK' to continue.
+PTM0187I: Please confirm the directory where %1 and its associated files will be copied.
+PTM0188I: ~Browse...
+PTM0189I: Select Directory
+PTM0190I: Do you want to update the copy of this driver which is currently in-use by existing printers?  (This may require a system reboot to take effect.)
+PTM0191I: Update Existing Printers
+PTM0192I: The driver has been updated.  You may need to shut down and reboot for the change to take effect.
+PTM0193I: The driver was added successfully.
+PTM0194I: Supported Models
+PTM0195I: Supported devices in %1 (%2 total):
+PTM0196?:
+PTM0197?:
+PTM0198?:
+PTM0199?:
+; User messages
+PTM0200I: Please Confirm
+PTM0201I: Delete printer "%1"?
+PTM0202I: Delete port %1?
+PTM0203I: Delete driver "%1"?
+PTM0204?:
+PTM0205I: Add a new port of type %1?
+PTM0206?:
+PTM0207?:
+PTM0208?:
+PTM0209?:
+PTM0210I: No Properties
+PTM0211I: There are no properties available for the port %1.
+PTM0212?:
+PTM0213?:
+PTM0214?:
+PTM0215?:
+PTM0216?:
+PTM0217?:
+PTM0218?:
+PTM0219?:
+PTM0220I: An error occurred while copying files.
+PTM0221I: An error occurred when attempting to create a directory.
+PTM0222I: An invalid path was specified.
+PTM0223I: An error occurred while importing the PPD file.
+PTM0224I: An error occurred while trying to update %1.
+PTM0225?:
+PTM0226?:
+PTM0227?:
+PTM0228?:
+PTM0229?:
+PTM0230I: Select PPD File
+PTM0231I: The %1 driver or one of its required files could not be located.
+PTM0232I: The install files for the %1 driver could not be located.  These files will be recreated from the driver files which are already installed on your system.
+PTM0233I: Please indicate how this PPD will be used.
+PTM0234I: Install or update a CUPS-based printer.
+PTM0235I: Add support to a legacy PostScript driver.
+PTM0236I: Import PostScript Printer Description
+PTM0237I: You cannot import a PPD file unless you have either CUPS or at least one legacy PostScript driver installed.
+PTM0238I: The PPD has been imported.
+PTM0239?:
+
Index: trunk/gui/shared/PrManUtl.VRS
===================================================================
--- trunk/gui/shared/PrManUtl.VRS	(revision 33)
+++ trunk/gui/shared/PrManUtl.VRS	(revision 33)
@@ -0,0 +1,808 @@
+/*:VRX         DriverIsInstalled
+*/
+/* Checks if a given print driver (without extension) is installed, and if so
+ * returns the path to the active files.  Returns '' if the driver is not
+ * installed.
+ */
+DriverIsInstalled: PROCEDURE
+    ARG driver
+    PARSE VALUE VRGetIni('PM_DEVICE_DRIVERS', driver, 'USER') WITH drv_path '00'x .
+    IF ( drv_path <> '') THEN
+        drv_path = STREAM( drv_path, 'C', 'QUERY EXISTS')
+RETURN drv_path
+
+
+/*:VRX         GetDriverSource
+*/
+/* Figure out where to look for the PrinterPak driver files used as the install
+ * source.  Preference is given to the local repository (PDR_DIR); if it's not
+ * there, we look in a couple of other places where it might have ended up.
+ * Note that we don't look for the actual installed driver files under \OS2\DLL;
+ * that logic is handled in LocateDriverFiles(), which calls this routine.
+ *
+ * Various global values are assumed to be set already:
+ * - globals.!prdrv:      filespec of \OS2\INSTALL\PRDRV.LST
+ * - globals.!repository: value indicated by PM_INSTALL->PDR_DIR in OS2.INI
+ *
+ * Returns the path, or '' if not found.  Also, 'pmdx' will be 0-9 if the
+ * driver is in the repository (indicating the repository subdirectory), or
+ * '' if the driver is not in the repository.
+ */
+GetDriverSource: PROCEDURE EXPOSE globals. pmdx
+    ARG driver
+    IF driver == '' THEN RETURN ''
+
+    drv_file = ''
+    IF globals.!repository <> '' THEN DO
+
+        /* See if the driver is defined in the local repository.  (This is the
+         * directory where installable printer drivers are kept.  OS/2 gets them
+         * from here when you select 'Printer driver included with OS/2'.)
+         */
+        pmdx = GetDriverPMDD( driver, globals.!prdrv )
+        IF pmdx == '' THEN DO
+            /* Hmm, the driver isn't listed in PRDRV.LST.  Let's check to see if
+             * it's in the default repository location anyway.
+             */
+            IF WORDPOS( driver, 'ECUPS ECUPS-HP PSPRINT PSPRINT2') > 0 THEN
+                pmdx = '9'
+            ELSE
+                pmdx = '0'
+            drv_file = STREAM( globals.!repository'\PMDD_'pmdx'\'driver'.DRV', 'C', 'QUERY EXISTS')
+            IF drv_file <> '' THEN DO
+                /* We found the driver in the repository, even though it isn't
+                 * defined as such.  So let's add the proper definition to
+                 * PRDRV.LST now.
+                 */
+                CALL LINEOUT globals.!prdrv, LEFT( driver'.DRV', 14 ) pmdx ||,
+                             '  (added automatically)'
+                CALL LINEOUT globals.!prdrv
+            END
+            ELSE
+                pmdx = ''
+        END
+        ELSE DO
+            /* The driver is listed; now make sure it's actually there.
+             */
+            drv_file = STREAM( globals.!repository'\PMDD_'pmdx'\'driver'.DRV', 'C', 'QUERY EXISTS')
+        END
+    END
+
+    IF drv_file == '' THEN DO
+        CALL LINEOUT globals.!log1, 'Driver' driver 'is not in the local repository.'
+        /* If the driver really isn't in the repository, there are a couple of
+         * other places that various install utilities might have put it...
+         */
+        PARSE VALUE VRGetIni('PM_INSTALL', driver'_DIR', 'USER') WITH drvr_dir '00'x .
+        IF drvr_dir == '' THEN
+            PARSE VALUE VRGetIni('InstPDR', 'PATH_TO_'driver, 'USER') WITH drvr_dir '00'x .
+        IF drvr_dir <> '' THEN DO
+            drv_file = drvr_dir'\'driver'.DRV'
+            CALL LINEOUT globals.!log1, 'Found driver in' drvr_dir'.'
+        END
+    END
+
+RETURN drv_file
+
+
+/*:VRX         GetDriverPMDD
+*/
+/* Check to see which repository directory the specified driver resides in.
+ * Returns the number suffix of the PMDD_* subdirectory name, or '' if either
+ * the driver or the index file could not be located.
+ */
+GetDriverPMDD: PROCEDURE
+    PARSE ARG driver, prdrv_lst
+
+    IF prdrv_lst <> '' THEN DO
+        CALL LINEIN prdrv_lst, 1, 0
+        DO WHILE LINES( prdrv_lst ) > 0
+            PARSE VALUE LINEIN( prdrv_lst ) WITH (driver)'.DRV' pmdx .
+            IF pmdx <> '' THEN LEAVE
+        END
+        CALL STREAM prdrv_lst, 'C', 'CLOSE'
+    END
+    ELSE pmdx = ''
+
+RETURN pmdx
+
+
+/*:VRX         LocateDriverFiles
+*/
+/* Returns:
+ *   0 - Driver files not found.
+ *   1 - Driver files found, path saved in 'driver_path'; 'driver_repo' will be 1
+ *       if the driver is 'shipped' (i.e. defined in PRDRV.LST) or 0 otherwise.
+ *   2 - Only found installed driver files in (\OS2\DLL\xxx, saved in 'driver_path');
+ *       will need to copy them somewhere for future installs.
+ */
+LocateDriverFiles: PROCEDURE EXPOSE globals. driver_path driver_repo
+    ARG driver
+    IF driver == '' THEN driver = 'PSCRIPT'
+
+    CALL LINEOUT globals.!log1, 'Looking for' driver 'files'
+
+    mustcopy = 0
+    driver_path = GetDriverSource( driver )
+
+    IF driver_path == '' THEN DO
+        /* No source found.  We'll have to try copying the actual installed
+         * driver files from under \OS2\DLL.
+         */
+        CALL LINEOUT globals.!log1, 'Driver source not found.  Trying installed driver.'
+        PARSE VALUE VRGetIni('PM_DEVICE_DRIVERS', driver, 'USER') WITH drv_used '00'x .
+        IF ( drv_used <> '') & VRFileExists( drv_used ) THEN
+            driver_path = drv_used
+    END
+    IF driver_path <> '' THEN DO
+        srcdir = VRParseFilePath( driver_path, 'DP')
+        pin    = STREAM( srcdir'\PIN.EXE',    'C', 'QUERY EXISTS')
+        ppdenc = STREAM( srcdir'\PPDENC.EXE', 'C', 'QUERY EXISTS')
+        /* TODO should we check for all the REQUIREDDRIVER FILES as well? */
+    END
+
+    IF pmdx == '' THEN
+        driver_repo = 0
+    ELSE
+        driver_repo = 1
+
+    /* Driver (or one of its required files) was not found.
+     */
+    IF ( driver_path == '') | ( pin == '') | ( ppdenc == '') | ,
+       ( VerifyDriverEAs( driver_path ) == 0 ) THEN
+    DO
+        CALL LINEOUT globals.!log1, ' - Missing required driver files.'
+        RETURN 0
+    END
+
+    IF mustcopy THEN RETURN 2
+RETURN 1
+
+
+/*:VRX         VerifyDriverEAs
+*/
+/* Make sure the driver has its extended attributes.  If not, look for an
+ * accompanying .EA or .EA_ file, and join it to the driver.
+ */
+VerifyDriverEAs: PROCEDURE EXPOSE globals.
+    PARSE ARG driver
+    eas.0 = 0
+    CALL SysQueryEAList driver, 'eas.'
+    IF eas.0 == 0 THEN DO
+        ea_file = SUBSTR( driver, 1, LASTPOS('.', driver )) || 'EA'
+        IF STREAM( ea_file,  'C', 'QUERY EXISTS') ==  '' THEN
+            ea_file = ea_file || '_'
+        IF STREAM( ea_file,  'C', 'QUERY EXISTS') ==  '' THEN
+            RETURN 0
+
+        ADDRESS CMD '@UNLOCK' driver '2>NUL 1>NUL'
+        ADDRESS CMD '@EAUTIL' driver ea_file '/j /p 2>NUL 1>NUL'
+    END
+RETURN 1
+
+
+/*:VRX         BldLevelVersion
+*/
+/* Parse the revision (version) number from a BLDLEVEL string
+ */
+BldLevelVersion: PROCEDURE EXPOSE globals.
+    ARG module
+    revision = ''
+
+    _nq = RXQUEUE('CREATE')
+    _oq = RXQUEUE('SET', _nq )
+
+    ADDRESS CMD '@bldlevel' module '2>&1 | RXQUEUE' _nq
+    DO QUEUED()
+        PARSE PULL _blline
+        IF LEFT( _blline, 9 ) == 'Revision:' THEN DO
+            PARSE VAR _blline 'Revision:' revision .
+            LEAVE
+        END
+    END
+
+    CALL RXQUEUE 'SET', _oq
+    CALL RXQUEUE 'DELETE', _nq
+
+    IF revision == '' THEN revision = '-'
+
+RETURN revision
+
+
+/*:VRX         CopyPrinterPak
+*/
+/* Copies a printerpak driver and all its dependent files from one directory
+ * to another.
+ *
+ *   driver    - The fully-qualified filename of the printerpak .DRV
+ *   newdrvdir - The directory where the files will be copied; must exist
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+CopyPrinterPak: PROCEDURE EXPOSE globals.
+    PARSE ARG driver, newdrvdir
+
+    drv_dir = VRParseFilePath( driver, 'DP')
+    IF drv_dir == '' THEN RETURN 0
+
+    IF VerifyDriverEAs( driver ) == 0 THEN RETURN 0
+
+    CALL LINEOUT globals.!log1, 'Copying driver files from' drv_dir 'to' newdrvdir'...'
+
+    /* Read the list of required driver files from the EAs, and copy them
+     * all to the target directory.
+     */
+    IF SysGetEA( driver, 'REQUIREDDRIVERFILES', 'reqfiles') == 0 THEN DO
+        PARSE VAR reqfiles 5 filelist
+        filelist = TRANSLATE( filelist, ' ', ',')
+        DO i = 1 TO WORDS( filelist )
+            copyfile = drv_dir'\' || WORD( filelist, i )
+            ok = VRCopyFile( copyfile, newdrvdir'\' || WORD( filelist, i ))
+            CALL LINEOUT globals.!log1, ' -' copyfile '(REQUIRED):' ok
+        END
+        DROP copyfile
+        DROP filelist
+    END
+    ELSE RETURN 0
+
+    /* If there are optional files defined as well, try to copy those also.
+     */
+    IF SysGetEA( driver, 'OPTIONALDRIVERFILES', 'reqfiles') == 0 THEN DO
+        PARSE VAR reqfiles 5 filelist
+        filelist = TRANSLATE( filelist, ' ', ',')
+        DO i = 1 TO WORDS( filelist )
+            copyfile = drv_dir'\' || WORD( filelist, i )
+            IF STREAM( copyfile, 'C', 'QUERY EXISTS') == '' THEN ITERATE
+            ok = VRCopyFile( copyfile, newdrvdir'\' || WORD( filelist, i ))
+            CALL LINEOUT globals.!log1, ' -' copyfile '(OPTIONAL):' ok
+        END
+        DROP copyfile
+        DROP filelist
+    END
+
+RETURN 1
+
+
+/*:VRX         PrinterExistsInDRV
+*/
+/* Determine if the specified PrinterPak driver already contains support
+ * for the specified printer model.
+ */
+PrinterExistsInDRV: PROCEDURE EXPOSE globals.
+    PARSE UPPER ARG driver_name, printer_name
+    printer_name = TRANSLATE( printer_name, '_', '.')
+
+    printer_drv = globals.!os2dir'\DLL\'driver_name'\'driver_name'.DRV'
+    /* ?? TODO: install driver_name if not found (prompt first) ?? */
+
+    IF SysGetEA( printer_drv, '.EXPAND', 'exist_ea') <> 0 THEN RETURN 0
+    PARSE VAR exist_ea 1 _eatype 3 .
+    IF C2X( _eatype ) <> 'FDFF' THEN RETURN 0
+
+    PARSE VAR exist_ea 3 _ealen 5 exist_models
+    total_len = C2D( REVERSE( _ealen ))
+
+    /* The variable exist_models now contains a null-separated list of printer
+     * models supported by the driver (including those from previously-imported
+     * PPD files).  Next we check each one against our requested printer name.
+     */
+    start = 1
+    found = 0
+    DO WHILE ( found == 0 ) & ( start < total_len )
+        _strend = POS('0'x, exist_models, start )
+        IF _strend == 0 THEN LEAVE
+        _model = TRANSLATE( SUBSTR( exist_models, start, _strend - start ))
+        IF _model == printer_name THEN
+            found = 1
+        ELSE
+            start = _strend + 1
+    END
+
+RETURN found
+
+
+/*:VRX         CreateDriverList
+*/
+/* Generate a driver listfile from the .EXPAND EA
+ */
+CreateDriverList: PROCEDURE EXPOSE globals.
+    ARG driver, listfile
+
+    IF STREAM( listfile, 'C', 'QUERY EXISTS') <> '' THEN
+        CALL SysFileDelete listfile
+
+    drv_name = FILESPEC('NAME', driver )
+    IF SysGetEA( driver, '.EXPAND', 'eaval') == 0 THEN DO
+        PARSE VAR eaval 3 ealen 5 models
+        offs = 1
+        datalen = C2D( REVERSE( ealen ))
+        DO WHILE offs <= datalen
+            start = SUBSTR( models, offs )
+            inc = POS('00'x, start )
+            IF inc > 1 THEN DO
+                current_name = STRIP( SUBSTR( start, 1, inc-1 ))
+                CALL LINEOUT listfile, current_name':' current_name '('drv_name')'
+            END
+            offs = offs + inc
+        END
+        CALL LINEOUT listfile
+        CALL LINEOUT globals.!log1, 'Created driver list' listfile 'for' driver'.'
+    END
+    ELSE
+        CALL LINEOUT globals.!log1, 'No drivers found in' driver '(missing .EXPAND extended attribute?)'
+
+RETURN 1
+
+
+/*:VRX         AddPort_CUPS
+*/
+/* Adds a new CUPS port.  Returns 0 on full success, 1 if the port was created
+ * but could not be configured, and an OS/2 or PM error code otherwise.
+ */
+AddPort_CUPS: PROCEDURE EXPOSE globals.
+    PARSE ARG portname, hostname, queuename
+    CALL LINEOUT globals.!log1, 'Creating new port' portname
+    ADDRESS CMD '@cupsport' portname hostname queuename '>>' globals.!log2
+    IF rc == 1 THEN DO
+        CALL VRSetIni 'PM_'portname, 'INITIALIZATION', hostname'#'queuename||'00'x, 'SYSTEM', 'NoClose'
+        CALL VRSetIni 'PM_'portname, 'DESCRIPTION',    hostname':'queuename||'00'x, 'SYSTEM'
+    END
+RETURN rc
+
+
+/*:VRX         DeletePort
+*/
+/* Deletes a printer port (any type).
+ */
+DeletePort: PROCEDURE EXPOSE globals.
+    PARSE ARG portname
+    CALL SysIni 'SYSTEM', 'PM_'portname, 'DELETE:'
+    CALL SysIni 'SYSTEM', 'PM_SPOOLER_PORT', portname, 'DELETE:'
+RETURN 1
+
+
+/*:VRX         GetNextPortName
+*/
+/* Get the next unique (non-existing) port name for the specified port driver.
+ */
+GetNextPortName: PROCEDURE
+    ARG portdrv
+
+    maxports = 64       /* should be smarter about this if possible */
+    exists = 1
+    x = 0
+    DO WHILE ( x < maxports ) & ( exists == 1 )
+        x = x + 1
+        portname = portdrv || x
+        nextport = SysIni('SYSTEM', 'PM_SPOOLER_PORT', portname )
+        IF LEFT( nextport, 6 ) == 'ERROR:' THEN exists = 0
+    END
+    IF exists == 1 THEN
+        portname = ''
+
+RETURN portname
+
+
+/*:VRX         GetPortDrivers
+*/
+/* Get the list of currently-installed port drivers.  NOTE: we exclude LPRPDRVR
+ * from this list, because it has to be managed via the TCP/IP configuration
+ * program.
+ */
+GetPortDrivers: PROCEDURE EXPOSE portdrivers.
+    ok = SysIni('SYSTEM', 'PM_PORT_DRIVER', 'ALL:', 'installed.')
+    IF LEFT( ok, 6 ) == 'ERROR:' THEN RETURN 0
+    count = 0
+    DO i = 1 TO installed.0
+        IF installed.i = 'LPRPDRVR' THEN ITERATE
+        fullpath = STRIP( SysIni('SYSTEM', 'PM_PORT_DRIVER', installed.i ), 'T', '00'x )
+        IF LEFT( fullpath, 6 ) == 'ERROR:' THEN fullpath = ''
+        fullpath = STREAM( fullpath , 'C', 'QUERY EXISTS')
+        count = count + 1
+        portdrivers.count = installed.i || ' ' || fullpath
+    END
+    portdrivers.0 = count
+RETURN portdrivers.0
+
+
+/*:VRX         GetQueueName
+*/
+/* Generate a unique queue name from the specified printer name.
+ */
+GetQueueName: PROCEDURE
+    ARG queuename
+
+    DO UNTIL badchar = 0
+        badchar = VERIFY( queuename, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789 ')
+        IF badchar > 0 THEN
+            queuename = OVERLAY(' ', queuename, badchar, 1 )
+    END
+    queuename = LEFT( SPACE( queuename, 0 ), 8 )
+
+    tail = 0
+    PARSE VALUE VRGetIni('PM_SPOOLER', 'DIR', 'SYSTEM') WITH spldir ';' .
+    DO WHILE VRFileExists( spldir'\'queuename ) == 1
+        tail = tail + 1
+        queuename = STRIP( LEFT( queuename, 8 - LENGTH( tail ))) || tail
+    END
+
+RETURN queuename
+
+
+/*:VRX         InstallPortDriver
+*/
+/* Installs a new port driver.
+ *
+ * Returns: 0 on success, 1 on error
+ */
+InstallPortDriver: PROCEDURE EXPOSE globals.
+    ARG new_pdr
+    filename = VRParseFileName( new_pdr, 'NE')
+    IF filename == '' THEN RETURN
+    installed_pdr = TRANSLATE( globals.!os2dir'\DLL\'filename )
+    IF installed_pdr <> new_pdr THEN DO
+        ok = VRCopyFile( new_pdr, installed_pdr )
+        IF ok == 0 THEN RETURN 1
+        /* Try to copy any optional files as well */
+        IF SysGetEA( new_pdr, 'OPTIONALDRIVERFILES', 'reqfiles') == 0 THEN DO
+            drv_dir = VRParseFilePath( new_pdr, 'DP')
+            PARSE VAR reqfiles 5 filelist
+            filelist = TRANSLATE( filelist, ' ', ',')
+            DO i = 1 TO WORDS( filelist )
+                copyfile = drv_dir'\' || WORD( filelist, i )
+                IF STREAM( copyfile, 'C', 'QUERY EXISTS') == '' THEN ITERATE
+                ok = VRCopyFile( copyfile, newdrvdir'\' || WORD( filelist, i ))
+                /*CALL LINEOUT globals.!log1, ' -' copyfile '(OPTIONAL):' ok*/
+            END
+        END
+    END
+
+    key = VRParseFileName( installed_pdr, 'N')
+    CALL VRSetIni 'PM_PORT_DRIVER', key, installed_pdr||'00'x, 'SYSTEM'
+RETURN 0
+
+
+/*:VRX         InstallPrintDriver
+*/
+/* 'Installs' (that is to say, registers with the spooler) an OS printer
+ * device driver/model.  Installs the corresponding printerpak driver if
+ * necessary.
+ *
+ *   driver     - The name of the printerpak driver (without path or extension)
+ *   driverfull - The fully-qualified filename of the printerpak driver
+ *   model      - The printer make/model name used by the driver
+ *
+ * Returns: 0 on success, 1 on error
+ */
+InstallPrintDriver: PROCEDURE EXPOSE globals.
+    PARSE ARG driver, driverfull, model
+
+    ok = 0
+    targetdir = globals.!os2dir'\DLL\'driver
+    targetdrv = targetdir'\'driver'.DRV'
+    IF ( VRFileExists( targetdrv ) == 0 ) THEN DO
+        CALL VRMkDir targetdir
+        r = CopyDriverToSource( driverfull, targetdir )
+        IF r <> 1 THEN ok = 1
+    END
+    IF ok == 0 THEN DO
+        IF VRGetIni('PM_DEVICE_DRIVERS', driver, 'USER') <> targetdrv THEN
+            CALL VRSetIni 'PM_DEVICE_DRIVERS', driver, targetdrv||'00'x, 'USER'
+        CALL VRSetIni 'PM_SPOOLER_DD', driver'.'model, driver'.DRV;;;'||'00'x, 'SYSTEM'
+    END
+RETURN ok
+
+/*:VRX         CreatePrinterObject
+*/
+/* Create the specified printer using SysCreateObject (this should create the
+ * queue automatically).
+ *
+ * Returns: 0 on success or non-zero return code on error.
+ */
+CreatePrinterObject: PROCEDURE EXPOSE globals.
+    PARSE ARG driver, model, portname, queuename, printername
+
+    CALL LINEOUT globals.!log1, 'Creating new printer:' printername '('queuename')'
+    ok = RPUPrinterCreate( printername, queuename, portname, driver'.'model )
+RETURN ok
+
+/*:VRX         GetNameFromPPD
+*/
+GetNameFromPPD: PROCEDURE
+    ARG ppd_file
+
+    IF STREAM( ppd_file, 'C', 'QUERY EXISTS') == '' THEN RETURN ''
+    nickname = ''
+    IF VRParseFilePath( ppd_file, 'E') == 'GZ' THEN DO
+        nq = RXQUEUE('CREATE')
+        oq = RXQUEUE('SET', nq )
+        ADDRESS CMD '@gzip -c -d' ppd_file '| RXQUEUE' nq
+        DO QUEUED()
+            PARSE PULL line
+            line = STRIP( line )
+            IF LEFT( line, 15 ) == '*ShortNickName:' THEN DO
+            PARSE VAR line . ':' _nick '0D'x .
+                nickname = STRIP( _nick )
+                nickname = STRIP( nickname, 'B', '"')
+                LEAVE
+            END
+        END
+        CALL RXQUEUE 'SET',    oq
+        CALL RXQUEUE 'DELETE', nq
+    END
+    ELSE DO
+        CALL LINEIN ppd_file, 1, 0
+        DO WHILE LINES( ppd_file ) <> 0
+            line = STRIP( LINEIN( ppd_file ))
+            IF LEFT( line, 15 ) == '*ShortNickName:' THEN DO
+            PARSE VAR line . ':' _nick '0D'x .
+                nickname = STRIP( _nick )
+                nickname = STRIP( nickname, 'B', '"')
+                LEAVE
+            END
+        END
+        CALL STREAM ppd_file,  'C', 'CLOSE'
+    END
+
+RETURN nickname
+
+/*:VRX         CleanPPD
+*/
+/* Clean out lines from Gutenprint and Foomatic PPD files that are known to
+ * cause problems when importing with PIN.  (Partially based on work by Paul
+ * Smedley and Peter Brown).
+ */
+CleanPPD: PROCEDURE
+    PARSE ARG in_ppd, logfile
+    IF logfile <> '' THEN
+        logfile = STREAM( logfile, 'C', 'QUERY EXISTS')
+
+    out_ppd = VRParseFilePath( in_ppd, 'DPN') || '.TMP'
+    IF STREAM( out_ppd, 'C', 'QUERY EXISTS') \= '' THEN
+        CALL SysFileDelete out_ppd
+
+    IF logfile <> '' THEN
+        CALL CHAROUT logfile, 'Doing cleanup on' in_ppd '...'
+
+    skip_next = 0
+    DO WHILE LINES( in_ppd ) \= 0
+        line = LINEIN( in_ppd )
+        SELECT
+            WHEN skip_next == 1 THEN DO
+                line = STRIP( TRANSLATE( line ))
+                IF line == '*END' THEN skip_next = 0
+            END
+            WHEN LEFT( line, 11 ) == '*StpDefault'        THEN NOP
+            WHEN LEFT( line, 7  ) == '*StpStp'            THEN NOP
+            WHEN LEFT( line, 18 ) == '*StpResolutionMap:' THEN NOP
+            WHEN LEFT( line, 14 ) == '*OPOptionHints'     THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*da.'               THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*de.'               THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*es.'               THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*fi.'               THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*fr.'               THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*it.'               THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*ja.'               THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*ko.'               THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*nb.'               THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*nl.'               THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*pt.'               THEN NOP
+            WHEN LEFT( line, 4 ) ==  '*sv.'               THEN NOP
+            WHEN LEFT( line, 7 ) ==  '*zh_CN.'            THEN NOP
+            WHEN LEFT( line, 7 ) ==  '*zh_TW.'            THEN NOP
+            WHEN LEFT( line, 9  ) == '*Foomatic'          THEN DO
+                line = STRIP( line )
+                IF RIGHT( line, 2 ) == '&&' THEN skip_next = 1
+            END
+            OTHERWISE DO
+                CALL LINEOUT out_ppd, line
+                skip_next = 0
+            END
+        END
+    END
+    CALL STREAM in_ppd,  'C', 'CLOSE'
+    CALL STREAM out_ppd, 'C', 'CLOSE'
+
+    ok = VRCopyFile( out_ppd, in_ppd )
+    IF logfile <> '' THEN DO
+        IF ok == 1 THEN
+            CALL LINEOUT logfile, 'OK'
+        ELSE DO
+            CALL LINEOUT logfile, 'Failed!'
+            CALL LINEOUT logfile, '  ->' VRError()
+        END
+        CALL LINEOUT logfile, ''
+    END
+    CALL SysFileDelete out_ppd
+
+RETURN
+
+/*:VRX         MatchPrinterModel
+*/
+/* Find a set of printers supported by the OS/2 driver which mostly closely
+ * match the given name.
+ */
+MatchPrinterModel: PROCEDURE EXPOSE globals. models.
+    PARSE UPPER ARG driver_name, printer_name
+    printer_name = TRANSLATE( printer_name, '_', '.')
+    printer_drv = globals.!os2dir'\DLL\'driver_name'\'driver_name'.DRV'
+    models.0 = 0
+
+    IF SysGetEA( printer_drv, '.EXPAND', 'exist_ea') <> 0 THEN RETURN 0
+    PARSE VAR exist_ea 1 _eatype 3 .
+    IF C2X( _eatype ) <> 'FDFF' THEN RETURN 0
+
+    PARSE VAR exist_ea 3 _ealen 5 exist_models
+    total_len = C2D( REVERSE( _ealen ))
+
+    /* The variable exist_models now contains a null-separated list of printer
+     * models supported by the driver (including those from previously-imported
+     * PPD files).  Next we check each one against our requested printer name.
+     */
+    start = 1
+    count = 0
+    best  = 0
+    DO WHILE start < total_len
+        _strend = POS('0'x, exist_models, start )
+        IF _strend == 0 THEN LEAVE
+        _model = TRANSLATE( SUBSTR( exist_models, start, _strend - start ))
+        _model = TRANSLATE( _model, ' ', '-')
+        _comp = COMPARE( _model, printer_name )
+        IF WORD( _model, 1 ) == WORD( printer_name, 1 ) THEN DO
+            count = count + 1
+            IF _comp == 0 THEN DO
+                _comp = 9999
+                best  = count
+            END
+            ELSE IF ( best == 0 ) & ( _comp > LENGTH( printer_name )) THEN
+                best = count
+/*
+            models.count = RIGHT( _comp, 4, '0') SUBSTR( exist_models, start, _strend - start )
+*/
+            models.count = SUBSTR( exist_models, start, _strend - start )
+        END
+        start = _strend + 1
+    END
+    models.0 = count
+
+/*
+    CALL SysStemSort 'models.', 'D', 'I',,, 1, 4
+    DO i = 1 TO count
+        models.i = SUBWORD( models.i, 2 )
+    END
+*/
+RETURN best
+
+
+/*:VRX         CheckWritablePath
+*/
+CheckWritablePath: PROCEDURE EXPOSE globals.
+    ARG path
+
+    /* Make sure path exists & is a directory */
+    IF \VRIsDir( path ) THEN RETURN 1
+
+    /* Make sure the drive is accessible */
+    di = SysDriveInfo( VRParseFilePath( path, 'DP'))
+    IF di == '' THEN RETURN 2
+
+    /* Make sure the drive has a supported filesystem */
+    fs = SysFileSystemType( prdrv )
+    IF WORDPOS( fs, 'HPFS JFS FAT FAT32') == 0 THEN RETURN 3
+
+RETURN 0
+
+
+/*:VRX         QueryAvailableDrivers
+*/
+/* Determine which of our supported PrinterPak drivers are currently available.
+ */
+QueryAvailableDrivers: PROCEDURE EXPOSE globals. drv_list.
+    drv_list.0 = 0
+
+    test_drivers = 'ECUPS ECUPS-HP PSPRINT'
+    DO i = 1 TO WORDS( test_drivers )
+        driver = WORD( test_drivers, i )
+        ok = GetDriverSource( driver )
+        IF ok == '' THEN
+            ok = VRGetIni('PM_DEVICE_DRIVERS', driver, 'USER')
+        IF ok <> '' THEN
+            CALL SysStemInsert 'drv_list.', drv_list.0+1, driver
+    END
+
+RETURN drv_list.0
+
+
+/*:VRX         UpdatePrDesc
+*/
+UpdatePrDesc: PROCEDURE EXPOSE globals.
+    ARG driver, fqn
+
+    IF globals.!prdesc == '' THEN RETURN 1
+
+    ok = RPUEnumModels( fqn, 'newdevs.')
+    IF ok == 0 THEN RETURN 2
+
+    _count = 0
+    CALL LINEIN globals.!prdesc, 1, 0
+    DO WHILE LINES( globals.!prdesc )
+        _next = LINEIN( globals.!prdesc )
+        PARSE UPPER VAR _next WITH . ':' . '('_prdrv')' .
+        IF _prdrv == driver THEN ITERATE
+        _count = _count + 1
+        prdefs.count = _next
+    END
+    CALL STREAM globals.!prdesc, 'C', 'CLOSE'
+
+    DO i = 1 TO devs.0
+        _count = _count + 1
+        prdefs._count = newdevs.i':' newdevs.i '('driver')'
+    END
+    prdefs.0 = count
+
+    CALL VRSortStem 'prdefs.'
+
+    _prdir = VRParseFileName( globals.!prdesc, 'DP')
+    CALL VRCopyFile globals.!prdesc, _prdir'\PRDESC.BAK'
+    CALL VRDeleteFile globals.!prdesc
+    DO i = 1 TO prdefs.0
+        CALL LINEOUT globals.!prdesc, prdefs.i
+    END
+    CALL LINEOUT globals.!prdesc
+
+RETURN 0
+
+
+/*:VRX         NLSGetMessage
+*/
+/*
+ * Gets the message text associated with the given message number from the
+ * current language file.
+ */
+NLSGetMessage: PROCEDURE EXPOSE globals.
+    PARSE ARG msgnum, .
+    args = ARG()
+
+    msgfile = globals.!messages
+    IF msgnum == '' THEN RETURN ''
+
+    sub_parms = ''
+    DO i = 2 TO args
+        sub_parms = sub_parms', "'ARG( i )'"'
+    END
+
+    INTERPRET 'msgfromfile = SysGetMessage( msgnum, msgfile' sub_parms ')'
+
+    PARSE VAR msgfromfile message '0D'x .
+    IF SUBSTR( message, 1, 4 ) == 'SYS0' THEN message = ''
+
+RETURN message
+
+
+/*:VRX         NLSSetText
+*/
+/*
+ * Sets the specified property of the specified control to the specified
+ * message text.
+ */
+NLSSetText: PROCEDURE EXPOSE globals.
+    PARSE ARG control, property, message, substitution
+    args = ARG()
+
+    success = 1
+    IF args < 4 THEN
+        text = NLSGetMessage( message )
+    ELSE DO
+        sub_parms = ''
+        DO i = 4 TO args
+            sub_parms = sub_parms '"'|| ARG( i ) ||'",'
+        END
+        sub_parms = STRIP( sub_parms, 'T', ',')
+        INTERPRET 'text = NLSGetMessage( message, 'sub_parms')'
+    END
+
+    IF text == '' THEN success = 0
+    ELSE               CALL VRSet control, property, text
+
+RETURN success
+
Index: trunk/gui/util/prntobj/buildicc.cmd
===================================================================
--- trunk/gui/util/prntobj/buildicc.cmd	(revision 32)
+++ trunk/gui/util/prntobj/buildicc.cmd	(revision 33)
@@ -1,2 +1,2 @@
-icc /Ss /Gm /Gd prntobj.c
+icc /Fm /Ss /Gm /Gd prntobj.c
 dllrname.exe prntobj.exe CPPOM30=OS2OM30 /Q /R
