From: jlovell Date: Fri, 7 Apr 2006 21:00:45 +0000 (+0000) Subject: Load cups into easysw/current. X-Git-Tag: release-1.6.3~239 X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=commitdiff_plain;h=e53920b9224e07b7d5f3e5a3ffea1f64ded479d2 Load cups into easysw/current. git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@125 a1ca3aef-8c08-0410-bb20-df032aa958be --- diff --git a/CHANGES.txt b/CHANGES.txt index dd1be6a43..604557f50 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -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 diff --git a/Makedefs.in b/Makedefs.in index ceb6e4bf4..b415a0c2d 100644 --- a/Makedefs.in +++ b/Makedefs.in @@ -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 $" # diff --git a/backend/usb-darwin.c b/backend/usb-darwin.c index 11009b27a..39edff1ee 100644 --- a/backend/usb-darwin.c +++ b/backend/usb-darwin.c @@ -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 -#include - -#include -#include -#include -#include - #include #include #include @@ -70,1835 +52,1287 @@ #include #include #include -#include /* Used for writegReadMutex */ - -#ifndef kPMPrinterURI -# define kPMPrinterURI CFSTR("Printer URI") -#endif +#include +#include +#include +#include +#include +#include -/* - * Panther/10.3 kIOUSBInterfaceInterfaceID190 - * Jaguar/10.2 kIOUSBInterfaceInterfaceID182 - */ +#include +#include +#include -#define USB_INTERFACE_KIND CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190) -#define kUSBLanguageEnglish 0x409 +#include -/* - * 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. - - = + - - = - = :[,]*; - - = + - = + - - 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 + 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= or ?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: + 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= or ?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 $". */ diff --git a/backend/usb-unix.c b/backend/usb-unix.c index ae302a096..f3d1c3d51 100644 --- a/backend/usb-unix.c +++ b/backend/usb-unix.c @@ -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 $". */ diff --git a/backend/usb.c b/backend/usb.c index ede0292d7..6665f282e 100644 --- a/backend/usb.c +++ b/backend/usb.c @@ -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 $". */ diff --git a/conf/mime.types b/conf/mime.types index 8d738aaed..c063fa6ce 100644 --- a/conf/mime.types +++ b/conf/mime.types @@ -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 $". # diff --git a/config-scripts/cups-defaults.m4 b/config-scripts/cups-defaults.m4 index 3a6f25109..50394fa31 100644 --- a/config-scripts/cups-defaults.m4 +++ b/config-scripts/cups-defaults.m4 @@ -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$". diff --git a/config.h.in b/config.h.in index 911a9e8eb..b7de6e72a 100644 --- a/config.h.in +++ b/config.h.in @@ -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). * @@ -70,6 +70,13 @@ #define CUPS_DEFAULT_IPP_PORT 631 +/* + * Default printcap file... + */ + +#define CUPS_DEFAULT_PRINTCAP "/etc/printcap" + + /* * Maximum number of file descriptors to support. */ @@ -425,5 +432,5 @@ #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 $". */ diff --git a/configure.in b/configure.in index 15654e7b3..299ca6a44 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/cups/encode.c b/cups/encode.c index 8aab5f27d..ec46217f1 100644 --- a/cups/encode.c +++ b/cups/encode.c @@ -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 $". */ diff --git a/cups/globals.c b/cups/globals.c index 65427b4f0..b7dbbf348 100644 --- a/cups/globals.c +++ b/cups/globals.c @@ -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 $". */ diff --git a/cups/http-private.h b/cups/http-private.h index 0f66ed8c6..0a2927f6a 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -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 $". */ diff --git a/cups/http.c b/cups/http.c index 59a402339..a8ec36a02 100644 --- a/cups/http.c +++ b/cups/http.c @@ -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 $". */ diff --git a/cups/language.c b/cups/language.c index fa11f87cb..6990d9127 100644 --- a/cups/language.c +++ b/cups/language.c @@ -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 $". */ diff --git a/cups/test.ppd b/cups/test.ppd index 33b7a0df6..bdcdc9971 100644 --- a/cups/test.ppd +++ b/cups/test.ppd @@ -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). *% @@ -126,6 +126,7 @@ *OpenUI IntOption/Integer: PickOne *OrderDependency: 10 AnySetup *IntOption *DefaultIntOption: None +*IntOption None: "" *IntOption 1: "IntOption=1" *IntOption 2: "IntOption=2" *IntOption 3: "IntOption=3" @@ -137,6 +138,7 @@ *OpenUI StringOption/String: PickOne *OrderDependency: 10 AnySetup *StringOption *DefaultStringOption: None +*StringOption None: "" *StringOption foo: "StringOption=foo" *StringOption bar: "StringOption=bar" *CloseUI: *StringOption @@ -183,5 +185,5 @@ *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 $". *% diff --git a/cups/transcode.c b/cups/transcode.c index 8e9f3133b..c7384d9cb 100644 --- a/cups/transcode.c +++ b/cups/transcode.c @@ -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 #include #include #include @@ -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 $" */ diff --git a/filter/imagetops.c b/filter/imagetops.c index d417c9b54..4f512fc0d 100644 --- a/filter/imagetops.c +++ b/filter/imagetops.c @@ -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 $". */ diff --git a/filter/pstops.c b/filter/pstops.c index 4be662155..305c798d8 100644 --- a/filter/pstops.c +++ b/filter/pstops.c @@ -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 #include #include #include @@ -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 $". */ diff --git a/packaging/cups.list.in b/packaging/cups.list.in index 965c8e5b3..4218ed239 100644 --- a/packaging/cups.list.in +++ b/packaging/cups.list.in @@ -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 $". # diff --git a/scheduler/cert.c b/scheduler/cert.c index 0626b4461..8a0d7a161 100644 --- a/scheduler/cert.c +++ b/scheduler/cert.c @@ -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 $". */ diff --git a/scheduler/client.c b/scheduler/client.c index 1780b2207..06ee39340 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -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 $". */ diff --git a/scheduler/conf.c b/scheduler/conf.c index 430698472..4b2fc5da3 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -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 $". */ diff --git a/scheduler/env.c b/scheduler/env.c index b9c49dc3f..e6f84084c 100644 --- a/scheduler/env.c +++ b/scheduler/env.c @@ -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 - * X 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, ""); @@ -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 $". */ diff --git a/scheduler/ipp.c b/scheduler/ipp.c index 48b2349a9..e94c7310a 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -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 $". */ diff --git a/scheduler/job.c b/scheduler/job.c index 4860b1326..d2b1f13af 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -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 $". */ diff --git a/scheduler/job.h b/scheduler/job.h index 4b13d65f5..31dba60d3 100644 --- a/scheduler/job.h +++ b/scheduler/job.h @@ -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 $". */ diff --git a/scheduler/main.c b/scheduler/main.c index f244526e5..97aa1a121 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -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 $". */ diff --git a/scheduler/printers.c b/scheduler/printers.c index 456fc358d..86b4f7931 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -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 $". */ diff --git a/scheduler/process.c b/scheduler/process.c index d891adf17..5af7e5eef 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -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 -#if defined(__APPLE__) && __GNUC__ < 4 +#if defined(__APPLE__) # include -#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 string */ -#endif /* __APPLE__ && __GNUC__ > 3 */ + envp[0] = processPath; /* Replace 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 $". */ diff --git a/scheduler/server.c b/scheduler/server.c index 55645746a..226848796 100644 --- a/scheduler/server.c +++ b/scheduler/server.c @@ -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 $". */ diff --git a/scheduler/statbuf.c b/scheduler/statbuf.c index a4875b1c2..120c08914 100644 --- a/scheduler/statbuf.c +++ b/scheduler/statbuf.c @@ -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 $". */ diff --git a/scheduler/subscriptions.h b/scheduler/subscriptions.h index 646757120..ca5bb5807 100644 --- a/scheduler/subscriptions.h +++ b/scheduler/subscriptions.h @@ -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 $". */