]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Load cups into easysw/current.
authorjlovell <jlovell@a1ca3aef-8c08-0410-bb20-df032aa958be>
Fri, 7 Apr 2006 21:00:45 +0000 (21:00 +0000)
committerjlovell <jlovell@a1ca3aef-8c08-0410-bb20-df032aa958be>
Fri, 7 Apr 2006 21:00:45 +0000 (21:00 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@125 a1ca3aef-8c08-0410-bb20-df032aa958be

32 files changed:
CHANGES.txt
Makedefs.in
backend/usb-darwin.c
backend/usb-unix.c
backend/usb.c
conf/mime.types
config-scripts/cups-defaults.m4
config.h.in
configure.in
cups/encode.c
cups/globals.c
cups/http-private.h
cups/http.c
cups/language.c
cups/test.ppd
cups/transcode.c
filter/imagetops.c
filter/pstops.c
packaging/cups.list.in
scheduler/cert.c
scheduler/client.c
scheduler/conf.c
scheduler/env.c
scheduler/ipp.c
scheduler/job.c
scheduler/job.h
scheduler/main.c
scheduler/printers.c
scheduler/process.c
scheduler/server.c
scheduler/statbuf.c
scheduler/subscriptions.h

index dd1be6a43c3024ddfa6dc40fb060ec2da3fee958..604557f50ccd38995a676780e17812558d735d5f 100644 (file)
@@ -1,8 +1,29 @@
-CHANGES.txt - 2006-04-03
+CHANGES.txt - 2006-04-07
 ------------------------
 
 CHANGES IN CUPS V1.2
 
+       - The scheduler was not always using the string pool,
+         causing random crashes.
+       - The lpmove and the web interface's Move Job button did
+         not work with stopped jobs (STR #1534)
+       - The PostScript filter did not handle the page-set
+         option properly with number-up printing (STR #1543)
+       - The scheduler now only warns about unsupported ACLs
+         once (STR #1532)
+       - The "fitplot" option did not work with output from
+         Mozilla (STR #1542)
+       - The imagetops filter did not work with Level 2 or 3
+         printers (STR #1533)
+       - The scheduler now recognizes PostScript files with PJL
+         commands that do not include an ENTER LANGUAGE command.
+       - Added --with-printcap configure option.
+       - 64-bit SSL fixes for MacOS X.
+       - The scheduler didn't send some printer state change
+         events.
+       - The scheduler didn't send jobs to busy remote printers.
+       - Fixed some problems with the launchd support.
+       - Added new USB printer backend for MacOS X.
        - The PostScript filter now handles files that start with
          an incomplete PJL header (PR #6076)
        - The web interface language selection code did not try
index ceb6e4bf47e5c0b72931702258c390d10027934e..b415a0c2d99526c8206298c51a6d45d231f02824 100644 (file)
@@ -1,5 +1,5 @@
 #
-# "$Id: Makedefs.in 5341 2006-03-24 19:51:21Z mike $"
+# "$Id: Makedefs.in 5384 2006-04-07 18:03:16Z mike $"
 #
 #   Common makefile definitions for the Common UNIX Printing System (CUPS).
 #
@@ -118,11 +118,11 @@ INSTALLSTATIC     =       @INSTALLSTATIC@
 ARCHFLAGS      =       @ARCHFLAGS@
 ARFLAGS                =       @ARFLAGS@
 BACKLIBS       =       @BACKLIBS@
-CFLAGS         =       -I.. $(RC_CFLAGS) $(SSLFLAGS) @CPPFLAGS@ @CFLAGS@ \
+CFLAGS         =       -I.. $(SSLFLAGS) @CPPFLAGS@ @CFLAGS@ \
                        @LARGEFILE@ @PTHREAD_FLAGS@ $(OPTIONS)
 COMMONLIBS     =       @LIBS@
 CUPSDLIBS      =       @CUPSDLIBS@
-CXXFLAGS       =       -I.. $(RC_CFLAGS) $(SSLFLAGS) @CPPFLAGS@ @CXXFLAGS@ \
+CXXFLAGS       =       -I.. $(SSLFLAGS) @CPPFLAGS@ @CXXFLAGS@ \
                        @LARGEFILE@ @PTHREAD_FLAGS@ $(OPTIONS)
 CXXLIBS                =       @CXXLIBS@
 DSOFLAGS       =       @DSOFLAGS@
@@ -260,5 +260,5 @@ DBUSDIR             =       @DBUSDIR@
 
 
 #
-# End of "$Id: Makedefs.in 5341 2006-03-24 19:51:21Z mike $"
+# End of "$Id: Makedefs.in 5384 2006-04-07 18:03:16Z mike $"
 #
index 11009b27a176bd887ff7f7b901fae88c27be5d17..39edff1ee48d6d532efb1049a41c74777d06e991 100644 (file)
@@ -1,68 +1,50 @@
 /*
- * "$Id: usb-darwin.c 5241 2006-03-07 22:07:44Z mike $"
+ * "$Id: usb-darwin.c 5373 2006-04-06 20:03:32Z mike $"
  *
- *   USB port on Darwin backend for the Common UNIX Printing System (CUPS).
- *
- *   This file is included from "usb.c" when compiled on MacOS X or Darwin.
- *
- *   Copyright 2004 Apple Computer, Inc. All rights reserved.
+ * © Copyright 2005-2006 Apple Computer, Inc. All rights reserved.
  *
- *   IMPORTANT:         This Apple software is supplied to you by Apple Computer,
- *   Inc. ("Apple") in consideration of your agreement to the following
- *   terms, and your use, installation, modification or redistribution of
- *   this Apple software constitutes acceptance of these terms.         If you do
- *   not agree with these terms, please do not use, install, modify or
- *   redistribute this Apple software.
+ * IMPORTANT:  This Apple software is supplied to you by Apple Computer,
+ * Inc. ("Apple") in consideration of your agreement to the following
+ * terms, and your use, installation, modification or redistribution of
+ * this Apple software constitutes acceptance of these terms.  If you do
+ * not agree with these terms, please do not use, install, modify or
+ * redistribute this Apple software.
  *
- *   In consideration of your agreement to abide by the following terms, and
- *   subject to these terms, Apple grants you a personal, non-exclusive
- *   license, under Apple/s copyrights in this original Apple software (the
- *   "Apple Software"), to use, reproduce, modify and redistribute the Apple
- *   Software, with or without modifications, in source and/or binary forms;
- *   provided that if you redistribute the Apple Software in its entirety and
- *   without modifications, you must retain this notice and the following
- *   text and disclaimers in all such redistributions of the Apple Software. 
- *   Neither the name, trademarks, service marks or logos of Apple Computer,
- *   Inc. may be used to endorse or promote products derived from the Apple
- *   Software without specific prior written permission from Apple.  Except
- *   as expressly stated in this notice, no other rights or licenses, express
- *   or implied, are granted by Apple herein, including but not limited to
- *   any patent rights that may be infringed by your derivative works or by
- *   other works in which the Apple Software may be incorporated.
+ * In consideration of your agreement to abide by the following terms, and
+ * subject to these terms, Apple grants you a personal, non-exclusive
+ * license, under Apple's copyrights in this original Apple software (the
+ * "Apple Software"), to use, reproduce, modify and redistribute the Apple
+ * Software, with or without modifications, in source and/or binary forms;
+ * provided that if you redistribute the Apple Software in its entirety and
+ * without modifications, you must retain this notice and the following
+ * text and disclaimers in all such redistributions of the Apple Software. 
+ * Neither the name, trademarks, service marks or logos of Apple Computer,
+ * Inc. may be used to endorse or promote products derived from the Apple
+ * Software without specific prior written permission from Apple.  Except
+ * as expressly stated in this notice, no other rights or licenses, express
+ * or implied, are granted by Apple herein, including but not limited to
+ * any patent rights that may be infringed by your derivative works or by
+ * other works in which the Apple Software may be incorporated.
  *
- *   The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
- *   MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
- *   THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
- *   FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
- *   OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+ * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
+ * THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
+ * OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
  *
- *   IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
- *   OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *   INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
- *   MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
- *   AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
- *   STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
- *   POSSIBILITY OF SUCH DAMAGE.
- *
- * Contents:
- *
- *   print_device() - Send a file to the specified USB port.
- *   list_devices() - List all USB devices.
+ * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
+ * MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
+ * AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
+ * STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
 
 /*
- * Include necessary headers...
+ *   USB port on Darwin backend for the Common UNIX Printing System (CUPS).
  */
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <ApplicationServices/ApplicationServices.h>
-
-#include <IOKit/usb/IOUSBLib.h>
-#include <IOKit/IOCFPlugIn.h>
-#include <mach/mach.h> 
-#include <mach/mach_error.h>
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <termios.h>
 #include <unistd.h>
-#include <pthread.h>           /* Used for writegReadMutex */
-
-#ifndef kPMPrinterURI
-#  define kPMPrinterURI CFSTR("Printer URI")
-#endif
+#include <sys/sysctl.h>
+#include <libgen.h>
+#include <mach/mach.h> 
+#include <mach/mach_error.h>
+#include <mach/mach_time.h>
+#include <cups/debug.h>
 
-/*
- * Panther/10.3 kIOUSBInterfaceInterfaceID190
- * Jaguar/10.2 kIOUSBInterfaceInterfaceID182
- */
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOCFPlugIn.h>
 
-#define USB_INTERFACE_KIND  CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190)
-#define kUSBLanguageEnglish 0x409
+#include <pthread.h>
 
-/*
- * Section 5.3 USB Printing Class spec
+/* 
+ * WAITEOF_DELAY is number of seconds we'll wait for responses from
+ * the printer after we've finished sending all the data 
  */
+#define WAITEOF_DELAY                  7
+#define DEFAULT_TIMEOUT                        60L
 
-#define kUSBPrintingSubclass           1
-#define kUSBPrintingProtocolNoOpen     0
-#define kUSBPrintingProtocolUnidirectional  1
-#define kUSBPrintingProtocolBidirectional   2
+#define        USB_INTERFACE_KIND              CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190)
+#define kUSBLanguageEnglish            0x409
 
-#define kUSBPrintClassGetDeviceID      0
-#define kUSBPrintClassGetCentronicsStatus   1
-#define kUSBPrintClassSoftReset                2
-
-/*
- *  Apple MacOS X printer-class plugins
- */
+#define PRINTER_POLLING_INTERVAL       5                               /* seconds */
+#define INITIAL_LOG_INTERVAL           (PRINTER_POLLING_INTERVAL)
+#define SUBSEQUENT_LOG_INTERVAL                (3*INITIAL_LOG_INTERVAL)
 
 #define kUSBPrinterClassTypeID         (CFUUIDGetConstantUUIDWithBytes(NULL, 0x06, 0x04, 0x7D, 0x16, 0x53, 0xA2, 0x11, 0xD6, 0x92, 0x06, 0x00, 0x30, 0x65, 0x52, 0x45, 0x92))
-
-#define kUSBPrinterClassInterfaceID    (CFUUIDGetConstantUUIDWithBytes(NULL, 0x03, 0x34, 0x6D, 0x74, 0x53, 0xA3, 0x11, 0xD6, 0x9E, 0xA1, 0x76, 0x30, 0x65, 0x52, 0x45, 0x92))
-
-#define kUSBGenericPrinterClassDriver      CFSTR("/System/Library/Printers/Libraries/USBGenericPrintingClass.plugin")
-#define kUSBGenericTOPrinterClassDriver            CFSTR("/System/Library/Printers/Libraries/USBGenericTOPrintingClass.plugin")
+#define        kUSBPrinterClassInterfaceID     (CFUUIDGetConstantUUIDWithBytes(NULL, 0x03, 0x34, 0x6D, 0x74, 0x53, 0xA3, 0x11, 0xD6, 0x9E, 0xA1, 0x76, 0x30, 0x65, 0x52, 0x45, 0x92))
 
 #define kUSBClassDriverProperty                CFSTR("USB Printing Class")
-#define kUSBPrinterClassDeviceNotOpen      -9664   /*kPMInvalidIOMContext*/
 
-typedef union
-{
-  char     b;
-  struct
-  {
-    unsigned   reserved0 : 2;
-    unsigned   paperError : 1;
-    unsigned   select : 1;
-    unsigned   notError : 1;
-    unsigned   reserved1 : 3;
-  } status;
-} CentronicsStatusByte;
+#define kUSBGenericTOPrinterClassDriver        CFSTR("/System/Library/Printers/Libraries/USBGenericTOPrintingClass.plugin")
+#define kUSBPrinterClassDeviceNotOpen  -9664   /*kPMInvalidIOMContext*/
 
-typedef struct
-{
-  CFStringRef  manufacturer;   /* manufacturer name */
-  CFStringRef  product;        /* product name */
-  CFStringRef  compatible;     /* compatible product name */
-  CFStringRef  serial;         /* serial number */
-  CFStringRef  command;        /* command set */
-  CFStringRef  ppdURL;         /* url of the selected PPD, if any */
-} USBPrinterAddress;
 
-typedef IOUSBInterfaceInterface190 **USBPrinterInterface;
+#pragma mark -
+/*
+ * Section 5.3 USB Printing Class spec
+ */
+#define kUSBPrintingSubclass                   1
+#define kUSBPrintingProtocolNoOpen             0
+#define kUSBPrintingProtocolUnidirectional     1
+#define kUSBPrintingProtocolBidirectional      2
+
+typedef IOUSBInterfaceInterface190     **printer_interface_t;
 
-typedef struct 
+typedef struct iodevice_request_s              /**** Device request ****/
 {
-  UInt8            requestType;
-  UInt8            request;
-  UInt16    value;
-  UInt16    index;
-  UInt16    length;
-  void     *buffer;    
-} USBIODeviceRequest;
-
-typedef struct classDriverContext
+  UInt8                requestType;                    
+  UInt8                request;
+  UInt16       value;
+  UInt16       index;
+  UInt16       length;
+  void         *buffer;        
+} iodevice_request_t;
+
+typedef union {                                        /**** Centronics status byte ****/
+  char         b;
+  struct {
+    unsigned   reserved0:2;
+    unsigned   paperError:1;
+    unsigned   select:1;
+    unsigned   notError:1;
+    unsigned   reserved1:3;
+  } status;
+} centronics_status_t;
+
+typedef struct classdriver_context_s           /**** Classdriver context ****/
 {
   IUNKNOWN_C_GUTS;
-  CFPlugInRef      plugin;     /* release plugin */
-  IUnknownVTbl     **factory;  
-  void         *vendorReference;/* vendor class specific usage */
-  UInt32       location;   /* unique location in bus topology */
-  UInt8                interfaceNumber;
-  UInt16       vendorID;
-  UInt16       productID;
-  USBPrinterInterface  interface;  /* identify the device to IOKit */
-  UInt8                outpipe;    /* mandatory bulkOut pipe */
-  UInt8                inpipe;     /* optional bulkIn pipe */
-  /*
-  **   general class requests
-  */
-  kern_return_t            (*DeviceRequest)( struct classDriverContext **printer, USBIODeviceRequest *iorequest, UInt16 timeout );
-  kern_return_t (*GetString)( struct classDriverContext **printer, UInt8 whichString, UInt16 language, UInt16 timeout, CFStringRef *result );
-  /*
-  **   standard printer class requests
-  */
-  kern_return_t (*SoftReset)( struct classDriverContext **printer, UInt16 timeout );
-  kern_return_t (*GetCentronicsStatus)( struct classDriverContext **printer, CentronicsStatusByte *result, UInt16 timeout );
-  kern_return_t (*GetDeviceID)( struct classDriverContext **printer, CFStringRef *devid, UInt16 timeout );
-  /*
-  **   standard bulk device requests
-  */
-  kern_return_t            (*ReadPipe)( struct classDriverContext **printer, UInt8 *buffer, UInt32 *count );
-  kern_return_t            (*WritePipe)( struct classDriverContext **printer, UInt8 *buffer, UInt32 *count, Boolean eoj );
-  /*
-  **   interface requests
-  */
-  kern_return_t            (*Open)( struct classDriverContext **printer, UInt32 location, UInt8 protocol );
-  kern_return_t            (*Abort)( struct classDriverContext **printer );
-  kern_return_t            (*Close)( struct classDriverContext **printer );
-  /*
-  **   initialize and terminate
-  */
-  kern_return_t            (*Initialize)( struct classDriverContext **printer, struct classDriverContext **baseclass );
-  kern_return_t            (*Terminate)( struct classDriverContext **printer );
-} USBPrinterClassContext;
+  CFPlugInRef          plugin;                 /* release plugin */
+  IUnknownVTbl         **factory;              /* Factory */
+  void                 *vendorReference;       /* vendor class specific usage */
+  UInt32               location;               /* unique location in bus topology */
+  UInt8                        interfaceNumber;        /* Interface number */
+  UInt16               vendorID;               /* Vendor id */
+  UInt16               productID;              /* Product id */
+  printer_interface_t  interface;              /* identify the device to IOKit */
+  UInt8                        outpipe;                /* mandatory bulkOut pipe */
+  UInt8                        inpipe;                 /* optional bulkIn pipe */
 
+  /* general class requests */
+  kern_return_t (*DeviceRequest)( struct classdriver_context_s **printer, iodevice_request_t *iorequest, UInt16 timeout );
+  kern_return_t        (*GetString)( struct classdriver_context_s **printer, UInt8 whichString, UInt16 language, UInt16 timeout, CFStringRef *result );
 
-typedef struct usbPrinterClassType
-{
-    USBPrinterClassContext  *classdriver;
-    CFUUIDRef              factoryID;
-    UInt32                 refCount;
-} USBPrinterClassType;
+  /* standard printer class requests */
+  kern_return_t        (*SoftReset)( struct classdriver_context_s **printer, UInt16 timeout );
+  kern_return_t        (*GetCentronicsStatus)( struct classdriver_context_s **printer, centronics_status_t *result, UInt16 timeout );
+  kern_return_t        (*GetDeviceID)( struct classdriver_context_s **printer, CFStringRef *devid, UInt16 timeout );
 
+  /* standard bulk device requests */
+  kern_return_t (*ReadPipe)( struct classdriver_context_s **printer, UInt8 *buffer, UInt32 *count );
+  kern_return_t (*WritePipe)( struct classdriver_context_s **printer, UInt8 *buffer, UInt32 *count, Boolean eoj );
 
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-       Constants
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+  /* interface requests */
+  kern_return_t (*Open)( struct classdriver_context_s **printer, UInt32 location, UInt8 protocol );
+  kern_return_t (*Abort)( struct classdriver_context_s **printer );
+  kern_return_t (*Close)( struct classdriver_context_s **printer );
 
-/*
-    Debugging output to Console
-    DEBUG undefined or
-    DEBUG=0    production code: suppress console output
-
-    DEBUG=1    report errors (non-zero results)
-    DEBUG=2    report all results, generate dumps
-*/
-#if DEBUG==2
-#define DEBUG_ERR(c, x)                            showint(x, c)
-#define DEBUG_DUMP( text, buf, len )       dump( text, buf, len )
-#define DEBUG_CFString( text, a )          showcfstring( text, a )
-#define DEBUG_CFCompareString( text, a, b ) cmpcfs( text, a, b )
-#elif DEBUG==1
-#define DEBUG_ERR(c, x)                            if (c) fprintf(stderr, x, c)
-#define DEBUG_DUMP( text, buf, len )
-#define DEBUG_CFString( text, a )
-#define DEBUG_CFCompareString( text, a, b )
-#else
-#define DEBUG_ERR(c, x)
-#define DEBUG_DUMP( text, buf, len )
-#define DEBUG_CFString( text, a )
-#define DEBUG_CFCompareString( text, a, b )
-#endif
+  /* initialize and terminate */
+  kern_return_t (*Initialize)( struct classdriver_context_s **printer, struct classdriver_context_s **baseclass );
+  kern_return_t (*Terminate)( struct classdriver_context_s **printer );
 
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-       Type Definitions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
-typedef struct
-{
-    /*
-     * Tagged/Tranparent Binary Communications Protocol
-     * TBCP read
-     */
-    Boolean                tbcpQuoteReads;         /* enable tbcp on reads */
-    Boolean                escapeNextRead;         /* last char of last read buffer was escape */
-    UInt8                  *tbcpReadData;          /* read buffer */
-    UInt32                 readLength;             /* read buffer length (all used) */
-    int                            match_endoffset,        /* partial match of end TBCP sequence */
-                           match_startoffset;      /* partial match of start TBCP sequence */
-    /*
-     * TBCP write
-     */
-    UInt8                  *tbcpWriteData;         /* write buffer */
-    UInt32                 tbcpBufferLength,       /* write buffer allocated length */
-                           tbcpBufferRemaining;    /* write buffer not used */
+} classdriver_context_t;
 
-    Boolean                sendStatusNextWrite;
 
-} PostScriptData;
+typedef Boolean (*iterator_callback_t)(void *refcon, io_service_t obj);
 
-typedef struct 
-{
-    CFPlugInRef                    plugin;         /* valid until plugin is release  */
-    USBPrinterClassContext  **classdriver;  /* usb printer class in user space */
-    CFStringRef                    bundle;         /* class driver URI */
-    UInt32                 location;       /* unique location in USB topology */
-    USBPrinterAddress      address;        /* topology independent bus address */
-    CFURLRef               reference;      /* internal use */
-} USBPrinterInfo;
-
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-       Functions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+typedef struct iterator_reference_s {          /**** Iterator reference data */
+  iterator_callback_t callback;
+  void         *userdata;
+  Boolean      keepRunning;
+} iterator_reference_t;
 
-/*
-**  IOKit to CF functions
-*/
-USBPrinterInfo     *UsbCopyPrinter( USBPrinterInfo *aPrinter );
-CFMutableArrayRef   UsbGetAllPrinters( void );
-void               UsbReleasePrinter( USBPrinterInfo *aPrinter );
-void               UsbReleaseAllPrinters( CFMutableArrayRef printers );
-kern_return_t      UsbRegistryOpen( USBPrinterAddress *usbAddress, USBPrinterInfo **result );
-kern_return_t      UsbUnloadClassDriver( USBPrinterInfo *printer );
-kern_return_t      UsbLoadClassDriver( USBPrinterInfo *printer, CFUUIDRef interfaceID, CFStringRef classDriverBundle );
-CFStringRef        UsbMakeFullUriAddress( USBPrinterInfo *aPrinter );
-
-int        UsbSamePrinter( const USBPrinterAddress *lastTime, const USBPrinterAddress *thisTime ); 
-
-OSStatus    UsbGetPrinterAddress( USBPrinterInfo *thePrinter, USBPrinterAddress *address, UInt16 timeout );
-
-
-/*******************************************************************************
-    Contains:  Support IEEE-1284 DeviceID as a CFString.
-
-    Copyright 2000-2005 by Apple Computer, Inc., all rights reserved.
-
-    Description:
-       IEEE-1284 Device ID is referenced in USB and PPDT (1394.3). It allows
-       a computer peripheral to convey information about its required software
-       to the host system.
-       
-       DeviceID is defined as a stream of ASCII bytes, commencing with one 16-bit
-       binary integer in Little-Endian format which describes how many bytes
-       of data are required by the entire DeviceID.
-       
-       The stream of bytes is further characterized as a series of
-       key-value list pairs. In other words each key can be followed by one
-       or more values. Multiple key-value list pairs fill out the DeviceID stream.
-       
-       Some keys are required: COMMAND SET (or CMD), MANUFACTURER (or MFG),
-       and MODEL (or MDL).
-       
-       One needs to read the first two bytes of DeviceID to allocate storage
-       for the complete DeviceID string. Then a second read operation can
-       retrieve the entire string.
-       
-       Often DeviceID is not very large. By allocating a reasonable buffer one
-       can fetch most device's DeviceID string on the first read.
-    
-    A more formal definition of DeviceID.
-
-       <DeviceID> = <Length><Key_ValueList_Pair>+
-
-       <Length> = <low byte of 16 bit integer><high byte of 16 bit integer>
-       <Key_ValueList_Pair> = <Key>:<Value>[,<Value>]*;
-
-       <Key> = <ASCII Byte>+
-       <Value> = <ASCII Byte>+
-       
-       Some keys are defined in the standard. The standard specifies that
-       keys are case sensitive. White space is allowed in the key.
-       
-       The standard does not say that values are case-sensitive.
-       Lexmark is known to ship printers with mixed-case value:
-           i.e., 'CLASS:Printer'
-
-       Required Keys:
-           'COMMAND SET' or CMD
-           MANUFACTURER or MFG
-           MODEL or MDL
-       
-       Optional Keys:
-           CLASS
-               Value PRINTER is referenced in the standard.
-               
-       Observed Keys:
-           SN,SERN
-               Used by Hewlett-Packard for the serial number.
-       
-       
-*******************************************************************************/
-
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    Pragmas
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
-
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    Constants
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-#define kDeviceIDKeyCommand            CFSTR("COMMAND SET:")
-#define kDeviceIDKeyCommandAbbrev      CFSTR( "CMD:" )
-
-#define kDeviceIDKeyManufacturer       CFSTR("MANUFACTURER:")
-#define kDeviceIDKeyManufacturerAbbrev CFSTR( "MFG:" )
-
-#define kDeviceIDKeyModel              CFSTR("MODEL:")
-#define kDeviceIDKeyModelAbbrev                CFSTR( "MDL:" )
-
-#define kDeviceIDKeySerial             CFSTR("SN:")
-#define kDeviceIDKeySerialAbbrev       CFSTR("SERN:")
-
-#define kDeviceIDKeyCompatible         CFSTR("COMPATIBLITY ID:")
-#define kDeviceIDKeyCompatibleAbbrev   CFSTR("CID:")
-
-/* delimiters */
-#define kDeviceIDKeyValuePairDelimiter CFSTR(";")
-
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    Type definitions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    Function prototypes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
-static CFStringRef CreateEncodedCFString(CFStringRef string);
-static CFRange DelimitSubstring( CFStringRef stringToSearch, CFStringRef delim, CFRange bounds, CFStringCompareFlags options );
-static void parseOptions(const char *options, char *serial);
-
-CFStringRef
-DeviceIDCreateValueList(    const CFStringRef deviceID,
-                           const CFStringRef abbrevKey,
-                           const CFStringRef key );
-
-static int addPercentEscapes(const unsigned char* src, char* dst, int dstMax);
-static int removePercentEscapes(const char* src, unsigned char* dst, int dstMax);
-
-/* Required to suppress redefinition warnings for these two symbols 
-*/
-#if defined(TCP_NODELAY)
-#undef TCP_NODELAY
-#endif
-#if defined(TCP_MAXSEG)
-#undef TCP_MAXSEG
-#endif
+typedef struct printer_data_s {                        /**** Printer context data ****/
+  io_service_t           printerObj;
+  classdriver_context_t  **printerDriver;
 
-#include <cups/cups.h>
+  pthread_cond_t       readCompleteCondition;
+  pthread_mutex_t      readMutex;
+  int                  done;
 
+  const char           *uri;
+  CFStringRef          make;
+  CFStringRef          model;
+  CFStringRef          serial;
 
-#define PRINTER_POLLING_INTERVAL       5   /* seconds */
-#define INITIAL_LOG_INTERVAL           (PRINTER_POLLING_INTERVAL)
-#define SUBSEQUENT_LOG_INTERVAL                (3*INITIAL_LOG_INTERVAL)
+  UInt32               location;
+  Boolean              waitEOF;
 
-/* WAITEOF_DELAY is number of seconds we'll wait for responses from the printer */
-/*  after we've finished sending all the data */
-#define WAITEOF_DELAY          7
+} printer_data_t;
 
-#define USB_MAX_STR_SIZE       1024
 
+/*
+ * Local functions...
+ */
 
-static volatile int done = 0;
-static int gWaitEOF = false;
-static pthread_cond_t *gReadCompleteConditionPtr = NULL;
-static pthread_mutex_t *gReadMutexPtr = NULL;
+static Boolean list_device_callback(void *refcon, io_service_t obj);
+static Boolean find_device_callback(void *refcon, io_service_t obj);
+static void iterate_printers(iterator_callback_t callBack, void *userdata);
+static void device_added(void *userdata, io_iterator_t iterator);
+static void copy_deviceinfo(CFStringRef deviceIDString, CFStringRef *make, CFStringRef *model, CFStringRef *serial);
+static void release_deviceinfo(CFStringRef *make, CFStringRef *model, CFStringRef *serial);
+static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t intf, classdriver_context_t ***driver);
+static kern_return_t unload_classdriver(classdriver_context_t ***classDriver);
+static kern_return_t load_printerdriver(printer_data_t *printer);
+static kern_return_t registry_open(printer_data_t *printer);
+static kern_return_t registry_close(printer_data_t *printer);
+static OSStatus copy_deviceid(classdriver_context_t **printer, CFStringRef *deviceID);
+static void copy_devicestring(io_service_t usbInterface, CFStringRef *deviceID, UInt32 *deviceLocation);
+static CFStringRef copy_value_for_key(CFStringRef deviceID, CFStringRef *keys);
+static void parse_options(const char *options, char *serial, UInt32 *location, Boolean *waitEOF);
+static void setup_cfLanguage(void);
+static void *read_thread(void *reference);
+
+
+#if defined(__i386__)
+static pid_t   child_pid;                                      /* Child PID */
+static void run_ppc_backend(int argc, char *argv[], int fd);   /* Starts child backend process running as a ppc executable */
+static void sigterm_handler(int sig);                          /* SIGTERM handler */
+#endif /* __i386__ */
 
+#ifdef PARSE_PS_ERRORS
+static const char *next_line (const char *buffer);
+static void parse_pserror (char *sockBuffer, int len);
+#endif /* PARSE_PS_ERRORS */
 
+#pragma mark -
 
-#if DEBUG==2  
+/*
+ * 'list_devices()' - List all USB devices.
+ */
 
-static char
-hexdigit( char c )
+void list_devices()
 {
-    return ( c < 0 || c > 15 )? '?': (c < 10)? c + '0': c - 10 + 'A';
+  puts("direct usb \"Unknown\" \"USB Printer (usb)\"");
+  iterate_printers(list_device_callback, NULL);
 }
 
-static char
-asciidigit( char c )
-{
-    return (c< 20 || c > 0x7E)? '.': c;
-}
 
-void
-dump( char *text, void *s, int len )
-{
-    int i;
-    char *p = (char *) s;
-    char m[1+2*16+1+16+1];
-
-    fprintf( stderr, "%s pointer %x len %d\n", text, (unsigned int) p, len );
-
-    for ( ; len > 0; len -= 16 )
-    {
-       char *q = p;
-       char *out = m;
-       *out++ = '\t';
-       for ( i = 0; i < 16 && i < len; ++i, ++p )
-       {
-           *out++ = hexdigit( (*p >> 4) & 0x0F );
-                                *out++ = hexdigit( *p & 0x0F );
-       }
-       for ( ;i < 16; ++i )
-       {
-           *out++ = ' ';
-           *out++ = ' ';
-       }
-       *out++ = '\t';
-       for ( i = 0; i < 16 && i < len; ++i, ++q )
-           *out++ = asciidigit( *q );
-       *out = 0;
-       m[ strlen( m ) ] = '\0';
-       fprintf( stderr,  "%s\n", m );
-    }
-}
+/*
+ * 'print_device()' - Print a file to a USB device.
+ */
 
-void 
-printcfs( char *text, CFStringRef s )
+int                                    /* O - Exit status */
+print_device(const char *uri,          /* I - Device URI */
+             const char *hostname,     /* I - Hostname/manufacturer */
+             const char *resource,     /* I - Resource/modelname */
+            const char *options,       /* I - Device options/serial number */
+            int        fd,             /* I - File descriptor to print */
+            int        copies,         /* I - Copies to print */
+            int        argc,           /* I - Number of command-line arguments (6 or 7) */
+            char       *argv[])        /* I - Command-line arguments */
 {
-    char dest[1024];
-    if ( s != NULL )
-    {
-       if ( CFStringGetCString(s, dest, sizeof(dest), kCFStringEncodingUTF8) )
-           sprintf( dest,  "%s <%s>\n", text, dest );
-       else
-           sprintf( dest,  "%s [Unknown string]\n", text );
-    } else {
-       sprintf( dest,  "%s [NULL]\n", text );
+  printer_data_t  printer_data = { 0x0 };              /* Printer context */
+  char           serial[1024];                         /* Serial number buffer */
+  OSStatus       status = noErr;                       /* Function results */
+  pthread_t      thr;                                  /* Read thread */
+  char           buffer[2048];                         /* Write buffer */
+  int            thread_created = 0;                   /* Thread created? */
+  int            countdown = INITIAL_LOG_INTERVAL;     /* Logging interval */
+  pthread_cond_t  *readCompleteConditionPtr = NULL;    /* Read complete condition */
+  pthread_mutex_t *readMutexPtr = NULL;                        /* Read mutex */
+
+  setup_cfLanguage();
+  parse_options(options, serial, &printer_data.location, &printer_data.waitEOF);
+
+  if (resource[0] == '/')
+    resource++;
+
+  printer_data.uri = uri;
+  printer_data.make   = CFStringCreateWithCString(NULL, hostname, kCFStringEncodingUTF8);
+  printer_data.model  = CFStringCreateWithCString(NULL, resource, kCFStringEncodingUTF8);
+  printer_data.serial = CFStringCreateWithCString(NULL, serial, kCFStringEncodingUTF8);
+
+  fputs("STATE: +connecting-to-device\n", stderr);
+
+  do {
+    if (printer_data.printerObj != 0x0) {
+      IOObjectRelease(printer_data.printerObj);                        
+      unload_classdriver(&printer_data.printerDriver);
+      printer_data.printerObj = 0x0;
+      printer_data.printerDriver = 0x0;
     }
-    perror( dest );
-}
 
-void
-cmpcfs( char *text, CFStringRef a, CFStringRef b )
-{
-    CFRange found = {0, 0};
-    
-    printcfs( text, a );
-    printcfs( " ", b );
-
-    if (a != NULL && b != NULL) {
-       found = CFStringFind( a, b, kCFCompareCaseInsensitive );
-    
-    } else if (a == NULL && b == NULL) {
-       found.length = 1;   /* Match */
-       found.location = 0;
-    } else {
-       found.length = 0;   /* No match. */
+    fprintf(stderr, "INFO: Looking for '%s %s'\n", hostname, resource);
+    iterate_printers(find_device_callback, &printer_data);             
+
+    fprintf(stderr, "INFO: Opening Connection\n");
+    status = registry_open(&printer_data);
+#if defined(__i386__)
+    /*
+     * If we were unable to load the class drivers for this printer it's probably because they're ppc-only.
+     * In this case try to fork & exec this backend as a ppc executable so we can use them...
+     */
+    if (status == -2 /* kPMInvalidIOMContext */) {
+      run_ppc_backend(argc, argv, fd);
+      /* Never returns here */
     }
-    
-    if ( found.length > 0 )
-       fprintf( stderr,  "matched @%d:%d\n", (int) found.location, (int) found.length);
-    else
-       fprintf( stderr,  "not matched\n" );
-}
-#endif /*DEBUG==2 */
+#endif /* __i386__ */
+
+    if (status != noErr) {
+      sleep( PRINTER_POLLING_INTERVAL );
+      countdown -= PRINTER_POLLING_INTERVAL;
+      if ( countdown <= 0 ) {
+       fprintf(stderr, "INFO: Printer busy (status:0x%08x)\n", (int)status);
+       countdown = SUBSEQUENT_LOG_INTERVAL;    /* subsequent log entries, every 15 seconds */
+      }
+    }
+  } while (status != noErr);
 
-#ifdef PARSE_PS_ERRORS
-static const char *nextLine (const char *buffer);
-static void parsePSError (char *sockBuffer, int len);
+  fputs("STATE: -connecting-to-device\n", stderr);
 
+  /*
+   * Now that we are "connected" to the port, ignore SIGTERM so that we
+   * can finish out any page data the driver sends (e.g. to eject the
+   * current page...  Only ignore SIGTERM if we are printing data from
+   * stdin (otherwise you can't cancel raw jobs...)
+   */
 
-static const char *nextLine (const char *buffer)
-{
-    const char *cptr, *lptr = NULL;
-    for (cptr = buffer; *cptr && lptr == NULL; cptr++)
-       if (*cptr == '\n' || *cptr == '\r')
-           lptr = cptr;
-    return lptr;
-}
+  if (!fd) {
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+    sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+    memset(&action, 0, sizeof(action));
 
-static void parsePSError (char *sockBuffer, int len)
-{
-    static char         gErrorBuffer[1024] = "";
-    static char *gErrorBufferPtr = gErrorBuffer;
-    static char *gErrorBufferEndPtr = gErrorBuffer + sizeof(gErrorBuffer);
-
-    char *pCommentBegin, *pCommentEnd, *pLineEnd;
-    char *logLevel;
-    char logstr[1024];
-    int         logstrlen;
-
-    if (gErrorBufferPtr + len > gErrorBufferEndPtr - 1)
-       gErrorBufferPtr = gErrorBuffer;
-    if (len > sizeof(gErrorBuffer) - 1)
-       len = sizeof(gErrorBuffer) - 1;
-
-    memcpy(gErrorBufferPtr, (const void *)sockBuffer, len);
-    gErrorBufferPtr += len;
-    *(gErrorBufferPtr + 1) = '\0';
-
-
-    pLineEnd = (char *)nextLine((const char *)gErrorBuffer);
-    while (pLineEnd != NULL)
-    {
-       *pLineEnd++ = '\0';
-
-       pCommentBegin = strstr(gErrorBuffer,"%%[");
-       pCommentEnd = strstr(gErrorBuffer, "]%%");
-       if (pCommentBegin != gErrorBuffer && pCommentEnd != NULL)
-       {
-           pCommentEnd += 3;            /* Skip past "]%%" */
-           *pCommentEnd = '\0';         /* There's always room for the nul */
-
-           if (strncasecmp(pCommentBegin, "%%[ Error:", 10) == 0)
-               logLevel = "DEBUG";
-           else if (strncasecmp(pCommentBegin, "%%[ Flushing", 12) == 0)
-               logLevel = "DEBUG";
-           else
-               logLevel = "INFO";
-           
-           if ((logstrlen = snprintf(logstr, sizeof(logstr), "%s: %s\n", logLevel, pCommentBegin)) >= sizeof(logstr))
-           {
-               /* If the string was trucnated make sure it has a linefeed before the nul */
-               logstrlen = sizeof(logstr) - 1;
-               logstr[logstrlen - 1] = '\n';
-           }
-           write(STDERR_FILENO, logstr, logstrlen);
-       }
+    sigemptyset(&action.sa_mask);
+    action.sa_handler = SIG_IGN;
+    sigaction(SIGTERM, &action, NULL);
+#else
+    signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+  }
 
-       /* move everything over... */
-       strcpy(gErrorBuffer, pLineEnd);
-       gErrorBufferPtr = gErrorBuffer;
-       pLineEnd = (char *)nextLine((const char *)gErrorBuffer);
-    }
-}
-#endif /* PARSE_PS_ERRORS */
+  if (status == noErr) {
+    if (pthread_cond_init(&printer_data.readCompleteCondition, NULL) == 0)     
+      readCompleteConditionPtr = &printer_data.readCompleteCondition;
 
-void *
-readthread( void *reference )
-{
-    /*
-    ** post a read to the device and write results to stdout
-    ** the final pending read will be Aborted in the main thread
-    */
-    UInt8                  readbuffer[512];
-    UInt32                 rbytes;
-    kern_return_t          readstatus;
-    USBPrinterClassContext  **classdriver = (USBPrinterClassContext **) reference;
-
-    
-    do
-    {
-       rbytes = sizeof(readbuffer) - 1;
-       readstatus = (*classdriver)->ReadPipe( classdriver, readbuffer, &rbytes );
-       if ( kIOReturnSuccess == readstatus && rbytes > 0 )
-       {
-           write( STDOUT_FILENO, readbuffer, rbytes );
-           /* cntrl-d is echoed by the printer.
-           * NOTES: 
-           *   Xerox Phaser 6250D doesn't echo the cntrl-d.
-           *   Xerox Phaser 6250D doesn't always send the product query.
-           */
-           if (gWaitEOF && readbuffer[rbytes-1] == 0x4)
-               break;
-#ifdef PARSE_PS_ERRORS
-           parsePSError(readbuffer, rbytes);
-#endif
-       }
-    } while ( gWaitEOF || !done );  /* Abort from main thread tests error here */
+    if (pthread_mutex_init(&printer_data.readMutex, NULL) == 0)
+      readMutexPtr = &printer_data.readMutex;
 
-    /* Let the other thread (main thread) know that we have
-    * completed the read thread...
-    */
-    pthread_mutex_lock(gReadMutexPtr);
-    pthread_cond_signal(gReadCompleteConditionPtr);
-    pthread_mutex_unlock(gReadMutexPtr);
+    if (pthread_create(&thr, NULL, read_thread, &printer_data) == 0)
+      thread_created = 1;
 
-    return NULL;
-}
+    if (thread_created == 0) 
+      fprintf(stderr, "WARNING: Couldn't create read channel\n");
+  }
 
-/*
-* 'print_device()' - Send a file to the specified USB port.
-*/
+  /*
+   * The main thread sends the print file...
+   */
 
-int print_device(const char *uri, const char *hostname, const char *resource, const char *options, int fd, int copies)
-{
-    UInt32     wbytes,         /* Number of bytes written */
-               buffersize = 2048;
-    size_t     nbytes;         /* Number of bytes read */
-    off_t      tbytes;         /* Total number of bytes written */
-    char       *buffer,        /* Output buffer */
-               *bufptr;        /* Pointer into buffer */
-
-   pthread_cond_t   readCompleteCondition;
-   pthread_mutex_t  readMutex;
-   pthread_t       thr;
-   int             thread_created = 0;
-
-    USBPrinterInfo     *targetPrinter = NULL;
-    CFMutableArrayRef  usbPrinters;
-    char               manufacturer_buf[USB_MAX_STR_SIZE],
-                       product_buf[USB_MAX_STR_SIZE],
-                       serial_buf[USB_MAX_STR_SIZE];
-    CFStringRef                manufacturer;
-    CFStringRef                product;
-    CFStringRef                serial;
-
-    OSStatus           status = noErr;
-
-
-    #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
-       struct sigaction action;    /* Actions for POSIX signals */
-    #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-
-    fprintf(stderr, "INFO: Opening the print file and connection...\n");
-
-    parseOptions(options, serial_buf);
-
-    if (resource[0] == '/')
-      resource++;
-
-    removePercentEscapes(hostname,     manufacturer_buf,   sizeof(manufacturer_buf));
-    removePercentEscapes(resource,     product_buf,        sizeof(product_buf));
-
-    manufacturer = CFStringCreateWithCString(NULL, manufacturer_buf, kCFStringEncodingUTF8);
-    product     = CFStringCreateWithCString(NULL, product_buf,      kCFStringEncodingUTF8);
-    serial      = CFStringCreateWithCString(NULL, serial_buf,       kCFStringEncodingUTF8);
-
-    USBPrinterInfo         *activePrinter = NULL;
-    USBPrinterClassContext  **classdriver;
-    int                            countdown = INITIAL_LOG_INTERVAL;
-
-    fputs("STATE: +connecting-to-device\n", stderr);
-
-    do
-    {
-       /* */
-       /*  given a manufacturer and product, bind to a specific printer on the bus */
-       /* */
-       usbPrinters = UsbGetAllPrinters();
-       /* */
-       /*  if we have at least one element of the URI, find a printer module that matches */
-       /* */
-       if ( NULL != usbPrinters && (manufacturer || product ) )
-       {
-           int i,
-               numPrinters =  CFArrayGetCount(usbPrinters);
-           for ( i = 0; i < numPrinters; ++i ) 
-           {
-               int             match = FALSE;
-               USBPrinterInfo  *printer = (USBPrinterInfo *) CFArrayGetValueAtIndex( usbPrinters, i );
-               if ( printer )
-               {
-                   match = printer->address.manufacturer && manufacturer? CFEqual(printer->address.manufacturer, manufacturer ): FALSE;
-                   if ( match )
-                   {
-                       match = printer->address.product && product? CFEqual(printer->address.product, product ): FALSE;
-                   }
-                   if ( match && serial )  
-                   {
-                       /* Note with old queues (pre Panther) the CUPS uri may have no serial number (serial==NULL). */
-                       /*  In this case, we will ignore serial number (as before), and we'll match to the first */
-                       /*  printer that agrees with manufacturer and product. */
-                       /* If the CUPS uri does include a serial number, we'll enter this clause */
-                       /*  which requires the printer's serial number to match the CUPS serial number. */
-                       /* The net effect is that for printers with a serial number, */
-                       /*  new queues must match the serial number, while old queues match any printer  */
-                       /*  that satisfies the manufacturer/product match. */
-                       /* */
-                       match = printer->address.serial? CFEqual(printer->address.serial, serial ): FALSE;
-                   }
-                   if ( match )
-                   {
-                       targetPrinter = UsbCopyPrinter( printer );
-                       break;  /* for, compare partial address to address for each printer on usb bus */
-                   }
-               }
-           }
-       }
-       UsbReleaseAllPrinters( usbPrinters );
-       if ( NULL != targetPrinter )
-           status = UsbRegistryOpen( &targetPrinter->address, &activePrinter );
-
-       if ( NULL == activePrinter )
-       {
-           sleep( PRINTER_POLLING_INTERVAL );
-           countdown -= PRINTER_POLLING_INTERVAL;
-           if ( !countdown )
-           {
-               /* periodically, write to the log so someone knows we're waiting */
-               if (NULL == targetPrinter)
-                   fprintf( stderr, "WARNING: Printer not responding\n" );
-               else
-                   fprintf( stderr, "INFO: Printer busy\n" );
-               countdown = SUBSEQUENT_LOG_INTERVAL;    /* subsequent log entries, every 30 minutes */
-           }
-       }
-    } while ( NULL == activePrinter );
+  while (status == noErr && copies-- > 0) {
+    UInt32             wbytes;                 /* Number of bytes written */
+    ssize_t            nbytes;                 /* Number of bytes read */
+    off_t              tbytes = 0;             /* Total number of bytes written */
 
-    classdriver = activePrinter->classdriver;
-    if ( NULL == classdriver )
-    {
-       perror("ERROR: Unable to open USB Printing Class port");
-       return (status);
-    }
-    
-    fputs("STATE: -connecting-to-device\n", stderr);
+    fprintf(stderr, "INFO: Sending data\n");
 
-    /*
-    * Now that we are "connected" to the port, ignore SIGTERM so that we
-    * can finish out any page data the driver sends (e.g. to eject the
-    * current page...  Only ignore SIGTERM if we are printing data from
-    * stdin (otherwise you can't cancel raw jobs...)
-    */
-    
-    if (fd != 0)
-    {
-#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
-       sigset(SIGTERM, SIG_IGN);
-#elif defined(HAVE_SIGACTION)
-       memset(&action, 0, sizeof(action));
-       
-       sigemptyset(&action.sa_mask);
-       action.sa_handler = SIG_IGN;
-       sigaction(SIGTERM, &action, NULL);
-#else
-       signal(SIGTERM, SIG_IGN);
-#endif /* HAVE_SIGSET */
+    if (STDIN_FILENO != fd) {
+      fputs("PAGE: 1 1", stderr);
+      lseek( fd, 0, SEEK_SET );
     }
 
-    buffer = malloc( buffersize );
-    if ( !buffer ) {
-       fprintf( stderr, "ERROR: Couldn't allocate internal buffer\n" );
-       status = -1;
-    }
-    else
-    {
-       fprintf(stderr, "INFO: Sending the print file...\n");
-       if (pthread_cond_init(&readCompleteCondition, NULL) == 0)
-       {
-           gReadCompleteConditionPtr = &readCompleteCondition;
-           
-           if (pthread_mutex_init(&readMutex, NULL) == 0)
-           {
-               gReadMutexPtr = &readMutex;
-
-               if (pthread_create(&thr, NULL, readthread, classdriver ) > 0)
-                   fprintf(stderr, "WARNING: Couldn't create read channel\n");
-               else
-                   thread_created = 1;
-           }
-       }
-    }
-    /*
-    * the main thread sends the print file...
-    */
-    while (noErr == status && copies > 0)
-    {
-       copies --;
-       if (STDIN_FILENO != fd)
-       {
-           fputs("PAGE: 1 1", stderr);
-           lseek( fd, 0, SEEK_SET );   /* rewind */
+    while (status == noErr && (nbytes = read(fd, buffer, sizeof(buffer))) > 0) {
+      char *bufptr = buffer;
+      tbytes += nbytes;
+
+      while (nbytes > 0 && status == noErr) {
+       wbytes = nbytes;
+       status = (*(printer_data.printerDriver))->WritePipe( printer_data.printerDriver, (UInt8*)bufptr, &wbytes, 0 /* nbytes > wbytes? 0: feof(fp) */ );
+       if (wbytes < 0 || noErr != status) {
+         OSStatus err = (*(printer_data.printerDriver))->Abort(printer_data.printerDriver);
+         fprintf(stderr, "ERROR: %ld: Unable to send print file to printer (canceled:%ld)\n", status, err);
+         break;
        }
 
-       tbytes = 0;
-       while (noErr == status && (nbytes = read(fd, buffer, buffersize)) > 0)
-       {
-           /*
-           * Write the print data to the printer...
-           */
-
-           tbytes += nbytes;
-           bufptr = buffer;
-
-           while (nbytes > 0 && noErr == status )
-           {
-               wbytes = nbytes;
-               status = (*classdriver)->WritePipe( classdriver, (UInt8*)bufptr, &wbytes, 0 /*nbytes > wbytes? 0: feof(fp)*/ );
-               if (wbytes < 0 || noErr != status)
-               {
-                   OSStatus err;
-                   err = (*classdriver)->Abort( classdriver );
-                   fprintf(stderr, "ERROR: %ld: Unable to send print file to printer (canceled %ld)\n", status, err );
-                   break;
-               }
-
-               nbytes -= wbytes;
-               bufptr += wbytes;
-           }
+       nbytes -= wbytes;
+       bufptr += wbytes;
+      }
 
-           if (fd != 0 && noErr == status)
-               fprintf(stderr, "INFO: Sending print file, %qd bytes...\n", (off_t)tbytes);
-       }
-    }
-    done = 1;  /* stop scheduling reads */
-
-    if ( thread_created )
-    {
-       /* Give the read thread WAITEOF_DELAY seconds to complete all the data. If
-       * we are not signaled in that time then force the thread to exit by setting
-       * the waiteof to be false. Plese note that this relies on us using the timeout
-       * class driver.
-       */
-       struct timespec sleepUntil = { time(NULL) + WAITEOF_DELAY, 0 };
-       pthread_mutex_lock(&readMutex);
-       if (pthread_cond_timedwait(&readCompleteCondition, &readMutex, (const struct timespec *)&sleepUntil) != 0)
-           gWaitEOF = false;
-       pthread_mutex_unlock(&readMutex);
-       pthread_join( thr,NULL);                /* wait for the child thread to return */
+      if (fd != 0 && status == noErr)
+       fprintf(stderr, "DEBUG: Sending print file, %qd bytes...\n", (off_t)tbytes);
     }
+  }
 
-    (*classdriver)->Close( classdriver );   /* forces the read to stop incase we are doing a blocking read */
-    UsbUnloadClassDriver( activePrinter );
-    /*
-    * Close the socket connection and input file and return...
-    */
-    free( buffer );
+  if (thread_created) {
+    /* Signal the read thread that we are done... */
+    printer_data.done = 1;
+
+    /* Give the read thread WAITEOF_DELAY seconds to complete all the data. If
+     * we are not signaled in that time then force the thread to exit by setting
+     * the waiteof to be false. Plese note that this relies on us using the timeout
+     * class driver.
+     */
+    struct timespec sleepUntil = { time(NULL) + WAITEOF_DELAY, 0 };
+    pthread_mutex_lock(&printer_data.readMutex);
+    if (pthread_cond_timedwait(&printer_data.readCompleteCondition, &printer_data.readMutex, (const struct timespec *)&sleepUntil) != 0)
+      printer_data.waitEOF = false;
+    pthread_mutex_unlock(&printer_data.readMutex);
+    pthread_join( thr,NULL);                           /* wait for the child thread to return */
+  }
 
-    if (STDIN_FILENO != fd)
-       close(fd);
+  /*
+   * Close the connection and input file and general clean up...
+   */
+  registry_close(&printer_data);
 
-    if (gReadCompleteConditionPtr != NULL)
-       pthread_cond_destroy(gReadCompleteConditionPtr);
-    if (gReadMutexPtr != NULL)
-       pthread_mutex_destroy(gReadMutexPtr);
+  if (STDIN_FILENO != fd)
+    close(fd);
 
-    return status == kIOReturnSuccess? 0: status;
-}
+  if (readCompleteConditionPtr != NULL)
+    pthread_cond_destroy(&printer_data.readCompleteCondition);
 
-static Boolean
-encodecfstr( CFStringRef cfsrc, char *dst, long len )
-{
-    return CFStringGetCString(cfsrc, dst, len, kCFStringEncodingUTF8 );
+  if (readMutexPtr != NULL)
+    pthread_mutex_destroy(&printer_data.readMutex);
+
+  if (printer_data.make != NULL)
+    CFRelease(printer_data.make);
+
+  if (printer_data.model != NULL)
+    CFRelease(printer_data.model);
+
+  if (printer_data.serial != NULL)
+    CFRelease(printer_data.serial);
+
+  if (printer_data.printerObj != 0x0)
+    IOObjectRelease(printer_data.printerObj);
+
+  return status;
 }
 
+#pragma mark -
 /*
-* 'list_devices()' - List all USB devices.
-*/
-void list_devices(void)
+ * 'list_device_callback()' - list_device iterator callback.
+ */
+
+static Boolean list_device_callback(void *refcon, io_service_t obj)
 {
-    char               encodedManufacturer[1024];
-    char               encodedProduct[1024];
-    char               uri[1024];
-    CFMutableArrayRef  usbBusPrinters = UsbGetAllPrinters();
-    CFIndex            i, numPrinters = NULL != usbBusPrinters? CFArrayGetCount( usbBusPrinters ): 0;
-    
-    puts("direct usb \"Unknown\" \"USB Printer (usb)\"");
-    for ( i = 0;  i < numPrinters; ++i )
-    {
-       USBPrinterInfo      *printer = (USBPrinterInfo *) CFArrayGetValueAtIndex( usbBusPrinters, i );
-
-       if ( printer ) 
-       {
-           CFStringRef addressRef = UsbMakeFullUriAddress( printer );
-           if ( addressRef )
-           {
-               if ( CFStringGetCString(addressRef, uri, sizeof(uri), kCFStringEncodingUTF8) ) {
-           
-                   encodecfstr( printer->address.manufacturer, encodedManufacturer, sizeof(encodedManufacturer) );
-                   encodecfstr( printer->address.product, encodedProduct, sizeof(encodedProduct) );
-                   printf("direct %s \"%s %s\" \"%s\"\n", uri, encodedManufacturer, encodedProduct, encodedProduct);
-               }
-           }
-       }
+  Boolean keepRunning = (obj != 0x0);
+
+  if (keepRunning) {
+    CFStringRef deviceIDString = NULL;
+    UInt32 deviceLocation = 0;
+
+    copy_devicestring(obj, &deviceIDString, &deviceLocation);
+    if (deviceIDString != NULL) {
+      CFStringRef make = NULL,  model = NULL, serial = NULL;
+      char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024], optionsstr[1024];
+
+      copy_deviceinfo(deviceIDString, &make, &model, &serial);
+
+      modelstr[0] = '/';
+
+      CFStringGetCString(make, makestr, sizeof(makestr),    kCFStringEncodingUTF8);
+      CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1, kCFStringEncodingUTF8);
+
+      optionsstr[0] = '\0';
+      if (serial != NULL)
+      {
+        CFStringGetCString(serial, serialstr, sizeof(serialstr), kCFStringEncodingUTF8);
+       snprintf(optionsstr, sizeof(optionsstr), "?serial=%s", serialstr);
+      }
+      else if (deviceLocation != 0)
+      {
+       snprintf(optionsstr, sizeof(optionsstr), "?location=%lx", deviceLocation);
+      }
+
+      httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
+      strncat(uristr, optionsstr, sizeof(uristr));
+
+      printf("direct %s \"%s %s\" \"%s\"\n", uristr, makestr, &modelstr[1], &modelstr[1]);
+
+      release_deviceinfo(&make, &model, &serial);
+      CFRelease(deviceIDString);
     }
-    UsbReleaseAllPrinters( usbBusPrinters );
-    fflush(NULL);
+  }
+
+  return keepRunning;
 }
 
 
-static void parseOptions(const char *options, char *serial)
-{
-    char    *serialnumber;  /* ?serial=<serial> or ?location=<location> */
-    char    optionName[255],   /* Name of option */
-           value[255],         /* Value of option */
-           *ptr;               /* Pointer into name or value */
-
-    if (serial)
-       *serial = '\0';
-
-    if (!options)
-       return;
-
-    serialnumber = NULL;
-
-    while (*options != '\0')
-    {
-       /*
-       * Get the name...
-       */
-       for (ptr = optionName; *options && *options != '=' && *options != '+' && *options != '&'; )
-           *ptr++ = *options++;
-
-       *ptr = '\0';
-       value[0] = '\0';
-
-       if (*options == '=')
-       {
-           /*
-           * Get the value...
-           */
-           
-           options ++;
-           
-           for (ptr = value; *options && *options != '+' && *options != '&';)
-               *ptr++ = *options++;
-
-           *ptr = '\0';
-           
-           if (*options == '+' || *options == '&')
-               options ++;
-       }
-       else if (*options == '+' || *options == '&')
-       {
-           options ++;
-       }
+/*
+ * 'find_device_callback()' - print_device iterator callback.
+ */
 
-       /*
-       * Process the option...
-       */
-       if (strcasecmp(optionName, "waiteof") == 0)
-       {
-           if (strcasecmp(value, "on") == 0 ||
-               strcasecmp(value, "yes") == 0 ||
-               strcasecmp(value, "true") == 0)
-           {
-               gWaitEOF = true;
+static Boolean find_device_callback(void *refcon, io_service_t obj)
+{
+  Boolean keepLooking = true;
+
+  if (obj != 0x0 && refcon != NULL) {
+    CFStringRef idString = NULL;
+    UInt32 location = -1;
+    printer_data_t *userData = (printer_data_t *)refcon;
+
+    copy_devicestring(obj, &idString, &location);
+    if (idString != NULL) {
+      CFStringRef make = NULL,  model = NULL, serial = NULL;
+
+      copy_deviceinfo(idString, &make, &model, &serial);
+      if (CFStringCompare(make, userData->make, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
+       if (CFStringCompare(model, userData->model, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
+         if (userData->serial != NULL) {
+           if (serial != NULL && CFStringCompare(model, userData->model, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
+             IOObjectRetain(obj);
+             userData->printerObj = obj;
+             keepLooking = false;
            }
-           else if (strcasecmp(value, "off") == 0 ||
-                   strcasecmp(value, "no") == 0 ||
-                   strcasecmp(value, "false") == 0)
-           {
-               gWaitEOF = false;
+         }
+         else {
+           if (userData->printerObj != 0) {
+             IOObjectRetain(userData->printerObj);
            }
-           else
-           {
-               fprintf(stderr, "WARNING: Boolean expected for waiteof option \"%s\"\n", value);
+           userData->printerObj = obj;
+           IOObjectRetain(obj);
+
+           if (userData->location == 0 || userData->location == location) {
+             keepLooking = false;
            }
+         }
        }
-       else if (strcasecmp(optionName, "serial") == 0 ||
-                strcasecmp(optionName, "location") == 0 )
-       {
-           strcpy(serial, value);
-           serialnumber = serial;
-       }
+      }
+
+      release_deviceinfo(&make, &model, &serial);
+      CFRelease(idString);
     }
+  }
+  else {               
+    keepLooking = (refcon != NULL && ((printer_data_t *)refcon)->printerObj == 0);
+  }
 
-    return;
+  return keepLooking;
 }
 
 
-/*!
- * @function  addPercentEscapes
- * @abstract  Encode a string with percent escapes
- *
- * @param  src     The source C string
- * @param  dst     Desination buffer
- * @param  dstMax   Size of desination buffer
- *
- * @result    A non-zero return value for errors
+#pragma mark -
+/*
+ * 'iterate_printers()' - iterate over all the printers.
  */
-static int addPercentEscapes(const unsigned char* src, char* dst, int dstMax)
+
+static void iterate_printers(iterator_callback_t callBack, void *userdata)
 {
-  unsigned char c;
-  char     *dstEnd = dst + dstMax - 1; /* -1 to leave room for the NUL */
+  mach_port_t  masterPort = 0x0;
+  kern_return_t kr = IOMasterPort (bootstrap_port, &masterPort);
 
-  while (*src)
-  {
-    c = *src++;
+  if (kr == kIOReturnSuccess && masterPort != 0x0) {
+    io_iterator_t addIterator = 0x0;
 
-    if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || 
-       (c >= '0' && c <= '9') || (c == '.' || c == '-'  || c == '*' || c == '_'))
-    {
-      if (dst >= dstEnd)
-       return -1;
+    iterator_reference_t reference = { callBack, userdata, true };
+    IONotificationPortRef addNotification = IONotificationPortCreate(masterPort);
 
-      *dst++ = c;
-    }
-    else
-    {
-      if (dst >= dstEnd - 2)
-       return -1;
+    int klass = kUSBPrintingClass;
+    int subklass = kUSBPrintingSubclass;
+
+    CFNumberRef usb_klass = CFNumberCreate(NULL, kCFNumberIntType, &klass);
+    CFNumberRef usb_subklass = CFNumberCreate(NULL, kCFNumberIntType, &subklass);
+    CFMutableDictionaryRef usbPrinterMatchDictionary = IOServiceMatching(kIOUSBInterfaceClassName);
+
+    CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceClass"), usb_klass);
+    CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceSubClass"), usb_subklass);
 
-      snprintf(dst, dstEnd - dst, "%%%02x", c);
-      dst += 3;
+    CFRelease(usb_klass);
+    CFRelease(usb_subklass);
+
+    kr = IOServiceAddMatchingNotification(addNotification, kIOMatchedNotification, usbPrinterMatchDictionary, &device_added, &reference, &addIterator);
+    if (addIterator != 0x0) {
+      device_added (&reference, addIterator);
+
+      if (reference.keepRunning) {
+       CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(addNotification), kCFRunLoopDefaultMode);
+       CFRunLoopRun();
+      }
+      IOObjectRelease(addIterator);
     }
+    mach_port_deallocate(mach_task_self(), masterPort);
   }
-
-  *dst = '\0';
-  return 0;
 }
 
 
-/*!
- * @function   removePercentEscapes
- * @abstract   Returns a string with any percent escape sequences replaced with their equivalent character
- *
- * @param      src     Source buffer
- * @param      srclen  Number of bytes in source buffer
- * @param      dst     Desination buffer
- * @param      dstMax  Size of desination buffer
- *
- * @result     A non-zero return value for errors
+/*
+ * 'device_added()' - device added notifier.
  */
-static int removePercentEscapes(const char* src, unsigned char* dst, int dstMax)
-{
-    int c;
-    const unsigned char *dstEnd = dst + dstMax;
 
-    while (*src && dst < dstEnd)
-    {
-       c = *src++;
+static void device_added(void *userdata, io_iterator_t iterator)
+{      
+  iterator_reference_t *reference = userdata;
 
-       if (c == '%')
-       {
-           sscanf(src, "%02x", &c);
-           src += 2;
-       }
-       *dst++ = (char)c;
+  io_service_t obj;
+  while (reference->keepRunning && (obj = IOIteratorNext(iterator)) != 0x0) {
+    if (reference->callback != NULL) {
+      reference->keepRunning = reference->callback(reference->userdata, obj);
     }
+    IOObjectRelease(obj);
+  }
 
-    if (dst >= dstEnd)
-       return -1;
+  /* One last call to the call back now that we are not longer have printers left to iterate...
+   */
+  if (reference->keepRunning)
+    reference->keepRunning = reference->callback(reference->userdata, 0x0);
 
-    *dst = '\0';
-    return 0;
+  if (!reference->keepRunning) {
+    CFRunLoopStop(CFRunLoopGetCurrent());
+  }
 }
 
-/*-----------------------------------------------------------------------------*
 
-       DelimitSubstring
+#pragma mark -
+/*
+ * 'copy_deviceinfo()' - Copy strings from the 1284 device ID.
+ */
 
-       Desc:   Search a string from a starting location, looking for a given
-               delimiter. Return the range from the start of the search to the
-               delimiter, or end of string (whichever is shorter).
+static void copy_deviceinfo(CFStringRef deviceIDString, CFStringRef *make, CFStringRef *model, CFStringRef *serial)
+{      
+  CFStringRef modelKeys[]  = { CFSTR("MDL:"), CFSTR("MODEL:"), NULL };
+  CFStringRef makeKeys[]   = { CFSTR("MFG:"), CFSTR("MANUFACTURER:"), NULL };
+  CFStringRef serialKeys[] = { CFSTR("SN:"),  CFSTR("SERN:"), NULL };
+
+  if (make != NULL)
+    *make = copy_value_for_key(deviceIDString, makeKeys);
+  if (model != NULL)
+    *model = copy_value_for_key(deviceIDString, modelKeys);
+  if (serial != NULL)
+    *serial = copy_value_for_key(deviceIDString, serialKeys);
+}
 
-       In:     stringToSearch      string which contains a substring that we search
-               delim               string which marks the end of the string 
-               bounds              start and length of substring of stringToSearch
-               options             case sensitive, anchored, etc.
 
-       Out:    Range up to the delimiter.
+/*
+ * 'release_deviceinfo()' - Release deviceinfo strings.
+ */
 
-*-----------------------------------------------------------------------------*/
-static CFRange
-DelimitSubstring( CFStringRef stringToSearch, CFStringRef delim, CFRange bounds, CFStringCompareFlags options )
+static void release_deviceinfo(CFStringRef *make, CFStringRef *model, CFStringRef *serial)
 {
-    CFRange    where_delim,    /* where the delimiter was found */
-               value;
-    /* */
-    /* trim leading space by changing bounds */
-    /* */
-    while ( bounds.length > 0 && CFStringFindWithOptions( stringToSearch, CFSTR(" "), bounds, kCFCompareAnchored, &where_delim ) )
-    {
-       ++bounds.location;  /* drop a leading ' ' */
-       --bounds.length;
-    }
-    value = bounds;        /* assume match to the end of string, may be NULL */
-    /* */
-    /* find the delimiter in the remaining string */
-    /* */
-    if (  bounds.length > 0 && CFStringFindWithOptions( stringToSearch, delim, bounds, options, &where_delim ) )
-    {
-       /* */
-       /* match to the delimiter */
-       /* */
-       value.length = where_delim.location /* delim */ - bounds.location /* start of search */;
+  if (make != NULL && *make != NULL) {
+    CFRelease(*make);
+    *make = NULL;
+  }
+
+  if (model != NULL && *model != NULL) {
+    CFRelease(*model);
+    *model = NULL;
+  }
+
+  if (serial != NULL && *serial != NULL) {
+    CFRelease(*serial);
+    *serial = NULL;
+  }
+}
+
+
+#pragma mark -
+/*
+ * 'load_classdriver()' - Load a classdriver.
+ */
+
+static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t intf, classdriver_context_t ***printerDriver)
+{
+  kern_return_t kr = kUSBPrinterClassDeviceNotOpen;
+  classdriver_context_t **driver = NULL;
+  CFStringRef bundle = (driverPath == NULL ? kUSBGenericTOPrinterClassDriver : driverPath);
+
+  if ( NULL != bundle ) {
+    CFURLRef url = CFURLCreateWithFileSystemPath(NULL, bundle, kCFURLPOSIXPathStyle, true);
+    CFPlugInRef plugin = (url != NULL ? CFPlugInCreate(NULL, url) : NULL);
+
+    if (url != NULL) 
+      CFRelease(url);
+
+    if (plugin != NULL) {
+      CFArrayRef factories = CFPlugInFindFactoriesForPlugInTypeInPlugIn(kUSBPrinterClassTypeID, plugin);
+      if (factories != NULL && CFArrayGetCount(factories) > 0)  {
+       CFUUIDRef factoryID = CFArrayGetValueAtIndex(factories, 0);
+       IUnknownVTbl **iunknown = CFPlugInInstanceCreate(NULL, factoryID, kUSBPrinterClassTypeID);
+       if (NULL != iunknown) {
+         kr = (*iunknown)->QueryInterface(iunknown, CFUUIDGetUUIDBytes(kUSBPrinterClassInterfaceID), (LPVOID *)&driver);
+         if (kr == kIOReturnSuccess && driver != NULL) {                                       
+           classdriver_context_t **genericDriver = NULL;
+           if (driverPath != NULL && CFStringCompare(driverPath, kUSBGenericTOPrinterClassDriver, 0) != kCFCompareEqualTo) {
+             kr = load_classdriver(NULL, intf, &genericDriver);
+           }
+
+           if (kr == kIOReturnSuccess) {
+             (*driver)->interface = intf;
+             (*driver)->Initialize(driver, genericDriver);
+
+             (*driver)->plugin = plugin;
+             (*driver)->interface = intf;
+             *printerDriver = driver;
+           }
+         }
+         (*iunknown)->Release(iunknown);
+       }
+       CFRelease(factories);
+      }
     }
-    DEBUG_CFString( "\tFind target", stringToSearch );
-    DEBUG_CFString( "\tFind pattern", delim );
-    DEBUG_ERR( (int) value.location, "\t\tFound %d\n" );
-    DEBUG_ERR( (int) value.length, " length %d"         );
+  }
+
+#ifdef DEBUG
+  char bundlestr[1024];
+  CFStringGetCString(bundle, bundlestr, sizeof(bundlestr), kCFStringEncodingUTF8);
+  fprintf(stderr, "DEBUG:load_classdriver(%s) (kr:0x%08x)\n", bundlestr, (int)kr);
+#endif /* DEBUG */
 
-    return value;
+  return kr;
 }
 
 
-/*-----------------------------------------------------------------------------*
+/*
+ * 'unload_classdriver()' - Unload a classdriver.
+ */
 
-       DeviceIDCreateValueList
+static kern_return_t unload_classdriver(classdriver_context_t ***classDriver)
+{
+  if (*classDriver != NULL) {
+    (**classDriver)->Release(*classDriver);
+    *classDriver = NULL;
+  }
 
-       Desc:   Create a new string for the value list of the specified key.
-               The key may be specified as two strings (an abbreviated form
-               and a standard form). NULL can be passed for either form of 
-               the key.
-               
-               (Although passing NULL for both forms of the key is considered
-                bad form[!] it is handled correctly.)
+  return kIOReturnSuccess;
+}
 
-       In:     deviceID    the device's IEEE-1284 DeviceID key-value list
-               abbrevKey   the key we're interested in (NULL allowed)
-               key         
 
-       Out:    CFString    the value list 
-               or NULL     key wasn't found in deviceID
+/*
+ * 'load_printerdriver()' - Load a vendor's (or generic) classdriver.
+ */
 
-*-----------------------------------------------------------------------------*/
-CFStringRef
-DeviceIDCreateValueList( const CFStringRef deviceID, const CFStringRef abbrevKey, const CFStringRef key )
+static kern_return_t load_printerdriver(printer_data_t *printer)
 {
-    CFRange    found = CFRangeMake( -1,0);   /* note CFStringFind sets length 0 if string not found */
-    CFStringRef valueList = NULL;
-
-    DEBUG_CFString( "---------DeviceIDCreateValueList DeviceID:", deviceID );
-    DEBUG_CFString( "---------DeviceIDCreateValueList key:", key );
-    DEBUG_CFString( "---------DeviceIDCreateValueList abbrevkey:", abbrevKey );
-   if ( NULL != deviceID && NULL != abbrevKey )
-       found = CFStringFind( deviceID, abbrevKey, kCFCompareCaseInsensitive );
-    if (  NULL != deviceID && NULL != key && found.length <= 0 )
-       found = CFStringFind( deviceID, key, kCFCompareCaseInsensitive );
-    if ( found.length > 0 )
-    {
-       /* the key is at found */
-       /* the value follows the key until we reach the semi-colon, or end of string */
-       /* */
-       CFRange search = CFRangeMake( found.location + found.length,
-                                 CFStringGetLength( deviceID ) - (found.location + found.length) );
-       /* */
-       /* finally extract the string */
-       /* */
-       valueList = CFStringCreateWithSubstring ( kCFAllocatorDefault, deviceID,
-                                                 DelimitSubstring( deviceID, kDeviceIDKeyValuePairDelimiter, search, kCFCompareCaseInsensitive ) );
-    DEBUG_CFString( "---------DeviceIDCreateValueList:", valueList );
-    }
-    return valueList;
+  IOCFPlugInInterface **iodev = NULL;
+  SInt32 score;
+
+  kern_return_t kr = IOCreatePlugInInterfaceForService(printer->printerObj, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
+  if (kr == kIOReturnSuccess) {
+    printer_interface_t intf;
+    HRESULT res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &intf);
+    if (res == noErr) {
+      CFMutableDictionaryRef properties = NULL;
+
+      kr = IORegistryEntryCreateCFProperties(printer->printerObj, &properties, NULL, kNilOptions);
+      if (kr == kIOReturnSuccess) {
+       CFStringRef driverBundlePath = NULL;
+       if (properties != NULL) {
+         driverBundlePath = (CFStringRef) CFDictionaryGetValue(properties, kUSBClassDriverProperty);
+       }
+       kr = load_classdriver(driverBundlePath, intf, &printer->printerDriver);
+      }
 
+      if (kr != kIOReturnSuccess)
+       (*intf)->Release(intf);
+    }
+    IODestroyPlugInInterface(iodev);
+  }
+  return kr;
 }
 
 
+/*
+ * 'registry_open()' - Open a connection to the printer.
+ */
 
-/******************************************************************************/
+static kern_return_t registry_open(printer_data_t *printer)
+{
+  kern_return_t kr = load_printerdriver(printer);
+  if (kr != kIOReturnSuccess) {
+    kr = -2;
+  }
 
-/*-----------------------------------------------------------------------------*
+  if (printer->printerDriver != NULL) {
+    kr = (*(printer->printerDriver))->Open(printer->printerDriver, printer->location, kUSBPrintingProtocolBidirectional);
+    if (kr != kIOReturnSuccess || (*(printer->printerDriver))->interface == NULL) {
+      kr = (*(printer->printerDriver))->Open(printer->printerDriver, printer->location, kUSBPrintingProtocolUnidirectional);
+      if (kr == kIOReturnSuccess) {
+       if ((*(printer->printerDriver))->interface == NULL) {
+         (*(printer->printerDriver))->Close(printer->printerDriver);
+         kr = -1;
+       }
+      }
+    }
+  }
 
-CompareSameString
+  if (kr != kIOReturnSuccess) {
+    unload_classdriver(&printer->printerDriver);
+  }
 
-Desc:  Return the CFCompare result for two strings, either or both of which
-       can be NULL.
+  return kr;
+}
 
-In:
-       a       current value
-       b       last value
 
-Out:
-       0       if the strings match
-       non-zero    if the strings don't match
+/*
+ * 'registry_close()' - Close the connection to the printer.
+ */
 
-*-----------------------------------------------------------------------------*/
-static int
-CompareSameString( const CFStringRef a, const CFStringRef b )
+static kern_return_t registry_close(printer_data_t *printer)
 {
-    if ( NULL == a && NULL == b )
-       return 0;
-    else if ( NULL != a && NULL != b )
-       return CFStringCompare( a, b, kCFCompareAnchored );
-    else
-       return 1;   /* one of a or b is NULL this time, but wasn't last time */
+  if (printer->printerDriver != NULL) {
+    (*(printer->printerDriver))->Close(printer->printerDriver);
+  }
+  unload_classdriver(&printer->printerDriver);
+  return kIOReturnSuccess;
 }
 
 
-/******************************************************************************/
-kern_return_t
-UsbLoadClassDriver( USBPrinterInfo *printer, CFUUIDRef interfaceID, CFStringRef classDriverBundle )
+/*
+ * 'copy_deviceid()' - Copy the 1284 device id string.
+ */
+
+static OSStatus copy_deviceid(classdriver_context_t **printer, CFStringRef *deviceID)
 {
-    kern_return_t   kr = kUSBPrinterClassDeviceNotOpen;
-    if ( NULL != classDriverBundle )
-       printer->bundle = classDriverBundle;    /* vendor-specific class override */
-    else
-#ifdef TIMEOUT
-       classDriverBundle = kUSBGenericTOPrinterClassDriver;    /*  supply the generic TIMEOUT class driver */
-#else
-       classDriverBundle = kUSBGenericPrinterClassDriver;  /*  supply the generic  class driver */
-#endif
-    DEBUG_CFString( "UsbLoadClassDriver classDriverBundle", classDriverBundle );
-    if ( NULL != classDriverBundle )
-    {
-       USBPrinterClassContext  **classdriver = NULL;
-       CFURLRef                classDriverURL = CFURLCreateWithFileSystemPath( NULL, classDriverBundle, kCFURLPOSIXPathStyle, TRUE );
-       CFPlugInRef             plugin = NULL == classDriverURL? NULL: CFPlugInCreate( NULL, classDriverURL );
-       if ( NULL != plugin)
-       {
-           /* See if this plug-in implements the Test type. */
-           CFArrayRef factories =  CFPlugInFindFactoriesForPlugInTypeInPlugIn( kUSBPrinterClassTypeID, plugin );
-
-           /* If there are factories for the requested type, attempt to */
-           /* get the IUnknown interface. */
-           DEBUG_ERR( 0, "UsbLoadClassDriver plugin %x\n" );
-           if (NULL != factories && CFArrayGetCount(factories) > 0) 
-           {
-               /* Get the factory ID for the first location in the array of IDs. */
-               CFUUIDRef factoryID = CFArrayGetValueAtIndex( factories, 0 );
-               /* Use the factory ID to get an IUnknown interface. */
-               /* Here the code for the PlugIn is loaded. */
-               IUnknownVTbl **iunknown = CFPlugInInstanceCreate( NULL, factoryID, kUSBPrinterClassTypeID );
-               /* If this is an IUnknown interface, query for the Test interface. */
-               DEBUG_ERR( 0, "UsbLoadClassDriver factories %x\n" );
-               if (NULL != iunknown)
-               {
-                   DEBUG_ERR( 0, "UsbLoadClassDriver CFPlugInInstanceCreate %x\n" );
-                   kr = (*iunknown)->QueryInterface( iunknown, CFUUIDGetUUIDBytes(interfaceID), (LPVOID *) &classdriver );
-
-                   (*iunknown)->Release( iunknown );
-                   if ( S_OK == kr && NULL != classdriver )
-                   {
-                       DEBUG_ERR( kr, "UsbLoadClassDriver QueryInterface %x\n" );
-                       printer->plugin = plugin;
-                       kr = (*classdriver)->Initialize( classdriver, printer->classdriver );
-                       
-                       kr = kIOReturnSuccess;
-                       printer->classdriver = classdriver;
-                   }
-                   else
-                   {
-                       DEBUG_ERR( kr, "UsbLoadClassDriver QueryInterface FAILED %x\n" );
-                   }
-               }
-               else
-               {
-                   DEBUG_ERR( kr, "UsbLoadClassDriver CFPlugInInstanceCreate FAILED %x\n" );
-               }
-           }
-           else
-           {
-               DEBUG_ERR( kr, "UsbLoadClassDriver factories FAILED %x\n" );
-           }
+  CFStringRef devID = NULL,
+
+  deviceMake = NULL,
+  deviceModel = NULL,
+  deviceSerial = NULL;
+
+  OSStatus err = (*printer)->GetDeviceID(printer, &devID, DEFAULT_TIMEOUT);
+
+  copy_deviceinfo(devID, &deviceMake, &deviceModel, &deviceSerial);
+
+  if (deviceMake == NULL || deviceModel == NULL || deviceSerial == NULL) {
+    IOUSBDeviceDescriptor      desc;
+    iodevice_request_t         request;
+
+    request.requestType = USBmakebmRequestType( kUSBIn,  kUSBStandard, kUSBDevice );
+    request.request = kUSBRqGetDescriptor;
+    request.value = (kUSBDeviceDesc << 8) | 0;
+    request.index = 0;
+    request.length = sizeof(desc);
+    request.buffer = &desc;
+    err = (*printer)->DeviceRequest(printer, &request, DEFAULT_TIMEOUT);
+    if (err == kIOReturnSuccess) {
+      CFMutableStringRef newDevID = CFStringCreateMutable(NULL, 0);
+
+      if (deviceMake == NULL) {
+       CFStringRef data = NULL;
+       err = (*printer)->GetString(printer, desc.iManufacturer, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
+       if (data != NULL) {
+         CFStringAppendFormat(newDevID, NULL, CFSTR("MFG:%@;"), data);
+         CFRelease(data);
        }
-       else
-       {
-           DEBUG_ERR( kr, "UsbLoadClassDriver plugin FAILED %x\n" );
+      }
+
+      if (deviceModel == NULL) {
+       CFStringRef data = NULL;
+       err = (*printer)->GetString(printer, desc.iProduct, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
+       if (data != NULL) {
+         CFStringAppendFormat(newDevID, NULL, CFSTR("MDL:%@;"), data);
+         CFRelease(data);
        }
-       if ( kr != kIOReturnSuccess || NULL == plugin || NULL == classdriver )
-       {
-           UsbUnloadClassDriver( printer );
+      }
+
+      if (deviceSerial == NULL && desc.iSerialNumber != 0) {
+       CFStringRef data = NULL;
+       err = (*printer)->GetString(printer, desc.iSerialNumber, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
+       if (data != NULL) {
+         CFStringAppendFormat(newDevID, NULL, CFSTR("SERN:%@;"), data);
+         CFRelease(data);
        }
-    }
-    
-    return kr;
-}
+      }
 
+      if (devID != NULL) {
+       CFStringAppend(newDevID, devID);
+       CFRelease(devID);
+      }
 
-kern_return_t
-UsbUnloadClassDriver( USBPrinterInfo *printer )
-{
-    DEBUG_ERR( kIOReturnSuccess, "UsbUnloadClassDriver %x\n" );
-    if ( NULL != printer->classdriver )
-       (*printer->classdriver)->Release( printer->classdriver );
-    printer->classdriver = NULL;
-    
-    if ( NULL != printer->plugin )
-       CFRelease( printer->plugin );
-    printer->plugin = NULL;
-    
-    return kIOReturnSuccess;
-}
+      *deviceID = newDevID;
+    }
+  }
+  else {
+    *deviceID = devID;
+  }
+  release_deviceinfo(&deviceMake, &deviceModel, &deviceSerial);
 
+  return err;
+}
 
-/*-----------------------------------------------------------------------------*
 
-    UsbAddressDispose
+/*
+ * 'copy_devicestring()' - Copy the 1284 device id string.
+ */
 
-    Desc:   deallocates anything used to create a persistent printer address
+static void copy_devicestring(io_service_t usbInterface, CFStringRef *deviceID, UInt32 *deviceLocation)
+{
+  IOCFPlugInInterface **iodev = NULL;
+  SInt32 score;
+
+  kern_return_t kr = IOCreatePlugInInterfaceForService(usbInterface, kIOUSBInterfaceUserClientTypeID, 
+                                                      kIOCFPlugInInterfaceID, &iodev, &score);
+  if (kr == kIOReturnSuccess) {
+    printer_interface_t intf;
+
+    HRESULT res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &intf);
+    if (res == noErr) {
+      /* ignore the result for location id... */
+      (void)(*intf)->GetLocationID(intf, deviceLocation);
+
+      CFMutableDictionaryRef properties = NULL;
+      kr = IORegistryEntryCreateCFProperties(usbInterface, &properties, NULL, kNilOptions);
+      if (kIOReturnSuccess == kr) {
+       classdriver_context_t **klassDriver = NULL;
+       CFStringRef driverBundlePath = NULL;
+
+       if (properties != NULL) {
+         driverBundlePath = (CFStringRef) CFDictionaryGetValue(properties, kUSBClassDriverProperty);
+       }
 
-    In: address            the printer address we've created
+       kr = load_classdriver(driverBundlePath, intf, &klassDriver);
+       if (kr != kIOReturnSuccess && driverBundlePath != NULL)
+         kr = load_classdriver(NULL, intf, &klassDriver);
+       if (kr == kIOReturnSuccess && klassDriver != NULL) {                            
+         kr = copy_deviceid(klassDriver, deviceID);                                            
+       }
+       unload_classdriver(&klassDriver);
 
-    Out:    <none>
+       if (properties != NULL)
+         CFRelease(properties);
+      }
 
-*-----------------------------------------------------------------------------*/
-void
-UsbAddressDispose( USBPrinterAddress *address )
-{
-    if ( address->product != NULL ) CFRelease( address->product );
-    if ( address->manufacturer != NULL ) CFRelease( address->manufacturer );
-    if ( address->serial != NULL ) CFRelease( address->serial );
-    if ( address->command != NULL ) CFRelease( address->command );
+      /* (*intf)->Release(intf); */
+    }          
+    IODestroyPlugInInterface(iodev);
+  }
+}
 
-    address->product =
-    address->manufacturer =
-    address->serial =
-    address->command = NULL;
 
-}
+#pragma mark -
+/*
+ * 'copy_value_for_key()' - Copy value string associated with a key.
+ */
 
-/*-----------------------------------------------------------------------------*
-
-    UsbGetPrinterAddress
-
-    Desc:   Given a printer we're enumerating, discover it's persistent
-    reference.
-
-    A "persistent reference" is one which enables us to identify
-    a printer regardless of where it resides on the USB topology,
-    and enumeration sequence.
-
-    To do this, we actually construct a reference from information
-    buried inside the printer. First we look at the USB device
-    descripton: an ideally defined device will support strings for
-    manufacturer and product id, and serial number. The serial number
-    will be unique for each printer.
-
-    Our prefered identification fetches the IEEE-1284 device id string.
-    This transparently handled IEEE-1284 compatible printers which
-    connected over a USB-parallel cable. Only if we can't get all the
-    information to uniquely identify the printer do we try the strings
-    referenced in the printer's USB device descriptor. (These strings
-    are typically absent in a USB-parallel cable.)
-
-    If a device doesn't support serial numbers we have a problem:
-    we can't distinguish between two identical printers. Unique serial
-    numbers allow us to distinguish between two same-model, same-manufacturer
-    USB printers.
-
-    In:
-       thePrinter      iterator required for fetching device descriptor
-       devRefNum       required to configure the interface
-
-    Out:
-       address->manufacturer
-       address->product
-       address->serial
-               Any (and all) of these may be NULL if we can't retrieve
-               information for IEEE1284 DeviceID or the USB device
-               descriptor. Caller should be prepared to handle such a case.
-       address->command
-               May be updated.
-
-*-----------------------------------------------------------------------------*/
-OSStatus
-UsbGetPrinterAddress( USBPrinterInfo *thePrinter, USBPrinterAddress *address, UInt16 timeout )
+static CFStringRef copy_value_for_key(CFStringRef deviceID, CFStringRef *keys)
 {
+  CFStringRef  value = NULL;
+  CFArrayRef   kvPairs = deviceID != NULL ? CFStringCreateArrayBySeparatingStrings(NULL, deviceID, CFSTR(";")) : NULL;
+  CFIndex      max = kvPairs != NULL ? CFArrayGetCount(kvPairs) : 0;
+  CFIndex      idx = 0;
+
+  while (idx < max && value == NULL) {
+    CFStringRef kvpair = CFArrayGetValueAtIndex(kvPairs, idx);
+    CFIndex idxx = 0;
+    while (keys[idxx] != NULL && value == NULL) {                      
+      CFRange range = CFStringFind(kvpair, keys[idxx], kCFCompareCaseInsensitive);
+      if (range.length != -1) {
+       if (range.location != 0) {
+         CFMutableStringRef theString = CFStringCreateMutableCopy(NULL, 0, kvpair);
+         CFStringTrimWhitespace(theString);
+         range = CFStringFind(theString, keys[idxx], kCFCompareCaseInsensitive);
+         if (range.location == 0) {
+           value = CFStringCreateWithSubstring(NULL, theString, CFRangeMake(range.length, CFStringGetLength(theString) - range.length));
+         }
+         CFRelease(theString);
+       }
+       else {
+         CFStringRef theString = CFStringCreateWithSubstring(NULL, kvpair, CFRangeMake(range.length, CFStringGetLength(kvpair) - range.length));
+         CFMutableStringRef theString2 = CFStringCreateMutableCopy(NULL, 0, theString);
+         CFRelease(theString);
 
-    /* */
-    /* start by assuming the device is not IEEE-1284 compliant */
-    /* and that we can't read in the required strings. */
-    /* */
-    OSStatus               err;
-    CFStringRef                    deviceId = NULL;
-    USBPrinterClassContext  **printer = NULL == thePrinter? NULL: thePrinter->classdriver;
-    
-    address->manufacturer =
-    address->product =
-    address->compatible =
-    address->serial =
-    address->command = NULL;
-
-    DEBUG_DUMP( "UsbGetPrinterAddress thePrinter", thePrinter, sizeof(USBPrinterInfo) );
-
-    err = (*printer)->GetDeviceID( printer, &deviceId, timeout );
-    if ( noErr == err && NULL != deviceId )
-    {
-       /* the strings embedded here are defined in the IEEE1284 spec */
-       /* */
-       /*  use the MFG/MANUFACTURER for the manufacturer */
-       /*  and the MDL/MODEL for the product */
-       /*  there is no serial number defined in IEEE1284 */
-       /*      but it's been observed in recent HP printers */
-       /* */
-       address->command = DeviceIDCreateValueList( deviceId, kDeviceIDKeyCommandAbbrev, kDeviceIDKeyCommand );
-
-       address->product = DeviceIDCreateValueList( deviceId, kDeviceIDKeyModelAbbrev, kDeviceIDKeyModel );
-       address->compatible = DeviceIDCreateValueList( deviceId, kDeviceIDKeyCompatibleAbbrev, kDeviceIDKeyCompatible );
-
-       address->manufacturer = DeviceIDCreateValueList( deviceId, kDeviceIDKeyManufacturerAbbrev, kDeviceIDKeyManufacturer );
-
-       address->serial = DeviceIDCreateValueList( deviceId, kDeviceIDKeySerialAbbrev, kDeviceIDKeySerial );
-       CFRelease( deviceId );
-    }
-    DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->product", address->product );
-    DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->compatible", address->compatible );
-    DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->manufacturer", address->manufacturer );
-    DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->serial", address->serial );
-
-    if ( NULL == address->product || NULL == address->manufacturer || NULL == address->serial )
-    {
-       /* */
-       /*  if the manufacturer or the product or serial number were not specified in DeviceID */
-       /*      try to construct the address using USB English string descriptors */
-       /* */
-       IOUSBDeviceDescriptor   desc;
-       USBIODeviceRequest      request;
-                               
-       request.requestType = USBmakebmRequestType( kUSBIn,  kUSBStandard, kUSBDevice );
-       request.request = kUSBRqGetDescriptor;
-       request.value = (kUSBDeviceDesc << 8) | 0;
-       request.index = 0;  /* not kUSBLanguageEnglish*/
-       request.length = sizeof(desc);
-       request.buffer = &desc;
-       err = (*printer)->DeviceRequest( printer, &request, timeout );
-       DEBUG_ERR( (kern_return_t) err, "UsbGetPrinterAddress: GetDescriptor %x" );
-       if ( kIOReturnSuccess == err )
-       {
-           /* once we've retrieved the device descriptor */
-           /*  try to fill in missing pieces of information */
-           /* */
-           /*  Don't override any information already retrieved from DeviceID. */
-
-           if ( NULL == address->product)
-           {
-               err = (*printer)->GetString( printer, desc.iProduct, kUSBLanguageEnglish, timeout, &address->product );
-               if ( kIOReturnSuccess != err || address->product == NULL) {
-                   address->product = CFSTR("Unknown");
-               }                
-           }
-           DEBUG_CFString( "UsbGetPrinterAddress: UsbGetString address->product\n", address->product );
-
-           if ( NULL == address->manufacturer )
-           {
-               err = (*printer)->GetString( printer, desc.iManufacturer, kUSBLanguageEnglish, timeout, &address->manufacturer );
-               if (kIOReturnSuccess != err || address->manufacturer == NULL) {
-                   address->manufacturer = CFSTR("Unknown");
-               }
-           }
-           DEBUG_CFString( "UsbGetPrinterAddress: UsbGetString address->manufacturer\n", address->manufacturer );
-
-           if ( NULL == address->serial )
-           {
-               /* if the printer doesn't have a serial number, use locationId */
-               if ( 0 == desc.iSerialNumber )
-               {
-                   address->serial = CFStringCreateWithFormat( NULL, NULL, CFSTR("%lx"), (*printer)->location );
-               }
-               else
-               {
-                   err = (*printer)->GetString( printer, desc.iSerialNumber, kUSBLanguageEnglish, timeout, &address->serial );
-                   /* trailing NULs aren't handled correctly in URI */
-                   if ( address->serial )
-                   {
-                       UniChar     nulbyte = { 0 };
-                       CFStringRef trim = CFStringCreateWithCharacters(NULL, &nulbyte, 1);
-                       CFMutableStringRef newserial = CFStringCreateMutableCopy(NULL, 0, address->serial);
-
-                       CFStringTrim( newserial, trim );
-
-                       CFRelease(trim);
-                       CFRelease( address->serial );
-
-                       address->serial = newserial;
-                   }
-               }
-           }
-           DEBUG_CFString( "UsbGetPrinterAddress: UsbGetString address->serial\n", address->serial );
+         CFStringTrimWhitespace(theString2);
+         value = theString2;
        }
+      }
+      idxx++;
     }
-    if ( NULL != address->product)
-       CFRetain(address->product);         /* UsbGetString is really a UsbCopyString. */
-    if ( NULL != address->manufacturer )
-       CFRetain( address->manufacturer );
-    if ( NULL != address->serial )
-       CFRetain( address->serial );
-    return err;
+    idx++;
+  }
+
+  if (kvPairs != NULL)
+    CFRelease(kvPairs);        
+  return value;
 }
 
 
-/*-----------------------------------------------------------------------------*
+#pragma mark -
+/*
+ * 'parse_options()' - Parse uri options.
+ */
 
-UsbSamePrinter
+static void parse_options(const char *options, char *serial, UInt32 *location, Boolean *waitEOF)
+{
+  char *serialnumber;          /* ?serial=<serial> or ?location=<location> */
+  char optionName[255],        /* Name of option */
+       value[255],             /* Value of option */
+       *ptr;                   /* Pointer into name or value */
 
-       Desc:   match two Usb printer address; return TRUE if they are the same.
+  if (serial)
+    *serial = '\0';
+  if (location)
+    *location = 0;
 
-       In:     a   the persistent address found last time
-               b   the persistent address found this time
+  if (!options)
+    return;
 
-       Out:    non-zero iff the addresses are the same
+  serialnumber = NULL;
 
-*-----------------------------------------------------------------------------*/
-int
-UsbSamePrinter( const USBPrinterAddress *a, const USBPrinterAddress *b )
-{
-    int result = 0;
-    DEBUG_CFCompareString( "UsbSamePrinter serial", a->serial, b->serial );
-    DEBUG_CFCompareString( "UsbSamePrinter product", a->product, b->product );
-    DEBUG_CFCompareString( "UsbSamePrinter manufacturer", a->manufacturer, b->manufacturer );
+  while (*options != '\0') {
+    /* Get the name... */
+    for (ptr = optionName; *options && *options != '=' && *options != '+'; )
+      *ptr++ = *options++;
 
-    result = !CompareSameString( a->serial, b->serial );
-    if ( result )  result = !CompareSameString( a->product, b->product );
-    if ( result ) result = !CompareSameString( a->manufacturer, b->manufacturer );
+    *ptr = '\0';
+    value[0] = '\0';
 
-    return result;
-}
+    if (*options == '=') {
+      /* Get the value... */
+      options ++;
 
+      for (ptr = value; *options && *options != '+';)
+       *ptr++ = *options++;
 
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    Method:    UsbMakeFullUriAddress
+      *ptr = '\0';
 
-    Input Parameters:
+      if (*options == '+')
+       options ++;
+    }
+    else if (*options == '+') {
+      options ++;
+    }
 
-    Output Parameters:
+    /*
+     * Process the option...
+     */
+    if (strcasecmp(optionName, "waiteof") == 0) {
+      if (strcasecmp(value, "on") == 0 ||
+         strcasecmp(value, "yes") == 0 ||
+         strcasecmp(value, "true") == 0) {
+       *waitEOF = true;
+      }
+      else if (strcasecmp(value, "off")   == 0 ||
+              strcasecmp(value, "no")    == 0 ||
+              strcasecmp(value, "false") == 0) {
+       *waitEOF = false;
+      }
+      else {
+       fprintf(stderr, "WARNING: Boolean expected for waiteof option \"%s\"\n", value);
+      }
+    }
+    else if (strcasecmp(optionName, "serial") == 0) {
+      strcpy(serial, value);
+      serialnumber = serial;
+    }
+    else if (strcasecmp(optionName, "location") == 0 && location) {
+      *location = strtol(value, NULL, 16);
+    }
+  }
 
-    Description:
-       Fill in missing address information
+  return;
+}
 
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-CFStringRef
-UsbMakeFullUriAddress( USBPrinterInfo *printer )
-{
-    /* */
-    /* fill in missing address information. */
-    /* */
-    CFMutableStringRef printerUri = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("usb://") );
-    if ( NULL != printerUri )
-    {
-       CFStringRef serial = printer->address.serial;
 
-       CFStringAppend(printerUri, printer->address.manufacturer? CreateEncodedCFString( printer->address.manufacturer ): CFSTR("Unknown") );
-       CFStringAppend(printerUri, CFSTR("/") );
+/*!
+ * @function   setup_cfLanguage
+ * @abstract   Convert the contents of the CUPS 'LANG' environment
+ *             variable into a one element CF array of languages.
+ *
+ * @discussion Each submitted job comes with a natural language. CUPS passes
+ *             that language in an environment variable. We take that language
+ *             and jam it into the AppleLanguages array so that CF will use
+ *             it when reading localized resources. We need to do this before
+ *             any CF code reads and caches the languages array, so this function
+ *             should be called early in main()
+ */
+static void setup_cfLanguage(void)
+{
+  CFStringRef  lang[1] = {NULL};
+  CFArrayRef   langArray = NULL;
+  const char   *requestedLang = NULL;
+
+  requestedLang = getenv("LANG");
+  if (requestedLang != NULL) {
+    lang[0] = CFStringCreateWithCString(kCFAllocatorDefault, requestedLang, kCFStringEncodingUTF8);
+    langArray = CFArrayCreate(kCFAllocatorDefault, (const void **)lang, sizeof(lang) / sizeof(lang[0]), &kCFTypeArrayCallBacks);
+
+    CFPreferencesSetAppValue(CFSTR("AppleLanguages"), langArray, kCFPreferencesCurrentApplication);
+    DEBUG_printf((stderr, "DEBUG: usb: AppleLanguages = \"%s\"\n", requestedLang));
+
+    CFRelease(lang[0]);
+    CFRelease(langArray);
+  } else {
+    fprintf(stderr, "DEBUG: usb: LANG environment variable missing.\n");
+  }
+}
 
-       CFStringAppend(printerUri, printer->address.product? CreateEncodedCFString( printer->address.product ): CFSTR("Unknown") );
+#pragma mark -
+#if defined(__i386__)
+/*!
+ * @function   run_ppc_backend
+ *
+ * @abstract   Starts child backend process running as a ppc executable.
+ *
+ * @result     Never returns; always calls exit().
+ *
+ * @discussion 
+ */
+static void run_ppc_backend(int argc, char *argv[], int fd)
+{
+  int  i;
+  int  exitstatus = 0;
+  int  childstatus;
+  pid_t        waitpid_status;
+  char *my_argv[32];
+  char *usb_ppc_status;
 
-       /*Handle the common case where there is no serial number (S450?) */
-       CFStringAppend(printerUri, serial == NULL? CFSTR("?location="): CFSTR("?serial=") );
-       if ( serial == NULL)
-           serial = CFStringCreateWithFormat( NULL, NULL, CFSTR("%lx"), printer->location );
+  /*
+   * If we're running as i386 and couldn't load the class driver (because they'it's
+   * ppc-only) then try to re-exec ourselves in ppc mode to try again. If we don't have
+   * a ppc architecture we may be running i386 again so guard against this by setting
+   * and testing an environment variable...
+   */
+  usb_ppc_status = getenv("USB_PPC_STATUS");
+
+  if (usb_ppc_status == NULL) {
+    /* Catch SIGTERM if we are _not_ printing data from
+     * stdin (otherwise you can't cancel raw jobs...)
+     */
 
-        CFStringAppend(printerUri,  serial? CreateEncodedCFString( serial ): CFSTR("Unknown") );
+    if (fd != 0) {
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+      sigset(SIGTERM, sigterm_handler);
+#elif defined(HAVE_SIGACTION)
+      struct sigaction action; /* Actions for POSIX signals */
+      memset(&action, 0, sizeof(action));
+      sigaddset(&action.sa_mask, SIGTERM);
+      action.sa_handler = sigterm_handler;
+      sigaction(SIGTERM, &action, NULL);
+#else
+      signal(SIGTERM, sigterm_handler);
+#endif /* HAVE_SIGSET */
     }
-    
-    return printerUri;
-}
 
+    if ((child_pid = fork()) == 0) {
+      /* Child comes here. */
+      setenv("USB_PPC_STATUS", "1", false);
 
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    Method:    UsbGetAllPrinters
+      /* Tell the kernel we want the next exec call to favor the ppc architecture... */
+      int mib[] = { CTL_KERN, KERN_AFFINITY, 1, 1 };
+      int namelen = 4;
+      sysctl(mib, namelen, NULL, NULL, NULL, 0);
 
-    Input Parameters:
+      /* Set up the arguments and call exec... */
+      for (i = 0; i < argc && i < (sizeof(my_argv)/sizeof(my_argv[0])) - 1; i++)
+       my_argv[i] = argv[i];
 
-    Output Parameters:
-       array of all USB printers on the system
+      my_argv[i] = NULL;
 
-    Description:
-       Build a list of USB printers by iterating IOKit USB objects
+      execv("/usr/libexec/cups/backend/usb", my_argv);
 
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-CFMutableArrayRef
-UsbGetAllPrinters( void )
-{
-    kern_return_t      kr;     /* kernel errors */
-    mach_port_t                master_device_port = 0;
-    io_service_t       usbInterface = 0;
-    io_iterator_t      iter = 0;
-    CFMutableArrayRef  printers = CFArrayCreateMutable( NULL, 0, NULL );   /* all printers */
-
-    do
-    {
-
-       kr = IOMasterPort( bootstrap_port, &master_device_port );
-       DEBUG_ERR( kr, "UsbGetAllPrinters IOMasterPort %x\n" );
-       if(kIOReturnSuccess != kr)  break;
-
-       {
-           CFDictionaryRef     usbMatch = NULL;
-           
-           /* iterate over all interfaces.  */
-           usbMatch = IOServiceMatching(kIOUSBInterfaceClassName);
-           if ( !usbMatch ) break;
-           DEBUG_ERR( kr, "UsbGetAllPrinters IOServiceMatching %x\n" );
-       
-           /* IOServiceGetMatchingServices() consumes the usbMatch reference so we don't need to release it. */
-           kr = IOServiceGetMatchingServices(master_device_port, usbMatch, &iter);
-           usbMatch = NULL;
-           
-           DEBUG_ERR( kr, "UsbGetAllPrinters IOServiceGetMatchingServices %x\n" );
-           if(kIOReturnSuccess != kr || iter == NULL)  break;
-       }
-       
-       while (  NULL != (usbInterface = IOIteratorNext(iter))  )
-       {
-           IOCFPlugInInterface     **iodev;
-           USBPrinterInterface     intf;
-           HRESULT                 res;
-           SInt32                  score;
-           CFMutableDictionaryRef  properties;
-           CFStringRef             classDriver = NULL;
-
-           kr = IORegistryEntryCreateCFProperties( usbInterface, &properties, kCFAllocatorDefault, kNilOptions);
-           if ( kIOReturnSuccess == kr && NULL != properties)
-           {
-               classDriver = (CFStringRef) CFDictionaryGetValue( properties, kUSBClassDriverProperty );
-               if ( NULL != classDriver )
-                   CFRetain( classDriver );
-               CFRelease( properties );
-           }    
-
-           kr = IOCreatePlugInInterfaceForService( usbInterface,
-                                                       kIOUSBInterfaceUserClientTypeID, 
-                                                       kIOCFPlugInInterfaceID,
-                                                       &iodev,
-                                                       &score);
-               
-           DEBUG_ERR( kr, "UsbGetAllPrinters IOCreatePlugInInterfaceForService %x\n" );
-           if ( kIOReturnSuccess == kr )
-           {
-               UInt8               intfClass = 0;
-               UInt8               intfSubClass = 0;
-               res = (*iodev)->QueryInterface( iodev, USB_INTERFACE_KIND, (LPVOID *) &intf);
-               DEBUG_ERR( (kern_return_t) res, "UsbGetAllPrinters QueryInterface %x\n" );
-
-              (*iodev)->Release(iodev);
-               if ( noErr != res ) break;
-               kr = (*intf)->GetInterfaceClass(intf, &intfClass);
-               DEBUG_ERR(kr, "UsbGetAllPrinters GetInterfaceClass %x\n");
-               if ( kIOReturnSuccess == kr )
-                   kr = (*intf)->GetInterfaceSubClass(intf, &intfSubClass);
-               DEBUG_ERR(kr, "UsbGetAllPrinters GetInterfaceSubClass %x\n");
-               
-               if ( kIOReturnSuccess == kr &&
-                       kUSBPrintingClass == intfClass &&
-                       kUSBPrintingSubclass == intfSubClass )
-               {
-
-                   USBPrinterInfo          printer,
-                                           *printerInfo;
-                   /*
-                   For each type of printer specified in the lookup spec array, find
-                   all of that type of printer and add the results to the list of found
-                   printers.
-                   */
-                   /* create this printer's persistent address */
-                   memset( &printer, 0, sizeof(USBPrinterInfo) );
-                   kr = (*intf)->GetLocationID(intf, &printer.location);
-                   DEBUG_ERR(kr, "UsbGetAllPrinters GetLocationID %x\n");
-                   if ( kIOReturnSuccess == kr )
-                   {
-                       kr = UsbLoadClassDriver( &printer, kUSBPrinterClassInterfaceID, classDriver );
-                       DEBUG_ERR(kr, "UsbGetAllPrinters UsbLoadClassDriver %x\n");
-                       if ( kIOReturnSuccess == kr && printer.classdriver )
-                       {
-                           (*(printer.classdriver))->interface = intf;
-                           kr = UsbGetPrinterAddress( &printer, &printer.address, 60000L );
-                           { 
-                               /* always unload the driver */
-                               /*  but don't mask last error */
-                               kern_return_t unload_err = UsbUnloadClassDriver( &printer );
-                               if ( kIOReturnSuccess == kr )
-                                   kr = unload_err;
-                           }
-                       }
-                   }
-                   
-                   printerInfo = UsbCopyPrinter( &printer );
-                   if ( NULL != printerInfo )
-                       CFArrayAppendValue( printers, (const void *) printerInfo );     /* keep track of it */
-
-                } /* if there's a printer */
-               kr = (*intf)->Release(intf);
-           } /* if IOCreatePlugInInterfaceForService */
-           
-           IOObjectRelease(usbInterface);
-           usbInterface = NULL;
-           
-       } /* while there's an interface */
-    } while ( 0 );
-
-    if (iter) 
-    {
-       IOObjectRelease(iter);
-       iter = 0;
+      fprintf(stderr, "DEBUG: execv: %s\n", strerror(errno));
+      exitstatus = errno;
     }
-
-    if (master_device_port) 
-    {
-       mach_port_deallocate(mach_task_self(), master_device_port);
-       master_device_port = 0;
+    else if (child_pid > 0) {
+      /* Parent comes here. 
+       *
+       * Close the fds we won't be using then wait for the child backend to exit.
+       */
+      close(fd);
+      close(1);
+
+      fprintf(stderr, "DEBUG: Started usb(ppc) backend (PID %d)\n", (int)child_pid);
+
+      while ((waitpid_status = waitpid(child_pid, &childstatus, 0)) == (pid_t)-1 && errno == EINTR)
+        usleep(1000);
+
+      if (WIFSIGNALED(childstatus)) {
+       exitstatus = WTERMSIG(childstatus);
+       fprintf(stderr, "DEBUG: usb(ppc) backend %d crashed on signal %d!\n", child_pid, exitstatus);
+      }
+      else {
+       if ((exitstatus = WEXITSTATUS(childstatus)) != 0)
+         fprintf(stderr, "DEBUG: usb(ppc) backend %d stopped with status %d!\n", child_pid, exitstatus);
+       else
+         fprintf(stderr, "DEBUG: PID %d exited with no errors\n", child_pid);
+      }
     }
-    return printers;
-
-} /* UsbGetAllPrinters */
-
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    Method:    UsbReleasePrinter
+    else {
+      /* fork() error */
+      fprintf(stderr, "DEBUG: fork: %s\n", strerror(errno));
+      exitstatus = errno;
+    }
+  }
+  else {
+    fprintf(stderr, "DEBUG: usb child running i386 again\n");
+    exitstatus = ENOENT;
+  }
 
-    Input Parameters:
+  exit(exitstatus);
+}
 
-    Output Parameters:
+/*
+ * 'sigterm_handler()' - SIGTERM handler.
+ */
 
-    Description:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-void
-UsbReleasePrinter( USBPrinterInfo *printer )
+static void sigterm_handler(int sig)
 {
-    if ( printer )
-    {
-       UsbUnloadClassDriver( printer );
-       if ( NULL != printer->address.manufacturer )
-           CFRelease( printer->address.manufacturer );
-       if ( NULL != printer->address.product )
-           CFRelease( printer->address.product );
-       if ( NULL != printer->address.serial )
-           CFRelease( printer->address.serial );
-       if ( NULL != printer->address.command )
-           CFRelease( printer->address.command );
-       if ( NULL != printer->bundle )
-           CFRelease( printer->bundle );
-       free( printer );
-   }
+  /* If we started a child process pass the signal on to it...
+   */
+  if (child_pid)
+    kill(child_pid, sig);
+
+  exit(1);
 }
 
-/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-    Method:    UsbReleaseAllPrinters
+#endif /* __i386__ */
 
-    Input Parameters:
 
-    Output Parameters:
+#ifdef PARSE_PS_ERRORS
+/*
+ * 'next_line()' - Find the next line in a buffer.
+ */
 
-    Description:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-void
-UsbReleaseAllPrinters( CFMutableArrayRef printers )
+static const char *next_line (const char *buffer)
 {
-    if ( NULL != printers )
-    {
-       CFIndex i,
-               numPrinters = CFArrayGetCount(printers);
-       for ( i = 0; i < numPrinters; ++i ) 
-           UsbReleasePrinter( (USBPrinterInfo *) CFArrayGetValueAtIndex( printers, i ) );
-       CFRelease( printers );          
-    }
-}
+  const char *cptr, *lptr = NULL;
 
-USBPrinterInfo *
-UsbCopyPrinter( USBPrinterInfo *aPrinter )
-{
-    /* */
-    /* note this does not copy interface information, just address information */
-    /* */
-    USBPrinterInfo *printerInfo = (USBPrinterInfo *) calloc( 1, sizeof(USBPrinterInfo));
-    if ( NULL != printerInfo && NULL != aPrinter )
-    {
-       printerInfo->location = aPrinter->location;
-       if ( NULL != (printerInfo->address.manufacturer = aPrinter->address.manufacturer) )
-           CFRetain( printerInfo->address.manufacturer );
-       if ( NULL != (printerInfo->address.product = aPrinter->address.product) )
-           CFRetain( printerInfo->address.product );
-       if ( NULL != (printerInfo->address.serial = aPrinter->address.serial) )
-           CFRetain( printerInfo->address.serial );
-       if ( NULL != (printerInfo->address.command = aPrinter->address.command) )
-           CFRetain( printerInfo->address.command );
-       if ( NULL != (printerInfo->bundle = aPrinter->bundle) )
-           CFRetain( printerInfo->bundle );
-    }
-    
-    return printerInfo;
+  for (cptr = buffer; *cptr && lptr == NULL; cptr++)
+    if (*cptr == '\n' || *cptr == '\r')
+      lptr = cptr;
+  return lptr;
 }
 
-/*-----------------------------------------------------------------------------*
-
-       UsbRegistryOpen
 
-       Desc:   opens the USB printer which matches the supplied printerAddress
-
-       In:     myContext->printerAddress   persistent name which identifies the printer
+/*
+ * 'parse_pserror()' - Scan the backchannel data for postscript errors.
+ */
 
-       Out:    myContext->usbDeviceRef     current IOKit address of this printer
-*-----------------------------------------------------------------------------*/
-kern_return_t
-UsbRegistryOpen( USBPrinterAddress *usbAddress, USBPrinterInfo **result )
+static void parse_pserror (char *sockBuffer, int len)
 {
-    kern_return_t      kr = -1;    /* indeterminate failure */
-    CFMutableArrayRef  printers = UsbGetAllPrinters();
-    CFIndex            numPrinters = NULL != printers? CFArrayGetCount( printers): 0;
-    CFIndex            i;
-
-    *result = NULL; /* nothing matched */
-    for ( i = 0; i < numPrinters; ++i )
-    {
-       USBPrinterInfo  *thisPrinter = (USBPrinterInfo *) CFArrayGetValueAtIndex( printers, i );
-       if (  NULL != thisPrinter && UsbSamePrinter( usbAddress, &thisPrinter->address ) ) 
-       {
-           *result = UsbCopyPrinter( thisPrinter );    /* retains reference */
-           if ( NULL != *result )
-           {
-               /* */
-               /*  if we can't find a bi-di interface, settle for a known uni-directional interface */
-               /* */
-               USBPrinterClassContext **printer = NULL;
-               /* */
-               /*  setup the default class driver */
-               /*  If one is specified, allow the vendor driver to override our default implementation */
-               /* */
-               kr = UsbLoadClassDriver( *result, kUSBPrinterClassInterfaceID, NULL );
-               if ( kIOReturnSuccess == kr && (*result)->bundle )
-                   kr = UsbLoadClassDriver( *result, kUSBPrinterClassInterfaceID, (*result)->bundle );
-               if ( kIOReturnSuccess == kr && NULL != (*result)->classdriver )
-               {
-                   printer = (*result)->classdriver;
-                   kr = (*printer)->Open( printer, (*result)->location, kUSBPrintingProtocolBidirectional );
-                   if ( kIOReturnSuccess != kr || NULL == (*printer)->interface )
-                       kr = (*printer)->Open( printer, (*result)->location, kUSBPrintingProtocolUnidirectional );
-                   /*  it's possible kIOReturnSuccess == kr && NULL == (*printer)->interface */
-                   /*      in the event that we can't open either Bidirectional or Unidirectional interface */
-                   if ( kIOReturnSuccess == kr )
-                   {
-                       if ( NULL == (*printer)->interface )
-                       {
-                           (*printer)->Close( printer );
-                           UsbReleasePrinter( *result );
-                           *result = NULL;
-                       }
-                   }
-               }
-           }
-           break;
-       }
+  static char  gErrorBuffer[1024] = "";
+  static char *gErrorBufferPtr = gErrorBuffer;
+  static char *gErrorBufferEndPtr = gErrorBuffer + sizeof(gErrorBuffer);
+
+  char *pCommentBegin, *pCommentEnd, *pLineEnd;
+  char *logLevel;
+  char logstr[1024];
+  int  logstrlen;
+
+  if (gErrorBufferPtr + len > gErrorBufferEndPtr - 1)
+    gErrorBufferPtr = gErrorBuffer;
+  if (len > sizeof(gErrorBuffer) - 1)
+    len = sizeof(gErrorBuffer) - 1;
+
+  memcpy(gErrorBufferPtr, (const void *)sockBuffer, len);
+  gErrorBufferPtr += len;
+  *(gErrorBufferPtr + 1) = '\0';
+
+
+  pLineEnd = (char *)next_line((const char *)gErrorBuffer);
+  while (pLineEnd != NULL) {
+    *pLineEnd++ = '\0';
+
+    pCommentBegin = strstr(gErrorBuffer,"%%[");
+    pCommentEnd = strstr(gErrorBuffer, "]%%");
+    if (pCommentBegin != gErrorBuffer && pCommentEnd != NULL) {
+      pCommentEnd += 3;            /* Skip past "]%%" */
+      *pCommentEnd = '\0';         /* There's always room for the nul */
+
+      if (strncasecmp(pCommentBegin, "%%[ Error:", 10) == 0)
+       logLevel = "DEBUG";
+      else if (strncasecmp(pCommentBegin, "%%[ Flushing", 12) == 0)
+       logLevel = "DEBUG";
+      else
+       logLevel = "INFO";
+
+      if ((logstrlen = snprintf(logstr, sizeof(logstr), "%s: %s\n", logLevel, pCommentBegin)) >= sizeof(logstr)) {
+       /* If the string was trucnated make sure it has a linefeed before the nul */
+       logstrlen = sizeof(logstr) - 1;
+       logstr[logstrlen - 1] = '\n';
+      }
+      write(STDERR_FILENO, logstr, logstrlen);
     }
-    UsbReleaseAllPrinters( printers ); /* but, copied printer is retained */
-    DEBUG_ERR( kr, "UsbRegistryOpen return %x\n" );
 
-    return kr;
+    /* move everything over... */
+    strcpy(gErrorBuffer, pLineEnd);
+    gErrorBufferPtr = gErrorBuffer;
+    pLineEnd = (char *)next_line((const char *)gErrorBuffer);
+  }
 }
+#endif /* PARSE_PS_ERRORS */
 
-/*!
- * @function   CreateEncodedCFString
- *
- * @abstract   Create an encoded version of the string parameter 
- *             so that it can be included in a URI.
- *
- * @param   string  A CFStringRef of the string to be encoded.
- * @result  An encoded CFString.
- *
- * @discussion This function will change all characters in string into URL acceptable format
- *             by encoding the text using the US-ASCII coded character set.  The following
- *             are invalid characters: the octets 00-1F, 7F, and 80-FF hex.  Also called out
- *             are the chars "<", ">", """, "#", "{", "}", "|", "\", "^", "~", "[", "]", "`".
- *             The reserved characters for URL syntax are also to be encoded: (so don't pass
- *             in a full URL here!) ";", "/", "?", ":", "@", "=", "%", and "&".
+
+/*
+ * 'read_thread()' - A thread to read the backchannel data.
  */
-static CFStringRef CreateEncodedCFString(CFStringRef string)
+
+static void *read_thread(void *reference)
 {
-    CFStringRef result = NULL;
-    char *bufferUTF8 = NULL;
-    char *bufferEncoded = NULL;
-
-    if (string != NULL)
-    {
-       CFIndex bufferSizeUTF8 = (3 * CFStringGetLength(string));
-       if ((bufferUTF8 = (char*)malloc(bufferSizeUTF8)) != NULL)
-       {
-           CFStringGetCString(string, bufferUTF8, bufferSizeUTF8, kCFStringEncodingUTF8);
-           {
-               UInt16 bufferSizeEncoded = (3 * strlen(bufferUTF8)) + 1;
-               if ((bufferEncoded = (char*)malloc(bufferSizeEncoded)) != NULL)
-               {
-                   addPercentEscapes(bufferUTF8, bufferEncoded, bufferSizeEncoded);
-                   result = CFStringCreateWithCString(kCFAllocatorDefault, bufferEncoded, kCFStringEncodingUTF8);
-               }
-           }
-       }
+  /* post a read to the device and write results to stdout
+   * the final pending read will be Aborted in the main thread
+   */
+  UInt8                                readbuffer[512];
+  UInt32                       rbytes;
+  kern_return_t                        readstatus;
+  printer_data_t               *userData = (printer_data_t *)reference;
+  classdriver_context_t        **classdriver = userData->printerDriver;
+  struct mach_timebase_info    timeBaseInfo;
+  uint64_t                     start,
+                               delay;
+
+  /* Calculate what 250 milliSeconds are in mach absolute time...
+   */
+  mach_timebase_info(&timeBaseInfo);
+  delay = ((uint64_t)250000000 * (uint64_t)timeBaseInfo.denom) / (uint64_t)timeBaseInfo.numer;
+
+  do {
+    /* Remember when we started so we can throttle the loop after the read call...
+     */
+    start = mach_absolute_time();
+
+    rbytes = sizeof(readbuffer) - 1;
+    readstatus = (*classdriver)->ReadPipe( classdriver, readbuffer, &rbytes );
+    if ( kIOReturnSuccess == readstatus && rbytes > 0 ) {
+
+      cupsBackChannelWrite((char*)readbuffer, rbytes, 1.0);
+
+      /* cntrl-d is echoed by the printer.
+       * NOTES: 
+       *   Xerox Phaser 6250D doesn't echo the cntrl-d.
+       *   Xerox Phaser 6250D doesn't always send the product query.
+       */
+      if (userData->waitEOF && readbuffer[rbytes-1] == 0x4)
+       break;
+#ifdef PARSE_PS_ERRORS
+      parse_pserror(readbuffer, rbytes);
+#endif
     }
 
-    if (bufferUTF8)    free(bufferUTF8);
-    if (bufferEncoded) free(bufferEncoded);
+    /* Make sure this loop executes no more than once every 250 miliseconds...
+     */
+    if ((readstatus != kIOReturnSuccess || rbytes == 0) && (userData->waitEOF || !userData->done))
+      mach_wait_until(start + delay);
+
+  } while ( userData->waitEOF || !userData->done );    /* Abort from main thread tests error here */
 
-    return result;
+  /* Let the other thread (main thread) know that we have completed the read thread...
+   */
+  pthread_mutex_lock(&userData->readMutex);
+  pthread_cond_signal(&userData->readCompleteCondition);
+  pthread_mutex_unlock(&userData->readMutex);
+
+  return NULL;
 }
 
+
 /*
- * End of "$Id: usb-darwin.c 5241 2006-03-07 22:07:44Z mike $".
+ * End of "$Id: usb-darwin.c 5373 2006-04-06 20:03:32Z mike $".
  */
index ae302a0962fc48b904fa87d1057dba56a198f235..f3d1c3d51a90a4ef6f3a256191938e5541094fc8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: usb-unix.c 5259 2006-03-09 19:22:36Z mike $"
+ * "$Id: usb-unix.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   USB port backend for the Common UNIX Printing System (CUPS).
  *
@@ -56,7 +56,9 @@ print_device(const char *uri,         /* I - Device URI */
              const char *resource,     /* I - Resource/modelname */
             const char *options,       /* I - Device options/serial number */
             int        fp,             /* I - File descriptor to print */
-            int        copies)         /* I - Copies to print */
+            int        copies,         /* I - Copies to print */
+            int        argc,           /* I - Number of command-line arguments (6 or 7) */
+            char       *argv[])        /* I - Command-line arguments */
 {
   int          fd;                     /* USB device */
   int          rbytes;                 /* Number of bytes read */
@@ -77,6 +79,8 @@ print_device(const char *uri,         /* I - Device URI */
   unsigned int status;                 /* Port status (off-line, out-of-paper, etc.) */
 #endif /* __linux */
 
+  (void)argc;
+  (void)argv;
 
  /*
   * Open the USB port device...
@@ -618,5 +622,5 @@ open_device(const char *uri)                /* I - Device URI */
 
 
 /*
- * End of "$Id: usb-unix.c 5259 2006-03-09 19:22:36Z mike $".
+ * End of "$Id: usb-unix.c 5373 2006-04-06 20:03:32Z mike $".
  */
index ede0292d74a901079c5206e2d57e17244f9f7305..6665f282ed5b4db8175e98c67a34818ee999c2a1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: usb.c 5162 2006-02-24 03:15:13Z mike $"
+ * "$Id: usb.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   USB port backend for the Common UNIX Printing System (CUPS).
  *
@@ -63,7 +63,7 @@
 void   list_devices(void);
 int    print_device(const char *uri, const char *hostname,
                     const char *resource, const char *options,
-                    int fp, int copies);
+                    int fp, int copies, int argc, char *argv[]);
 
 
 /*
@@ -109,7 +109,9 @@ print_device(const char *uri,               /* I - Device URI */
              const char *resource,     /* I - Resource/modelname */
             const char *options,       /* I - Device options/serial number */
             int        fp,             /* I - File descriptor to print */
-            int        copies)         /* I - Copies to print */
+            int        copies,         /* I - Copies to print */
+            int        argc,           /* I - Number of command-line arguments (6 or 7) */
+            char       *argv[])        /* I - Command-line arguments */
 {
  /*
   * Can't print, so just reference the arguments to eliminate compiler
@@ -124,6 +126,8 @@ print_device(const char *uri,               /* I - Device URI */
   (void)options;
   (void)fp;
   (void)copies;
+  (void)argc;
+  (void)argv;
 
   return (CUPS_BACKEND_FAILED);
 }
@@ -251,7 +255,7 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
   * Finally, send the print file...
   */
 
-  status = print_device(uri, hostname, resource, options, fp, copies);
+  status = print_device(uri, hostname, resource, options, fp, copies, argc, argv);
 
  /*
   * Close the input file and return...
@@ -265,5 +269,5 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
 
 
 /*
- * End of "$Id: usb.c 5162 2006-02-24 03:15:13Z mike $".
+ * End of "$Id: usb.c 5373 2006-04-06 20:03:32Z mike $".
  */
index 8d738aaedcebc987edda4cd131a285e01f659535..c063fa6ce3d00eca94bed6eb623f97b808f63382 100644 (file)
@@ -1,5 +1,5 @@
 #
-# "$Id: mime.types 4590 2005-08-24 19:25:49Z mike $"
+# "$Id: mime.types 5375 2006-04-06 20:10:55Z mike $"
 #
 #   MIME types file for the Common UNIX Printing System (CUPS).
 #
@@ -77,7 +77,9 @@ application/postscript                ai eps ps string(0,%!) string(0,<04>%!) \
                                (contains(0,1024,"LANGUAGE=POSTSCRIPT") \
                                 contains(0,1024,"LANGUAGE = Postscript") \
                                 contains(0,1024,"LANGUAGE = PostScript") \
-                                contains(0,1024,"LANGUAGE = POSTSCRIPT"))
+                                contains(0,1024,"LANGUAGE = POSTSCRIPT") \
+                                (contains(0,1024,<0a>%!) + \
+                                 !contains(0,1024,"ENTER LANGUAGE")))
 application/vnd.hp-HPGL                hpgl string(0,<1B>&)\
                                string(0,<1B>E<1B>%0B) \
                                string(0,<1B>%-1B) string(0,<201B>)\
@@ -165,5 +167,5 @@ application/vnd.cups-raw    (string(0,<1B>E) + !string(2,<1B>%0B)) \
 #application/octet-stream
 
 #
-# End of "$Id: mime.types 4590 2005-08-24 19:25:49Z mike $".
+# End of "$Id: mime.types 5375 2006-04-06 20:10:55Z mike $".
 #
index 3a6f251095199dc875f947b4eb6b8e2a0c6c5b7e..50394fa312f095e8b500575929f6e7ab60b9eb93 100644 (file)
@@ -111,13 +111,21 @@ AC_SUBST(CUPS_IMPLICIT_CLASSES)
 
 dnl Default UseNetworkDefault
 AC_ARG_ENABLE(network_default, [  --enable-use-network-default
-                          enable UseNetworkDefault by default, default=yes])
-if test "x$enable_network_default" = xno; then
+                          enable UseNetworkDefault by default, default=auto])
+if test "x$enable_network_default" != xno; then
+       AC_MSG_CHECKING(whether to use network default printers)
+       if test "x$enable_network_default" = xyes -o $uname != Darwin; then
+               CUPS_USE_NETWORK_DEFAULT="Yes"
+               AC_DEFINE_UNQUOTED(CUPS_DEFAULT_USE_NETWORK_DEFAULT, 1)
+               AC_MSG_RESULT(yes)
+       else
+               CUPS_USE_NETWORK_DEFAULT="No"
+               AC_DEFINE_UNQUOTED(CUPS_DEFAULT_USE_NETWORK_DEFAULT, 0)
+               AC_MSG_RESULT(no)
+       fi
+else
        CUPS_USE_NETWORK_DEFAULT="No"
        AC_DEFINE_UNQUOTED(CUPS_DEFAULT_USE_NETWORK_DEFAULT, 0)
-else
-       CUPS_USE_NETWORK_DEFAULT="Yes"
-       AC_DEFINE_UNQUOTED(CUPS_DEFAULT_USE_NETWORK_DEFAULT, 1)
 fi
 AC_SUBST(CUPS_USE_NETWORK_DEFAULT)
 
@@ -148,12 +156,7 @@ AC_ARG_WITH(cups-group, [  --with-cups-group       set default group for CUPS],
        CUPS_GROUP="$withval",
        AC_MSG_CHECKING(for default print group)
        if test -f /etc/group; then
-               if test x$uname = xDarwin; then
-                       GROUP_LIST="nobody"
-               else
-                       GROUP_LIST="lp nobody"
-               fi
-
+               GROUP_LIST="lp nobody"
                CUPS_GROUP=""
                for group in $GROUP_LIST; do
                        if test "`grep \^${group}: /etc/group`" != ""; then
@@ -215,6 +218,22 @@ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_USER, "$CUPS_USER")
 AC_DEFINE_UNQUOTED(CUPS_DEFAULT_GROUP, "$CUPS_GROUP")
 AC_DEFINE_UNQUOTED(CUPS_DEFAULT_SYSTEM_GROUPS, "$CUPS_SYSTEM_GROUPS")
 
+dnl Default printcap file...
+AC_ARG_WITH(printcap, [  --with-printcap     set default printcap file],
+       default_printcap="$withval",
+       default_printcap="/etc/printcap")
+
+if test x$enable_printcap != xno -a x$default_printcap != xno; then
+       if test "x$default_printcap" = "x/etc/printcap" -a "$uname" = "Darwin" -a $uversion -ge 90; then
+               CUPS_DEFAULT_PRINTCAP=""
+       else
+               CUPS_DEFAULT_PRINTCAP="$default_printcap"
+       fi
+else
+       CUPS_DEFAULT_PRINTCAP=""
+fi
+
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_PRINTCAP, "$CUPS_DEFAULT_PRINTCAP")
 
 dnl
 dnl End of "$Id$".
index 911a9e8eb12e1d583376999c585d40705aec0bf7..b7de6e72ac8205f25874211362964ade24f58000 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: config.h.in 5157 2006-02-23 20:58:57Z mike $"
+ * "$Id: config.h.in 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Configuration file for the Common UNIX Printing System (CUPS).
  *
 #define CUPS_DEFAULT_IPP_PORT  631
 
 
+/*
+ * Default printcap file...
+ */
+
+#define CUPS_DEFAULT_PRINTCAP  "/etc/printcap"
+
+
 /*
  * Maximum number of file descriptors to support.
  */
 #endif /* !_CUPS_CONFIG_H_ */
 
 /*
- * End of "$Id: config.h.in 5157 2006-02-23 20:58:57Z mike $".
+ * End of "$Id: config.h.in 5373 2006-04-06 20:03:32Z mike $".
  */
index 15654e7b352c763127e253e8335ca47a412bd6c9..299ca6a44e7ef1d4ff61821531e7a20a9a7d16e7 100644 (file)
@@ -1,5 +1,5 @@
 dnl
-dnl "$Id: configure.in 5310 2006-03-19 03:23:34Z mike $"
+dnl "$Id: configure.in 5377 2006-04-06 20:39:41Z mike $"
 dnl
 dnl   Configuration script for the Common UNIX Printing System (CUPS).
 dnl
@@ -26,7 +26,6 @@ AC_INIT(cups/cups.h)
 
 sinclude(config-scripts/cups-opsys.m4)
 sinclude(config-scripts/cups-common.m4)
-sinclude(config-scripts/cups-defaults.m4)
 sinclude(config-scripts/cups-directories.m4)
 sinclude(config-scripts/cups-manpages.m4)
 
@@ -43,6 +42,7 @@ sinclude(config-scripts/cups-pam.m4)
 sinclude(config-scripts/cups-threads.m4)
 sinclude(config-scripts/cups-largefile.m4)
 sinclude(config-scripts/cups-launchd.m4)
+sinclude(config-scripts/cups-defaults.m4)
 sinclude(config-scripts/cups-pdf.m4)
 sinclude(config-scripts/cups-scripting.m4)
 
@@ -59,5 +59,5 @@ AC_OUTPUT(Makedefs packaging/cups.list init/cups.sh init/cups-lpd cups-config
 chmod +x cups-config
 
 dnl
-dnl End of "$Id: configure.in 5310 2006-03-19 03:23:34Z mike $".
+dnl End of "$Id: configure.in 5377 2006-04-06 20:39:41Z mike $".
 dnl
index 8aab5f27d673e24136353e318383a35275b6ca19..ec46217f12588a3e40d58e04914f03053d540c9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: encode.c 5332 2006-03-23 21:29:42Z mike $"
+ * "$Id: encode.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Option encoding routines for the Common UNIX Printing System (CUPS).
  *
@@ -364,7 +364,7 @@ cupsEncodeOptions2(
     * Copy the name over...
     */
 
-    if ((attr->name = strdup(option->name)) == NULL)
+    if ((attr->name = _cupsStrAlloc(option->name)) == NULL)
     {
      /*
       * Ran out of memory!
@@ -515,14 +515,14 @@ cupsEncodeOptions2(
            */
 
             attr->values[j].unknown.length = strlen(val);
-           attr->values[j].unknown.data   = strdup(val);
+           attr->values[j].unknown.data   = _cupsStrAlloc(val);
 
             DEBUG_printf(("cupsEncodeOptions2: Added octet-string value \"%s\"...\n",
                          attr->values[j].unknown.data));
             break;
 
        default :
-            if ((attr->values[j].string.text = strdup(val)) == NULL)
+            if ((attr->values[j].string.text = _cupsStrAlloc(val)) == NULL)
            {
             /*
              * Ran out of memory!
@@ -537,6 +537,9 @@ cupsEncodeOptions2(
             break;
       }
     }
+
+    if (copy)
+      free(copy);
   }
 }
 
@@ -554,5 +557,5 @@ compare_ipp_options(_ipp_option_t *a,       /* I - First option */
 
 
 /*
- * End of "$Id: encode.c 5332 2006-03-23 21:29:42Z mike $".
+ * End of "$Id: encode.c 5373 2006-04-06 20:03:32Z mike $".
  */
index 65427b4f0a52b2dac004d2804d8460f774132cc9..b7dbbf3480b1310b114303c5721d8e253059bfd2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: globals.c 5366 2006-04-02 16:11:04Z mike $"
+ * "$Id: globals.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Global variable access routines for the Common UNIX Printing System (CUPS).
  *
@@ -175,6 +175,9 @@ globals_destructor(void *value)             /* I - Data to free */
   for (i = 0; i < 3; i ++)
     cupsFileClose(cg->stdio_files[i]);
 
+  if (cg->last_status_message)
+    free(cg->last_status_message);
+
   cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);
 
   free(value);
@@ -223,5 +226,5 @@ _cupsGlobals(void)
 
 
 /*
- * End of "$Id: globals.c 5366 2006-04-02 16:11:04Z mike $".
+ * End of "$Id: globals.c 5373 2006-04-06 20:03:32Z mike $".
  */
index 0f66ed8c6b8e36016c8388703edf6000824b3f9e..0a2927f6aa07e9fa1dff552e329fac0589fca6da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: http-private.h 5049 2006-02-02 14:50:57Z mike $"
+ * "$Id: http-private.h 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Private HTTP definitions for the Common UNIX Printing System (CUPS).
  *
@@ -100,6 +100,15 @@ typedef struct
 
 typedef SSLConnectionRef http_tls_t;
 
+typedef union _cdsa_conn_ref_u         /**** CDSA Connection reference union
+                                        **** used to resolve 64-bit casting
+                                        **** warnings.
+                                        ****/
+{
+  SSLConnectionRef connection;         /* SSL connection pointer */
+  int             sock;                /* Socket */
+} cdsa_conn_ref_t;
+
 extern OSStatus        _httpReadCDSA(SSLConnectionRef connection, void *data,
                              size_t *dataLength);
 extern OSStatus        _httpWriteCDSA(SSLConnectionRef connection, const void *data,
@@ -123,5 +132,5 @@ extern const char *hstrerror(int error);
 #endif /* !_CUPS_HTTP_PRIVATE_H_ */
 
 /*
- * End of "$Id: http-private.h 5049 2006-02-02 14:50:57Z mike $".
+ * End of "$Id: http-private.h 5373 2006-04-06 20:03:32Z mike $".
  */
index 59a402339d10d0369d4f07ed254e860f434f5f52..a8ec36a02829fa59cf6d3d8d476af17ce8e157a1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: http.c 5282 2006-03-13 12:10:33Z mike $"
+ * "$Id: http.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   HTTP routines for the Common UNIX Printing System (CUPS).
  *
@@ -1388,11 +1388,15 @@ _httpReadCDSA(
     void             *data,            /* I  - Data buffer */
     size_t           *dataLength)      /* IO - Number of bytes */
 {
-  OSStatus     result;                 /* Return value */
-  ssize_t      bytes;                  /* Number of bytes read */
+  OSStatus       result;               /* Return value */
+  ssize_t        bytes;                /* Number of bytes read */
+  cdsa_conn_ref_t u;                   /* Connection reference union */
+
+
+  u.connection = connection;
 
   do
-    bytes = recv((int)connection, data, *dataLength, 0);
+    bytes = recv(u.sock, data, *dataLength, 0);
   while (bytes == -1 && errno == EINTR);
 
   if (bytes == *dataLength)
@@ -1962,11 +1966,15 @@ _httpWriteCDSA(
     const void       *data,            /* I  - Data buffer */
     size_t           *dataLength)      /* IO - Number of bytes */
 {
-  OSStatus     result;                 /* Return value */
-  ssize_t      bytes;                  /* Number of bytes read */
+  OSStatus       result;               /* Return value */
+  ssize_t        bytes;                /* Number of bytes read */
+  cdsa_conn_ref_t u;                   /* Connection reference union */
+
+
+  u.connection = connection;
 
   do
-    bytes = write((int)connection, data, *dataLength);
+    bytes = write(u.sock, data, *dataLength);
   while (bytes == -1 && errno == EINTR);
 
   if (bytes == *dataLength)
@@ -2295,13 +2303,24 @@ http_setup_ssl(http_t *http)            /* I - HTTP connection */
   conn->credentials = credentials;
 
 #  elif defined(HAVE_CDSASSL)
+  cdsa_conn_ref_t  u;                  /* Connection reference union */
+
+
   error = SSLNewContext(false, &conn);
 
   if (!error)
     error = SSLSetIOFuncs(conn, _httpReadCDSA, _httpWriteCDSA);
 
   if (!error)
-    error = SSLSetConnection(conn, (SSLConnectionRef)http->fd);
+  {
+   /*
+    * Use a union to resolve warnings about int/pointer size mismatches...
+    */
+
+    u.connection = NULL;
+    u.sock       = http->fd;
+    error        = SSLSetConnection(conn, u.connection);
+  }
 
   if (!error)
     error = SSLSetAllowsExpiredCerts(conn, true);
@@ -2758,5 +2777,5 @@ http_write_ssl(http_t     *http,  /* I - HTTP connection */
 
 
 /*
- * End of "$Id: http.c 5282 2006-03-13 12:10:33Z mike $".
+ * End of "$Id: http.c 5373 2006-04-06 20:03:32Z mike $".
  */
index fa11f87cb69b30819f042ca52d02e471983d308a..6990d912759c7c05e034a4ca6bac1f3f004af904 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: language.c 5366 2006-04-02 16:11:04Z mike $"
+ * "$Id: language.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   I18N/language support for the Common UNIX Printing System (CUPS).
  *
@@ -31,7 +31,6 @@
  *   cupsLangEncoding()     - Return the character encoding (us-ascii, etc.)
  *                            for the given language.
  *   cupsLangFlush()        - Flush all language data out of the cache.
- *   _cupsLangFlush()       - Flush all language data out of the cache.
  *   cupsLangFree()         - Free language data.
  *   cupsLangGet()          - Get a language.
  *   _cupsLangString()      - Get a message string.
@@ -1296,5 +1295,5 @@ cups_unquote(char       *d,               /* O - Unquoted string */
 
 
 /*
- * End of "$Id: language.c 5366 2006-04-02 16:11:04Z mike $".
+ * End of "$Id: language.c 5373 2006-04-06 20:03:32Z mike $".
  */
index 33b7a0df6bf6d3f8e23fa63c25004532149fdb41..bdcdc9971a364e04518d1c48a200c1aa03d67a77 100644 (file)
@@ -1,6 +1,6 @@
 *PPD-Adobe: "4.3"
 *%
-*% "$Id: test.ppd 5257 2006-03-09 15:27:27Z mike $"
+*% "$Id: test.ppd 5372 2006-04-05 18:25:34Z mike $"
 *%
 *%   Test PPD file for the Common UNIX Printing System (CUPS).
 *%
 *OpenUI IntOption/Integer: PickOne
 *OrderDependency: 10 AnySetup *IntOption
 *DefaultIntOption: None
+*IntOption None: ""
 *IntOption 1: "IntOption=1"
 *IntOption 2: "IntOption=2"
 *IntOption 3: "IntOption=3"
 *OpenUI StringOption/String: PickOne
 *OrderDependency: 10 AnySetup *StringOption
 *DefaultStringOption: None
+*StringOption None: ""
 *StringOption foo: "StringOption=foo"
 *StringOption bar: "StringOption=bar"
 *CloseUI: *StringOption
 *Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM
 *Font ZapfDingbats: Special "(001.004S)" Standard ROM
 *%
-*% End of "$Id: test.ppd 5257 2006-03-09 15:27:27Z mike $".
+*% End of "$Id: test.ppd 5372 2006-04-05 18:25:34Z mike $".
 *%
index 8e9f3133b241ba3fa9853cb2f9e2de78dbe2e4cf..c7384d9cb8501d4e1e44858cb6e179c49558db4e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: transcode.c 5366 2006-04-02 16:11:04Z mike $"
+ * "$Id: transcode.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Transcoding support for the Common UNIX Printing System (CUPS).
  *
@@ -49,6 +49,7 @@
 
 #include "globals.h"
 #include "debug.h"
+#include <limits.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <time.h>
@@ -1584,5 +1585,5 @@ get_vbcs_charmap(
 
 
 /*
- * End of "$Id: transcode.c 5366 2006-04-02 16:11:04Z mike $"
+ * End of "$Id: transcode.c 5373 2006-04-06 20:03:32Z mike $"
  */
index d417c9b54faa3b09c6781a3fb3e60a181539707a..4f512fc0dc90afb5684d6409e3e51159a3efcc12 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: imagetops.c 5099 2006-02-13 02:46:10Z mike $"
+ * "$Id: imagetops.c 5379 2006-04-07 13:48:37Z mike $"
  *
  *   Image file to PostScript filter for the Common UNIX Printing System (CUPS).
  *
@@ -873,7 +873,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
           }
 
           printf("<<"
-                 "/cupsImageType 1"
+                 "/ImageType 1"
                 "/Width %d"
                 "/Height %d"
                 "/BitsPerComponent 8",
@@ -892,12 +892,12 @@ main(int  argc,                           /* I - Number of command-line arguments */
                break;
           }
 
-          fputs("/DataSource currentfile /ASCII85Decode filter", stdout);
+          fputs("\n/DataSource currentfile/ASCII85Decode filter", stdout);
 
           if (((xc1 - xc0 + 1) / xprint) < 100.0)
             fputs("/Interpolate true", stdout);
 
-          puts("/cupsImageMatrix[1 0 0 -1 0 1]>>image");
+          puts("/ImageMatrix[1 0 0 -1 0 1]>>image");
 
           for (y = yc0, out_offset = 0; y <= yc1; y ++)
           {
@@ -1063,5 +1063,5 @@ ps_ascii85(cups_ib_t *data,               /* I - Data to print */
 
 
 /*
- * End of "$Id: imagetops.c 5099 2006-02-13 02:46:10Z mike $".
+ * End of "$Id: imagetops.c 5379 2006-04-07 13:48:37Z mike $".
  */
index 4be6621553430017249c04c8d984f84d9e8d5216..305c798d85421f29a0c83d099d678b234882b7da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: pstops.c 5369 2006-04-03 15:09:58Z mike $"
+ * "$Id: pstops.c 5382 2006-04-07 14:58:44Z mike $"
  *
  *   PostScript filter for the Common UNIX Printing System (CUPS).
  *
@@ -56,6 +56,7 @@
  */
 
 #include "common.h"
+#include <limits.h>
 #include <math.h>
 #include <cups/file.h>
 #include <cups/array.h>
@@ -437,12 +438,10 @@ check_range(pstops_doc_t *doc,            /* I - Document information */
     * See if we only print even or odd pages...
     */
 
-    if (!strcasecmp(doc->page_set, "even") &&
-        ((page - 1) % (doc->number_up << 1)) < doc->number_up)
+    if (!strcasecmp(doc->page_set, "even") && (page & 1))
       return (0);
 
-    if (!strcasecmp(doc->page_set, "odd") &&
-        ((page - 1) % (doc->number_up << 1)) >= doc->number_up)
+    if (!strcasecmp(doc->page_set, "odd") && !(page & 1))
       return (0);
   }
 
@@ -795,7 +794,7 @@ copy_dsc(cups_file_t  *fp,          /* I - File to read from */
   * Finish up the last page(s)...
   */
 
-  if (number && is_not_last_page(number))
+  if (number && is_not_last_page(number) && cupsArrayLast(doc->pages))
   {
     pageinfo = (pstops_page_t *)cupsArrayLast(doc->pages);
 
@@ -1286,98 +1285,118 @@ copy_page(cups_file_t  *fp,            /* I - File to read from */
   * Copy any page setup commands...
   */
 
-  if (!strncmp(line, "%%BeginPageSetup", 16))
+  if (first_page)
   {
-   /*
-    * Copy page setup commands...
-    */
-
-    doc_write(doc, line, linelen);
+    doc_puts(doc, "%%BeginPageSetup\n");
 
-    while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0)
+    if (pageinfo->num_options > 0)
     {
-      if (!strncmp(line, "%%EndPageSetup", 14))
-        break;
-      else if (!strncmp(line, "%%Include", 9))
-        continue;
+      int              i;              /* Looping var */
+      ppd_option_t     *option;        /* PPD option */
+      int              min_order;      /* Minimum OrderDependency value */
+      char             *doc_setup,     /* DocumentSetup commands to send */
+                       *any_setup;     /* AnySetup commands to send */
 
-      if (doc->number_up == 1 && !doc->fitplot)
-       doc_write(doc, line, linelen);
-    }
 
-   /*
-    * Skip %%EndPageSetup...
-    */
+     /*
+      * Yes, figure out the minimum OrderDependency value...
+      */
 
-    if (linelen > 0)
-      linelen = cupsFileGetLine(fp, line, linesize);
+      if ((option = ppdFindOption(ppd, "PageRegion")) != NULL)
+       min_order = option->order;
+      else
+       min_order = 999.0f;
 
-    if (pageinfo->num_options == 0)
-      doc_puts(doc, "%%EndPageSetup\n");
-  }
-  else if (first_page && pageinfo->num_options > 0)
-    doc_puts(doc, "%%BeginPageSetup\n");
+      for (i = 0; i < pageinfo->num_options; i ++)
+       if ((option = ppdFindOption(ppd, pageinfo->options[i].name)) != NULL &&
+            option->order < min_order)
+          min_order = option->order;
 
-  if (first_page && pageinfo->num_options > 0)
-  {
-    int                i;                      /* Looping var */
-    ppd_option_t *option;              /* PPD option */
-    int                min_order;              /* Minimum OrderDependency value */
-    char       *doc_setup,             /* DocumentSetup commands to send */
-               *any_setup;             /* AnySetup commands to send */
+     /*
+      * Mark and extract them...
+      */
 
+      cupsMarkOptions(ppd, pageinfo->num_options, pageinfo->options);
 
-   /*
-    * Yes, figure out the minimum OrderDependency value...
-    */
+      doc_setup = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, min_order);
+      any_setup = ppdEmitString(ppd, PPD_ORDER_ANY, min_order);
 
-    if ((option = ppdFindOption(ppd, "PageRegion")) != NULL)
-      min_order = option->order;
-    else
-      min_order = 999.0f;
+     /*
+      * Then send them out...
+      */
 
-    for (i = 0; i < pageinfo->num_options; i ++)
-      if ((option = ppdFindOption(ppd, pageinfo->options[i].name)) != NULL &&
-          option->order < min_order)
-        min_order = option->order;
+      if (doc_setup)
+       doc_puts(doc, doc_setup);
 
-   /*
-    * Mark and extract them...
-    */
+      if (any_setup)
+       doc_puts(doc, any_setup);
 
-    cupsMarkOptions(ppd, pageinfo->num_options, pageinfo->options);
+     /*
+      * Free the command strings...
+      */
 
-    doc_setup = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, min_order);
-    any_setup = ppdEmitString(ppd, PPD_ORDER_ANY, min_order);
+      if (doc_setup)
+       free(doc_setup);
 
-   /*
-    * Then send them out...
-    */
+      if (any_setup)
+       free(any_setup);
+    }
+  }
 
-    if (doc_setup)
-      doc_puts(doc, doc_setup);
+ /*
+  * Prep for the start of the page description...
+  */
 
-    if (any_setup)
-      doc_puts(doc, any_setup);
+  start_nup(doc, number, 1, bounding_box);
 
  /*
-    * Free the command strings...
-    */
+ /*
+  * Copy page setup commands as needed...
+  */
 
-    if (doc_setup)
-      free(doc_setup);
+  if (!strncmp(line, "%%BeginPageSetup", 16))
+  {
+    int        feature = 0;                    /* In a Begin/EndFeature block? */
 
-    if (any_setup)
-      free(any_setup);
 
-    doc_puts(doc, "%%EndPageSetup\n");
+    while ((linelen = cupsFileGetLine(fp, line, linesize)) > 0)
+    {
+      if (!strncmp(line, "%%EndPageSetup", 14))
+        break;
+      else if (!strncmp(line, "%%BeginFeature:", 15))
+      {
+        feature = 1;
+
+       if (doc->number_up > 1 || doc->fitplot)
+         continue;
+      }
+      else if (!strncmp(line, "%%EndFeature:", 13))
+      {
+        feature = 0;
+
+       if (doc->number_up > 1 || doc->fitplot)
+         continue;
+      }
+      else if (!strncmp(line, "%%Include", 9))
+        continue;
+
+      if (!feature || (doc->number_up == 1 && !doc->fitplot))
+       doc_write(doc, line, linelen);
+    }
+
+   /*
+    * Skip %%EndPageSetup...
+    */
+
+    if (linelen > 0)
+      linelen = cupsFileGetLine(fp, line, linesize);
   }
 
  /*
-  * Prep for the start of the page description...
+  * Finish the PageSetup section as needed...
   */
 
-  start_nup(doc, number, 1, bounding_box);
+  if (first_page)
+    doc_puts(doc, "%%EndPageSetup\n");
 
  /*
   * Read the rest of the page description...
@@ -2891,5 +2910,5 @@ start_nup(pstops_doc_t *doc,              /* I - Document information */
 
 
 /*
- * End of "$Id: pstops.c 5369 2006-04-03 15:09:58Z mike $".
+ * End of "$Id: pstops.c 5382 2006-04-07 14:58:44Z mike $".
  */
index 965c8e5b3e243b1f2dea24498c6bbd6315a68bc8..4218ed2392cbcf146af5691b80ec0279f27c27c5 100644 (file)
@@ -1,5 +1,5 @@
 #
-# "$Id: cups.list.in 5354 2006-03-29 20:55:15Z mike $"
+# "$Id: cups.list.in 5371 2006-04-04 22:19:35Z mike $"
 #
 #   ESP Package Manager (EPM) file list for the Common UNIX Printing
 #   System (CUPS).
@@ -212,11 +212,11 @@ d 0755 root sys $SERVERBIN/driver -
 d 0755 root sys $SERVERBIN/filter -
 f 0755 root sys $SERVERBIN/filter/gziptoany filter/gziptoany
 f 0755 root sys $SERVERBIN/filter/hpgltops filter/hpgltops
-%if $IMGFILTERS
+%if IMGFILTERS
 f 0755 root sys $SERVERBIN/filter/imagetops filter/imagetops
 f 0755 root sys $SERVERBIN/filter/imagetoraster filter/imagetoraster
 %endif
-%if $PDFTOPS
+%if PDFTOPS
 f 0755 root sys $SERVERBIN/filter/pdftops pdftops/pdftops
 %endif
 f 0755 root sys $SERVERBIN/filter/pstops filter/pstops
@@ -424,7 +424,7 @@ f 0644 root sys $INCLUDEDIR/cups/md5.h cups/md5.h
 f 0644 root sys $INCLUDEDIR/cups/ppd.h cups/ppd.h
 f 0644 root sys $INCLUDEDIR/cups/raster.h filter/raster.h
 
-%if $INSTALLSTATIC
+%if INSTALLSTATIC
 f 0644 root sys $LIBDIR/libcups.a cups/libcups.a
 f 0644 root sys $LIBDIR/libcupsimage.a filter/libcupsimage.a
 %endif
@@ -523,5 +523,5 @@ f 0644 root sys $AMANDIR/man$MAN8DIR/cups-lpd.$MAN8EXT man/cups-lpd.$MAN8EXT
 i 0755 root sys cups init/cups.sh
 
 #
-# End of "$Id: cups.list.in 5354 2006-03-29 20:55:15Z mike $".
+# End of "$Id: cups.list.in 5371 2006-04-04 22:19:35Z mike $".
 #
index 0626b446177ff17018af08f4b29c2999235fbd3c..8a0d7a16164552abdf190203037e8514deb2283b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: cert.c 5305 2006-03-18 03:05:12Z mike $"
+ * "$Id: cert.c 5381 2006-04-07 14:39:46Z mike $"
  *
  *   Authentication certificate routines for the Common UNIX
  *   Printing System (CUPS).
@@ -107,6 +107,8 @@ cupsdAddCert(int        pid,                /* I - Process ID */
 #  ifdef HAVE_MBR_UID_TO_UUID
     uuid_t             group;          /* Group ID */
 #  endif /* HAVE_MBR_UID_TO_UUID */
+    static int         acls_not_supported = 0;
+                                       /* Only warn once */
 #endif /* HAVE_ACL_INIT */
 
 
@@ -201,7 +203,8 @@ cupsdAddCert(int        pid,                /* I - Process ID */
 
       if (acl_valid(acl))
       {
-        char *text, *textptr;
+        char *text, *textptr;          /* Temporary string */
+
 
         cupsdLogMessage(CUPSD_LOG_ERROR, "ACL did not validate: %s",
                        strerror(errno));
@@ -217,9 +220,16 @@ cupsdAddCert(int        pid,               /* I - Process ID */
 #  endif /* HAVE_MBR_UID_TO_UUID */
 
       if (acl_set_fd(fd, acl))
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Unable to set ACLs on root certificate \"%s\" - %s",
-                       filename, strerror(errno));
+      {
+       if (errno != EOPNOTSUPP || !acls_not_supported)
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Unable to set ACLs on root certificate \"%s\" - %s",
+                         filename, strerror(errno));
+
+       if (errno == EOPNOTSUPP)
+         acls_not_supported = 1;
+      }
+
       acl_free(acl);
     }
 #endif /* HAVE_ACL_INIT */
@@ -416,5 +426,5 @@ cupsdInitCerts(void)
 
 
 /*
- * End of "$Id: cert.c 5305 2006-03-18 03:05:12Z mike $".
+ * End of "$Id: cert.c 5381 2006-04-07 14:39:46Z mike $".
  */
index 1780b2207e059085870fde48d44f3fc7e2c003a8..06ee39340d467b58f905799367943465a7d4852d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: client.c 5367 2006-04-02 19:00:00Z mike $"
+ * "$Id: client.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Client routines for the Common UNIX Printing System (CUPS) scheduler.
  *
@@ -2474,6 +2474,8 @@ check_if_modified(
       while (*ptr != '\0' && *ptr != ';')
         ptr ++;
     }
+    else
+      ptr ++;
   }
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
@@ -2616,11 +2618,13 @@ encrypt_client(cupsd_client_t *con)     /* I - Client to encrypt */
   return (1);
 
 #  elif defined(HAVE_CDSASSL)
-  OSStatus     error;                  /* Error info */
-  SSLContextRef        conn;                   /* New connection */
-  CFArrayRef   certificatesArray;      /* Array containing certificates */
-  int          allowExpired;           /* Allow expired certificates? */
-  int          allowAnyRoot;           /* Allow any root certificate? */
+  OSStatus             error;          /* Error info */
+  SSLContextRef                conn;           /* New connection */
+  CFArrayRef           certificatesArray;
+                                       /* Array containing certificates */
+  int                  allowExpired;   /* Allow expired certificates? */
+  int                  allowAnyRoot;   /* Allow any root certificate? */
+  cdsa_conn_ref_t      u;              /* Connection reference union */
 
 
   conn         = NULL;
@@ -2645,12 +2649,23 @@ encrypt_client(cupsd_client_t *con)     /* I - Client to encrypt */
     error = SSLSetProtocolVersion(conn, kSSLProtocol3);
 
   if (!error)
-    error = SSLSetConnection(conn, (SSLConnectionRef)con->http.fd);
+  {
+   /*
+    * Use a union to resolve warnings about int/pointer size mismatches...
+    */
+
+    u.connection = NULL;
+    u.sock       = con->http.fd;
+    error        = SSLSetConnection(conn, u.connection);
+  }
 
   if (!error)
     error = SSLSetPeerDomainName(conn, ServerName, strlen(ServerName) + 1);
 
-  /* have to do these options before setting server certs */
+ /*
+  * Have to set these options before setting server certs...
+  */
+
   if (!error && allowExpired)
     error = SSLSetAllowsExpiredCerts(conn, true);
 
@@ -3805,5 +3820,5 @@ send_file(cupsd_client_t *con,            /* I - Client connection */
 
 
 /*
- * End of "$Id: client.c 5367 2006-04-02 19:00:00Z mike $".
+ * End of "$Id: client.c 5373 2006-04-06 20:03:32Z mike $".
  */
index 4306984728d963e38b91b65c7f1f3e20acb4c5a2..4b2fc5da3a914a981f3b277b167c50c312c8e2bd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: conf.c 5353 2006-03-29 20:31:58Z mike $"
+ * "$Id: conf.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Configuration routines for the Common UNIX Printing System (CUPS).
  *
@@ -243,6 +243,7 @@ cupsdReadConfiguration(void)
   if (NumBrowsers > 0)
   {
     free(Browsers);
+    Browsers = NULL;
 
     NumBrowsers = 0;
   }
@@ -281,7 +282,7 @@ cupsdReadConfiguration(void)
   cupsdSetString(&AccessLog, CUPS_LOGDIR "/access_log");
   cupsdSetString(&ErrorLog, CUPS_LOGDIR "/error_log");
   cupsdSetString(&PageLog, CUPS_LOGDIR "/page_log");
-  cupsdSetString(&Printcap, "/etc/printcap");
+  cupsdSetString(&Printcap, CUPS_DEFAULT_PRINTCAP);
   cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions");
   cupsdSetString(&FontPath, CUPS_FONTPATH);
   cupsdSetString(&RemoteRoot, "remroot");
@@ -3251,5 +3252,5 @@ read_policy(cups_file_t *fp,              /* I - Configuration file */
 
 
 /*
- * End of "$Id: conf.c 5353 2006-03-29 20:31:58Z mike $".
+ * End of "$Id: conf.c 5373 2006-04-06 20:03:32Z mike $".
  */
index b9c49dc3fabd5ab16821c9a3db2c29acdd2fd2b7..e6f84084c3c29693bba82db9f0dac90729bcd415 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: env.c 5305 2006-03-18 03:05:12Z mike $"
+ * "$Id: env.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Environment management routines for the Common UNIX Printing System (CUPS).
  *
@@ -68,11 +68,10 @@ cupsdInitEnv(void)
 
 #if defined(__APPLE__)
  /*
-  * Add special voodoo magic for MacOS X 10.4 and later - this allows MacOS
-  * programs to access their bundle resources properly...
+  * Add special voodoo magic for MacOS X - this allows MacOS X 
+  * programs to access their bundle resources properly...
   *
-  * This string is replaced in cupsdStartProcess() when we are running on
-  * versions of MacOS X prior to 10.4...
+  * This string is replaced in cupsdStartProcess()...
   */
 
   cupsdSetString(common_env, "<CFProcessPath>");
@@ -246,5 +245,5 @@ clear_env(void)
 
 
 /*
- * End of "$Id: env.c 5305 2006-03-18 03:05:12Z mike $".
+ * End of "$Id: env.c 5373 2006-04-06 20:03:32Z mike $".
  */
index 48b2349a98722c96671785edaecab721244046a3..e94c7310ac271efbd8b48d5564bb5d3057b6cf6b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: ipp.c 5334 2006-03-24 01:20:03Z mike $"
+ * "$Id: ipp.c 5383 2006-04-07 15:36:10Z mike $"
  *
  *   IPP routines for the Common UNIX Printing System (CUPS) scheduler.
  *
@@ -1489,10 +1489,13 @@ add_job(cupsd_client_t  *con,           /* I - Client connection */
     */
 
     cupsdSetJobHoldUntil(job, attr->values[0].string.text);
+
+    job->state->values[0].integer = IPP_JOB_HELD;
+    job->state_value              = IPP_JOB_HELD;
   }
   else if (job->attrs->request.op.operation_id == IPP_CREATE_JOB)
   {
-    job->hold_until = time(NULL) + 60;
+    job->hold_until               = time(NULL) + 60;
     job->state->values[0].integer = IPP_JOB_HELD;
     job->state_value              = IPP_JOB_HELD;
   }
@@ -6525,7 +6528,7 @@ move_job(cupsd_client_t  *con,            /* I - Client connection */
     * Move the job to a different printer or class...
     */
 
-    cupsdMoveJob(job, dest);
+    cupsdMoveJob(job, dprinter);
   }
   else
   {
@@ -6557,7 +6560,7 @@ move_job(cupsd_client_t  *con,            /* I - Client connection */
       * Move the job to a different printer or class...
       */
 
-      cupsdMoveJob(job, dest);
+      cupsdMoveJob(job, dprinter);
     }
   }
 
@@ -8811,11 +8814,19 @@ start_printer(cupsd_client_t  *con,     /* I - Client connection */
   cupsdStartPrinter(printer, 1);
 
   if (dtype & CUPS_PRINTER_CLASS)
+  {
     cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" started by \"%s\".", name,
                     get_username(con));
+    cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL,
+                  "Class \"%s\" started by \"%s\".", name, get_username(con));
+  }
   else
+  {
     cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" started by \"%s\".", name,
                     get_username(con));
+    cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL,
+                  "Printer \"%s\" started by \"%s\".", name, get_username(con));
+  }
 
   cupsdCheckJobs();
 
@@ -8899,11 +8910,19 @@ stop_printer(cupsd_client_t  *con,      /* I - Client connection */
   cupsdStopPrinter(printer, 1);
 
   if (dtype & CUPS_PRINTER_CLASS)
+  {
     cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" stopped by \"%s\".", name,
                     get_username(con));
+    cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL,
+                  "Class \"%s\" stopped by \"%s\".", name, get_username(con));
+  }
   else
+  {
     cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" stopped by \"%s\".", name,
                     get_username(con));
+    cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL,
+                  "Printer \"%s\" stopped by \"%s\".", name, get_username(con));
+  }
 
  /*
   * Everything was ok, so return OK status...
@@ -9137,5 +9156,5 @@ validate_user(cupsd_job_t    *job,        /* I - Job */
 
 
 /*
- * End of "$Id: ipp.c 5334 2006-03-24 01:20:03Z mike $".
+ * End of "$Id: ipp.c 5383 2006-04-07 15:36:10Z mike $".
  */
index 4860b1326ee4190d2828610f3be56788ab4116a5..d2b1f13af0b4f32f588a0a0729d3c90c1d2e673e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: job.c 5305 2006-03-18 03:05:12Z mike $"
+ * "$Id: job.c 5383 2006-04-07 15:36:10Z mike $"
  *
  *   Job management routines for the Common UNIX Printing System (CUPS).
  *
@@ -386,7 +386,8 @@ cupsdCheckJobs(void)
                         "job-actual-printer-uri", NULL, printer->uri);
        }
 
-        if (printer->state == IPP_PRINTER_IDLE ||      /* Printer is idle */
+        if ((!(printer->type & CUPS_PRINTER_REMOTE) && /* Printer is local */
+            printer->state == IPP_PRINTER_IDLE) ||     /* and idle */
            ((printer->type & CUPS_PRINTER_REMOTE) &&   /* Printer is remote */
             !printer->job))                            /* and not printing */
          start_job(job, printer);
@@ -1066,26 +1067,31 @@ cupsdLoadJob(cupsd_job_t *job)          /* I - Job */
  */
 
 void
-cupsdMoveJob(cupsd_job_t *job,         /* I - Job */
-             const char  *dest)                /* I - Destination */
+cupsdMoveJob(cupsd_job_t     *job,     /* I - Job */
+             cupsd_printer_t *p)       /* I - Destination printer or class */
 {
   ipp_attribute_t      *attr;          /* job-printer-uri attribute */
-  cupsd_printer_t      *p;             /* Destination printer or class */
+  const char           *olddest;       /* Old destination */
+  cupsd_printer_t      *oldp;          /* Old pointer */
 
 
  /*
-  * Find the printer...
+  * Don't move completed jobs...
   */
 
-  if ((p = cupsdFindDest(dest)) == NULL)
+  if (job->state_value > IPP_JOB_STOPPED)
     return;
 
  /*
-  * Don't move completed jobs...
+  * Get the old destination...
   */
 
-  if (job->state_value >= IPP_JOB_PROCESSING)
-    return;
+  olddest = job->dest;
+
+  if (job->printer)
+    oldp = job->printer;
+  else
+    oldp = cupsdFindDest(olddest);
 
  /*
   * Change the destination information...
@@ -1093,7 +1099,11 @@ cupsdMoveJob(cupsd_job_t *job,           /* I - Job */
 
   cupsdLoadJob(job);
 
-  cupsdSetString(&job->dest, dest);
+  cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, oldp, job,
+                "Job #%d moved from %s to %s.", job->id, olddest,
+               p->name);
+
+  cupsdSetString(&job->dest, p->name);
   job->dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
                           CUPS_PRINTER_IMPLICIT);
 
@@ -1101,6 +1111,10 @@ cupsdMoveJob(cupsd_job_t *job,           /* I - Job */
                                IPP_TAG_URI)) != NULL)
     cupsdSetString(&(attr->values[0].string.text), p->uri);
 
+  cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
+                "Job #%d moved from %s to %s.", job->id, olddest,
+               p->name);
+
   cupsdSaveJob(job);
 }
 
@@ -3373,5 +3387,5 @@ unload_job(cupsd_job_t *job)              /* I - Job */
 
 
 /*
- * End of "$Id: job.c 5305 2006-03-18 03:05:12Z mike $".
+ * End of "$Id: job.c 5383 2006-04-07 15:36:10Z mike $".
  */
index 4b13d65f52ac5c95391023d716b6edeedf57adde..31dba60d3be28af4be248af0ae29ebb5f1aa2d46 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: job.h 5305 2006-03-18 03:05:12Z mike $"
+ * "$Id: job.h 5383 2006-04-07 15:36:10Z mike $"
  *
  *   Print job definitions for the Common UNIX Printing System (CUPS) scheduler.
  *
@@ -107,7 +107,7 @@ extern int          cupsdGetUserJobCount(const char *username);
 extern void            cupsdHoldJob(cupsd_job_t *job);
 extern void            cupsdLoadAllJobs(void);
 extern void            cupsdLoadJob(cupsd_job_t *job);
-extern void            cupsdMoveJob(cupsd_job_t *job, const char *dest);
+extern void            cupsdMoveJob(cupsd_job_t *job, cupsd_printer_t *p);
 extern void            cupsdReleaseJob(cupsd_job_t *job);
 extern void            cupsdRestartJob(cupsd_job_t *job);
 extern void            cupsdSaveAllJobs(void);
@@ -120,5 +120,5 @@ extern void         cupsdUpdateJob(cupsd_job_t *job);
 
 
 /*
- * End of "$Id: job.h 5305 2006-03-18 03:05:12Z mike $".
+ * End of "$Id: job.h 5383 2006-04-07 15:36:10Z mike $".
  */
index f244526e5796f0e888042cf77010edf46ba0ea59..97aa1a121fcf4597f1343e0049f15a901e88e0c8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: main.c 5305 2006-03-18 03:05:12Z mike $"
+ * "$Id: main.c 5383 2006-04-07 15:36:10Z mike $"
  *
  *   Scheduler main loop for the Common UNIX Printing System (CUPS).
  *
@@ -1012,7 +1012,7 @@ main(int  argc,                           /* I - Number of command-line args */
     * accumulated.  Don't send these more than once a second...
     */
 
-    if (LastEvent && (time(NULL) - LastEventTime) > 1)
+    if (LastEvent)
     {
 #ifdef HAVE_NOTIFY_POST
       if (LastEvent & CUPSD_EVENT_PRINTER_CHANGED)
@@ -1040,10 +1040,9 @@ main(int  argc,                          /* I - Number of command-line args */
 #endif /* HAVE_NOTIFY_POST */
 
      /*
-      * Reset the accumulated events and notification time...
+      * Reset the accumulated events...
       */
 
-      LastEventTime = time(NULL);
       LastEvent     = CUPSD_EVENT_NONE;
     }
   }
@@ -1190,7 +1189,7 @@ cupsdClearString(char **s)                /* O - String value */
 {
   if (s && *s)
   {
-    free(*s);
+    _cupsStrFree(*s);
     *s = NULL;
   }
 }
@@ -1256,10 +1255,10 @@ cupsdSetString(char       **s,          /* O - New string */
     return;
 
   if (*s)
-    free(*s);
+    _cupsStrFree(*s);
 
   if (v)
-    *s = strdup(v);
+    *s = _cupsStrAlloc(v);
   else
     *s = NULL;
 }
@@ -1290,13 +1289,13 @@ cupsdSetStringf(char       **s,         /* O - New string */
     vsnprintf(v, sizeof(v), f, ap);
     va_end(ap);
 
-    *s = strdup(v);
+    *s = _cupsStrAlloc(v);
   }
   else
     *s = NULL;
 
   if (olds)
-    free(olds);
+    _cupsStrFree(olds);
 }
 
 
@@ -1315,12 +1314,10 @@ launchd_checkin(void)
                        ld_resp,        /* Launch data response */
                        ld_array,       /* Launch data array */
                        ld_sockets,     /* Launch data sockets dictionary */
-                       ld_runatload,   /* Run-at-load setting */
                        tmp;            /* Launch data */
   cupsd_listener_t     *lis;           /* Listeners array */
   http_addr_t          addr;           /* Address variable */
   socklen_t            addrlen;        /* Length of address */
-  bool                 runatload;      /* Run-at-load setting value */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG, "launchd_checkin: pid=%d", (int)getpid());
@@ -1346,26 +1343,6 @@ launchd_checkin(void)
     exit(EXIT_FAILURE);
   }
 
- /*
-  * Get the "run-at-load" setting...
-  */
-
-  if ((ld_runatload =
-           launch_data_dict_lookup(ld_resp, LAUNCH_JOBKEY_RUNATLOAD)) != NULL &&
-      launch_data_get_type(ld_runatload) == LAUNCH_DATA_BOOL)
-    runatload = launch_data_get_bool(ld_runatload);
-  else
-  {
-    errno = launch_data_get_errno(ld_resp);
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "launchd_checkin: Unable to find Run-at-load setting: %s",
-                    strerror(errno));
-    exit(EXIT_FAILURE);
-  }
-
-  cupsdLogMessage(CUPSD_LOG_DEBUG, "launchd_checkin: Run-at-load=%s",
-                  runatload ? "true" : "false");
-
  /*
   * Get the sockets dictionary...
   */
@@ -1459,18 +1436,22 @@ launchd_checkin(void)
   {
     if (launch_data_get_type(ld_array) == LAUNCH_DATA_ARRAY)
     {
-      tmp = launch_data_array_get_index(ld_array, 0);
-
-      if (launch_data_get_type(tmp) == LAUNCH_DATA_FD)
+      if ((tmp = launch_data_array_get_index(ld_array, 0)))
       {
-        if (BrowseSocket != -1)
-         close(BrowseSocket);
-
-       BrowseSocket = launch_data_get_fd(tmp);
-      }
-      else
-       cupsdLogMessage(CUPSD_LOG_WARN,
-                       "launchd_checkin: BrowseSocket not a fd!");
+       if (launch_data_get_type(tmp) == LAUNCH_DATA_FD)
+       {
+         if (BrowseSocket != -1)
+           close(BrowseSocket);
+  
+         BrowseSocket = launch_data_get_fd(tmp);
+       }
+       else
+         cupsdLogMessage(CUPSD_LOG_WARN,
+                         "launchd_checkin: BrowseSocket not a fd!");
+     }
+     else
+       cupsdLogMessage(CUPSD_LOG_WARN,
+                      "launchd_checkin: BrowseSockets is an empty array!");
    }
    else
      cupsdLogMessage(CUPSD_LOG_WARN,
@@ -2107,13 +2088,6 @@ select_timeout(int fds)                  /* I - Number of descriptors returned */
   if (fds || cupsArrayCount(Clients) > 50)
     return (1);
 
- /*
-  * If we had a recent event notification, timeout in 1 second...
-  */
-
-  if (LastEvent)
-    return (1);
-
  /*
   * Otherwise, check all of the possible events that we need to wake for...
   */
@@ -2272,5 +2246,5 @@ usage(int status)                 /* O - Exit status */
 
 
 /*
- * End of "$Id: main.c 5305 2006-03-18 03:05:12Z mike $".
+ * End of "$Id: main.c 5383 2006-04-07 15:36:10Z mike $".
  */
index 456fc358d2a67803848238a6219dc71dda27ff22..86b4f79317aad3e2812c60bf74e59e3d17bee9ab 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: printers.c 5330 2006-03-23 21:07:20Z mike $"
+ * "$Id: printers.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Printer routines for the Common UNIX Printing System (CUPS).
  *
@@ -2271,6 +2271,11 @@ cupsdSetPrinterState(
 
   if (old_state != s)
   {
+    cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE_CHANGED, p, NULL,
+                 "%s \"%s\" state changed.",
+                 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
+                 p->name);
+
    /*
     * Let the browse code know this needs to be updated...
     */
@@ -3273,5 +3278,5 @@ write_irix_state(cupsd_printer_t *p)      /* I - Printer to update */
 
 
 /*
- * End of "$Id: printers.c 5330 2006-03-23 21:07:20Z mike $".
+ * End of "$Id: printers.c 5373 2006-04-06 20:03:32Z mike $".
  */
index d891adf170890945c6ffbb16c98ebc481d360e8a..5af7e5eef361a1ab0b7b395a8436e175d3e1baa5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: process.c 5094 2006-02-09 01:00:26Z mike $"
+ * "$Id: process.c 5376 2006-04-06 20:32:07Z mike $"
  *
  *   Process management routines for the Common UNIX Printing System (CUPS).
  *
@@ -35,9 +35,9 @@
 
 #include "cupsd.h"
 #include <grp.h>
-#if defined(__APPLE__) && __GNUC__ < 4
+#if defined(__APPLE__)
 #  include <libgen.h>
-#endif /* __APPLE__ && __GNUC__ < 4 */ 
+#endif /* __APPLE__ */ 
 
 
 /*
@@ -128,45 +128,47 @@ cupsdStartProcess(
 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
   struct sigaction action;             /* POSIX signal handler */
 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-#if defined(__APPLE__) && __GNUC__ < 4
-  int          envc;                   /* Number of environment variables */
+#if defined(__APPLE__)
   char         processPath[1024],      /* CFProcessPath environment variable */
                linkpath[1024];         /* Link path for symlinks... */
   int          linkbytes;              /* Bytes for link path */
-#endif /* __APPLE__ && __GNUC__ < 4 */
+#endif /* __APPLE__ */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
                   "cupsdStartProcess(\"%s\", %p, %p, %d, %d, %d)",
                   command, argv, envp, infd, outfd, errfd);
 
-#if defined(__APPLE__) && __GNUC__ < 4
- /*
-  * Add special voodoo magic for MacOS X 10.3 and earlier - this allows
-  * MacOS X programs to access their bundle resources properly...
-  */
-
-  if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
+#if defined(__APPLE__)
+  if (envp)
   {
    /*
-    * Yes, this is a symlink to the actual program, nul-terminate and
-    * use it...
+    * Add special voodoo magic for MacOS X - this allows MacOS X 
+    * programs to access their bundle resources properly...
     */
 
-    linkpath[linkbytes] = '\0';
+    if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
+    {
+     /*
+      * Yes, this is a symlink to the actual program, nul-terminate and
+      * use it...
+      */
+
+      linkpath[linkbytes] = '\0';
 
-    if (linkpath[0] == '/')
-      snprintf(processPath, sizeof(processPath), "CFProcessPath=%s",
-              linkpath);
+      if (linkpath[0] == '/')
+       snprintf(processPath, sizeof(processPath), "CFProcessPath=%s",
+                linkpath);
+      else
+       snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
+                dirname(command), linkpath);
+    }
     else
-      snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
-              dirname(command), linkpath);
-  }
-  else
-    snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command);
+      snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command);
 
-  envp[0] = processPath;               /* Replace <CFProcessPath> string */
-#endif /* __APPLE__ && __GNUC__ > 3 */
+    envp[0] = processPath;             /* Replace <CFProcessPath> string */
+  }
+#endif /* __APPLE__ */
 
  /*
   * Block signals before forking...
@@ -342,5 +344,5 @@ compare_procs(cupsd_proc_t *a,              /* I - First process */
 
 
 /*
- * End of "$Id: process.c 5094 2006-02-09 01:00:26Z mike $".
+ * End of "$Id: process.c 5376 2006-04-06 20:32:07Z mike $".
  */
index 55645746aa516a9a01bdca3253a4ce565e464992..226848796f6fab74549213302ce1331d40949663 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: server.c 5305 2006-03-18 03:05:12Z mike $"
+ * "$Id: server.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Server start/stop routines for the Common UNIX Printing System (CUPS).
  *
@@ -119,7 +119,6 @@ cupsdStartServer(void)
 
   LastEvent     = CUPSD_EVENT_PRINTER_CHANGED | CUPSD_EVENT_JOB_STATE_CHANGED |
                   CUPSD_EVENT_SERVER_STARTED;
-  LastEventTime = 0;
 
   started = 1;
 }
@@ -212,5 +211,5 @@ cupsdStopServer(void)
 
 
 /*
- * End of "$Id: server.c 5305 2006-03-18 03:05:12Z mike $".
+ * End of "$Id: server.c 5373 2006-04-06 20:03:32Z mike $".
  */
index a4875b1c227207182810d04ced9274c92687dd7a..120c0891420a3e2c676acffce025ec3fbc2bd739 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: statbuf.c 5073 2006-02-04 17:39:51Z mike $"
+ * "$Id: statbuf.c 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Status buffer routines for the Common UNIX Printing System (CUPS)
  *   scheduler.
@@ -317,7 +317,9 @@ cupsdStatBufUpdate(cupsd_statbuf_t *sb,     /* I - Status buffer */
   * Copy over the buffer data we've used up...
   */
 
-  _cups_strcpy(sb->buffer, lineptr);
+  if (lineptr < sb->buffer + sb->bufused)
+    _cups_strcpy(sb->buffer, lineptr);
+
   sb->bufused -= lineptr - sb->buffer;
 
   if (sb->bufused < 0)
@@ -328,5 +330,5 @@ cupsdStatBufUpdate(cupsd_statbuf_t *sb,     /* I - Status buffer */
 
 
 /*
- * End of "$Id: statbuf.c 5073 2006-02-04 17:39:51Z mike $".
+ * End of "$Id: statbuf.c 5373 2006-04-06 20:03:32Z mike $".
  */
index 646757120798e71f76900999040b1c289704de8b..ca5bb58077f37526b79c52c5c53214b421299baf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: subscriptions.h 5305 2006-03-18 03:05:12Z mike $"
+ * "$Id: subscriptions.h 5373 2006-04-06 20:03:32Z mike $"
  *
  *   Subscription definitions for the Common UNIX Printing System (CUPS) scheduler.
  *
@@ -136,8 +136,6 @@ VAR int             MaxEvents VALUE(100),   /* Maximum number of events */
 VAR cupsd_event_t **Events VALUE(NULL);        /* Active events */
 
 VAR unsigned   LastEvent VALUE(0);     /* Last events processed */
-VAR time_t     LastEventTime VALUE(0); /* Time that the last events were sent */
-
 VAR int                NotifierPipes[2] VALUE2(-1, -1);
                                        /* Pipes for notifier error/debug output */
 VAR cupsd_statbuf_t *NotifierStatusBuffer VALUE(NULL);
@@ -172,5 +170,5 @@ extern void cupsdUpdateNotifierStatus(void);
 
 
 /*
- * End of "$Id: subscriptions.h 5305 2006-03-18 03:05:12Z mike $".
+ * End of "$Id: subscriptions.h 5373 2006-04-06 20:03:32Z mike $".
  */