[Pkg-cups-devel] r408 - in cupsys/branches/cups-1.2/debian: . patches

Kenshi Muto kmuto at alioth.debian.org
Wed Nov 15 01:58:17 CET 2006


Author: kmuto
Date: Wed Nov 15 01:58:16 2006
New Revision: 408

Added:
   cupsys/branches/cups-1.2/debian/patches/00_r6100.dpatch   (contents, props changed)
Modified:
   cupsys/branches/cups-1.2/debian/changelog
   cupsys/branches/cups-1.2/debian/patches/00list
   cupsys/branches/cups-1.2/debian/patches/47_pid.dpatch
Log:
apply SVN r6100 (#397833)

Modified: cupsys/branches/cups-1.2/debian/changelog
==============================================================================
--- cupsys/branches/cups-1.2/debian/changelog	(original)
+++ cupsys/branches/cups-1.2/debian/changelog	Wed Nov 15 01:58:16 2006
@@ -4,6 +4,9 @@
   * Debconf translation
     - Brazillian Portuguese (closes: #397842)
     - Basque (closes: #398574)
+  * 00_r6100: Apply SVN r6100.
+    - Fixed an inefficiency in the SNMP IPP detection code
+      (closes: #397833)
 
  -- Kenshi Muto <kmuto at debian.org>  Tue, 14 Nov 2006 22:29:08 +0900
 

Added: cupsys/branches/cups-1.2/debian/patches/00_r6100.dpatch
==============================================================================
--- (empty file)
+++ cupsys/branches/cups-1.2/debian/patches/00_r6100.dpatch	Wed Nov 15 01:58:16 2006
@@ -0,0 +1,3880 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 00_r6100.dpatch by Kenshi Muto <kmuto at debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+ at DPATCH@
+diff -urNad cupsys-1.2.6~/CHANGES.txt cupsys-1.2.6/CHANGES.txt
+--- cupsys-1.2.6~/CHANGES.txt	2006-11-03 05:01:54.000000000 +0900
++++ cupsys-1.2.6/CHANGES.txt	2006-11-15 09:51:23.000000000 +0900
+@@ -1,6 +1,26 @@
+-CHANGES.txt - 2006-11-02
++CHANGES.txt - 2006-11-14
+ ------------------------
+ 
++CHANGES IN CUPS V1.2.7
++
++	- Documentation updates (STR #2089)
++	- The PostScript filter now rotates the bounding box
++	  values as needed (STR #2079)
++	- The scheduler no longer loads the remote printer cache
++	  when browsing is disabled (STR #2084)
++	- The scheduler no longer writes a new launchd
++	  configuration file if it doesn't have to (STR #2083)
++	- Updated the USB and PAP backends for Mac OS X (STR
++	  #2086)
++	- The scheduler now picks up on changes to IPv6 and DNS
++	  configuration on Mac OS X (STR #2085)
++	- The lpstat program could still hang (STR #2098)
++	- Fixed an inefficiency in the SNMP IPP detection code
++	  (STR #2100)
++	- The SSL negotiation code did not implement short
++	  timeouts (STR #2091)
++
++
+ CHANGES IN CUPS V1.2.6
+ 
+ 	- The web interface was not localized on Mac OS X (STR
+diff -urNad cupsys-1.2.6~/backend/pap.c cupsys-1.2.6/backend/pap.c
+--- cupsys-1.2.6~/backend/pap.c	2006-05-03 00:17:04.000000000 +0900
++++ cupsys-1.2.6/backend/pap.c	2006-11-15 09:51:22.000000000 +0900
+@@ -42,31 +42,35 @@
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+-* This program implements the Printer Access Protocol (PAP) on top of AppleTalk Transaction
+-* Protocol (ATP). If it were to use the blocking pap functions of the AppleTalk library it 
+-* would need seperate threads for reading, writing and status.
++* This program implements the Printer Access Protocol (PAP) on top of AppleTalk 
++* Transaction Protocol (ATP). If it were to use the blocking pap functions of 
++* the AppleTalk library it would need seperate threads for reading, writing
++* and status.
+ *
+ * Contents:
+ *
+ *  main()		- Send a file to the specified Appletalk printer.
+ *  listDevices()	- List all LaserWriter printers in the local zone.
+-*  printFile()		- Print from a file descriptor to an NBP specified printer.
++*  printFile()		- Print file.
+ *  papOpen()		- Open a pap session to a printer.
+-*  papClose()		- Close a pap session after cleaning up pending transactions.
++*  papClose()		- Close a pap session.
+ *  papWrite()		- Write bytes to a printer.
+-*  papCloseResp()	- Send a pap close response in the rare case we receive a close connection request.
++*  papCloseResp()	- Send a pap close response.
+ *  papSendRequest()	- Fomrat and send a pap packet.
+ *  papCancelRequest()	- Cancel a pending pap request.
+ *  statusUpdate()	- Print printer status to stderr.
+ *  parseUri()		- Extract the print name and zone from a uri.
+ *  addPercentEscapes()	- Encode a string with percent escapes.
+-*  removePercentEscapes	- Returns a string with any percent escape sequences replaced with their equivalent.
++*  removePercentEscapes	- Remove percent escape sequences from a string.
+ *  nbptuple_compare()	- Compare routine for qsort.
+ *  okayToUseAppleTalk() - Returns true if AppleTalk is available and enabled.
++*  packet_name()	- Returns packet name string.
+ *  connectTimeout()	- Returns the connect timeout preference value.
+ *  signalHandler()	- handle SIGINT to close the session before quiting.
+ */
+ 
++#include <config.h>
++
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <ctype.h>
+@@ -86,7 +90,8 @@
+ #include <netat/nbp.h>
+ #include <netat/pap.h>
+ 
+-#include <cups/http.h>
++#include <cups/cups.h>
++#include <cups/backend.h>
+ 
+ #include <libkern/OSByteOrder.h>
+ 
+@@ -95,19 +100,25 @@
+ #else
+ /* These definitions come from at_proto.h... */
+ #  define ZIP_DEF_INTERFACE NULL
+-enum { RUNNING, NOTLOADED, LOADED, OTHERERROR };	/* Appletalk Stack status Function. */
++enum { RUNNING, NOTLOADED, LOADED, OTHERERROR };
+ 
+ extern int atp_abort(int fd, at_inet_t *dest, u_short tid);
+ extern int atp_close(int fd);
+-extern int atp_getreq(int fd, at_inet_t *src, char *buf, int *len, int *userdata, int *xo, u_short *tid, u_char *bitmap, int nowait);
++extern int atp_getreq(int fd, at_inet_t *src, char *buf, int *len, int *userdata, 
++		      int *xo, u_short *tid, u_char *bitmap, int nowait);
+ extern int atp_getresp(int fd, u_short *tid, at_resp_t *resp);
+ extern int atp_look(int fd);
+ extern int atp_open(at_socket *sock);
+-extern int atp_sendreq(int fd, at_inet_t *dest, char *buf, int len, int userdata, int xo, int xo_relt, u_short *tid, at_resp_t *resp, at_retry_t *retry, int nowait);
+-extern int atp_sendrsp(int fd, at_inet_t *dest, int xo, u_short tid, at_resp_t *resp);
++extern int atp_sendreq(int fd, at_inet_t *dest, char *buf, int len, 
++		       int userdata, int xo, int xo_relt, u_short *tid, 
++		       at_resp_t *resp, at_retry_t *retry, int nowait);
++extern int atp_sendrsp(int fd, at_inet_t *dest, int xo, u_short tid, 
++		       at_resp_t *resp);
+ extern int checkATStack();
+-extern int nbp_lookup(at_entity_t *entity, at_nbptuple_t *buf, int max, at_retry_t *retry);
+-extern int nbp_make_entity(at_entity_t *entity, char *obj, char *type, char *zone);
++extern int nbp_lookup(at_entity_t *entity, at_nbptuple_t *buf, int max, 
++		      at_retry_t *retry);
++extern int nbp_make_entity(at_entity_t *entity, char *obj, char *type, 
++			   char *zone);
+ extern int zip_getmyzone(char *ifName,	at_nvestr_t *zone);
+ #endif /* HAVE_APPLETALK_AT_PROTO_H */
+ 
+@@ -116,7 +127,7 @@
+ #include <CoreFoundation/CFPreferences.h>
+ 
+ /* Defines */
+-#define MAX_PRINTERS	500        /* Max number of printers we can lookup in listDevices */
++#define MAX_PRINTERS	500        /* Max number of printers we can lookup */
+ #define PAP_CONNID	0
+ #define PAP_TYPE	1
+ #define PAP_EOF		2
+@@ -126,43 +137,35 @@
+ #define SEQUENCE_NUM(p)	(((u_char *)&p)[2])
+ #define IS_PAP_EOF(p)	(((u_char *)&p)[2])
+ 
+-#define  PAPPacketStr(x) \
+-  ((x) == AT_PAP_TYPE_OPEN_CONN)	? "PAP_OPEN_CONN"        : \
+-  ((x) == AT_PAP_TYPE_OPEN_CONN_REPLY)	? "PAP_OPEN_CONN_REPLY"  : \
+-  ((x) == AT_PAP_TYPE_SEND_DATA)	? "PAP_SEND_DATA"        : \
+-  ((x) == AT_PAP_TYPE_DATA)		? "PAP_DATA"             : \
+-  ((x) == AT_PAP_TYPE_TICKLE)		? "PAP_TICKLE"           : \
+-  ((x) == AT_PAP_TYPE_CLOSE_CONN)	? "PAP_CLOSE_CONN"       : \
+-  ((x) == AT_PAP_TYPE_CLOSE_CONN_REPLY)	? "PAP_CLOSE_CONN_REPLY" : \
+-  ((x) == AT_PAP_TYPE_SEND_STATUS)	? "PAP_SEND_STATUS"      : \
+-  ((x) == AT_PAP_TYPE_SEND_STS_REPLY)	? "PAP_SEND_STS_REPLY"   : \
+-  ((x) == AT_PAP_TYPE_READ_LW)		? "PAP_READ_LW"          : \
+-  "<Unknown>"
+-
+ #ifndef true
+ #define true	1
+ #define false 	0
+ #endif
+ 
+ /* Globals */
+-int       gSockfd	= 0;		/* Socket descriptor                */
+-at_inet_t gSessionAddr	= { 0 };	/* Address of the session responding socket    */
+-u_char    gConnID	= 0;		/* PAP session connection id            */
+-u_short   gSendDataID	= 0;		/* Transaction id of our pending send-data request  */
+-u_short   gTickleID	= 0;		/* Transaction id of our outstanding tickle request*/
+-int       gWaitEOF	= false;	/* Option: causes us to wait for a remote's EOF  */
++int       gSockfd	= 0;		/* Socket descriptor */
++at_inet_t gSessionAddr	= { 0 };	/* Address of the session responding socket */
++u_char    gConnID	= 0;		/* PAP session connection id */
++u_short   gSendDataID	= 0;		/* Transaction id of pending send-data request  */
++u_short   gTickleID	= 0;		/* Transaction id of outstanding tickle request*/
++int       gWaitEOF	= false;	/* Option: wait for a remote's EOF  */
+ int       gStatusInterval= 5;		/* Option: 0=off else seconds between status requests*/
+ int       gErrorlogged  = false;	/* If an error was logged don't send any more INFO messages */
+-int       gDebug	= 0;		/* Option: causes us to emit debugging info    */
++int       gDebug	= 0;		/* Option: emit debugging info    */
+ 
+ /* Local functions */
+ static int listDevices(void);
+-static int printFile(char* name, char* type, char* zone, int fdin, int fdout, int fderr, int copies, int argc);
+-static int papOpen(at_nbptuple_t* tuple, u_char* connID, int* fd, at_inet_t* pap_to, u_char* flowQuantum);
+-static int papClose(int abortflag);
+-static int papWrite(int sockfd, at_inet_t* dest, u_short tid, u_char connID, u_char flowQuantum, char* data, int len, int eof);
+-static int papCloseResp(int sockfd, at_inet_t* dest, int xo, u_short tid, u_char connID);
+-static int papSendRequest(int sockfd, at_inet_t* dest, u_char connID, int function, u_char bitmap, int xo, int seqno);
++static int printFile(char* name, char* type, char* zone, int fdin, int fdout, 
++		     int fderr, int copies, int argc);
++static int papOpen(at_nbptuple_t* tuple, u_char* connID, int* fd, 
++		   at_inet_t* pap_to, u_char* flowQuantum);
++static int papClose();
++static int papWrite(int sockfd, at_inet_t* dest, u_short tid, u_char connID, 
++		    u_char flowQuantum, char* data, int len, int eof);
++static int papCloseResp(int sockfd, at_inet_t* dest, int xo, u_short tid, 
++			u_char connID);
++static int papSendRequest(int sockfd, at_inet_t* dest, u_char connID, 
++			  int function, u_char bitmap, int xo, int seqno);
+ static int papCancelRequest(int sockfd, u_short tid);
+ static void statusUpdate(char* status, u_char statusLen);
+ static int parseUri(const char* argv0, char* name, char* type, char* zone);
+@@ -170,6 +173,7 @@
+ static int removePercentEscapes(const char* src, char* dst, int dstMax);
+ static int nbptuple_compare(const void *p1, const void *p2);
+ static int okayToUseAppleTalk(void);
++static const char *packet_name(u_char x);
+ static int connectTimeout(void);
+ static void signalHandler(int sigraised);
+ 
+@@ -199,10 +203,13 @@
+ 
+   if (argc == 1 || (argc == 2 && strcmp(argv[1], "-discover") == 0))
+   {
+-    /* Ignore errors returned by listDevices - they may be transitory 
+-    *  and we don't want cupsd to think that pap is forever unusable.
++    /* If listDevices() didn't find any devices or returns an error output a 
++    *  legacy style announcement.
++    *  
+     */
+-    listDevices();
++    if (listDevices() <= 0)
++      puts("network pap \"Unknown\" \"AppleTalk Printer Access Protocol (pap)\"");
++
+     return 0;
+   }
+ 
+@@ -239,9 +246,9 @@
+   }
+ 
+   /* Extract the device name and options from the URI... */
+-  parseUri(argv[0], name, type, zone);
++  parseUri(cupsBackendDeviceURI((char **)argv), name, type, zone);
+ 
+-  err = printFile(name, type, zone, fileno(fp), 3, STDERR_FILENO, copies, argc);
++  err = printFile(name, type, zone, fileno(fp), STDOUT_FILENO, STDERR_FILENO, copies, argc);
+ 
+   if (fp != stdin)
+     fclose(fp);
+@@ -263,7 +270,7 @@
+ static int listDevices(void)
+ {
+   int  err = noErr;
+-  int  ind;
++  int  i;
+   int  numberFound;
+ 
+   at_nvestr_t   at_zone;
+@@ -287,10 +294,13 @@
+     perror("ERROR: Unable to get default AppleTalk zone");
+     return -2;
+   }
++
+   memcpy(zone, at_zone.str, MIN(at_zone.len, sizeof(zone)-1));
+   zone[MIN(at_zone.len, sizeof(zone)-1)] = '\0';
+ 
+-  err = addPercentEscapes(zone, encodedZone, sizeof(encodedZone));
++  fprintf(stderr, "INFO: Using default AppleTalk zone \"%s\"\n", zone);
++
++  addPercentEscapes(zone, encodedZone, sizeof(encodedZone));
+ 
+   /* Look up all the printers in our zone */
+   nbp_make_entity(&entity, "=", "LaserWriter", zone);
+@@ -310,10 +320,10 @@
+   /* Not required but sort them so they look nice */
+   qsort(buf, numberFound, sizeof(at_nbptuple_t), nbptuple_compare);
+ 
+-  for (ind = 0; ind < numberFound; ind++) 
++  for (i = 0; i < numberFound; i++) 
+   {
+-    memcpy(name, buf[ind].enu_entity.object.str, MIN(buf[ind].enu_entity.object.len, sizeof(name)-1));
+-    name[MIN(buf[ind].enu_entity.object.len, sizeof(name)-1)] = '\0';
++    memcpy(name, buf[i].enu_entity.object.str, MIN(buf[i].enu_entity.object.len, sizeof(name)-1));
++    name[MIN(buf[i].enu_entity.object.len, sizeof(name)-1)] = '\0';
+ 
+     if (addPercentEscapes(name, encodedName, sizeof(encodedName)) == 0)
+     {
+@@ -371,7 +381,7 @@
+   int	err;
+   int	rc;
+   int	val;
+-  int	len, ind;
++  int	len, i;
+ 
+   char	fileBuffer[4096];    /* File buffer */
+   int	fileBufferNbytes;
+@@ -390,20 +400,19 @@
+   int		userdata, xo, reqlen;
+   u_short	tid;
+   u_char	bitmap;
+-  int		maxfdp1;
++  int		maxfdp1,
++		nbp_failures = 0;
+   struct timeval timeout, *timeoutPtr;
+   u_char	flowQuantum = 1;
+   u_short	recvSequence = 0;
+   time_t	now,
+-		connect_time,
++		start_time,
+ 		elasped_time, 
+ 		sleep_time,
+ 		connect_timeout = -1,
+ 		nextStatusTime = 0;
+   at_entity_t	entity;
+   at_retry_t	retry;
+-  Boolean	recoverableErrShown = false;
+-
+ 
+ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+   struct sigaction action;  /* Actions for POSIX signals */
+@@ -420,51 +429,60 @@
+   * Remember when we started looking for the printer.
+   */
+ 
+-  connect_time = time(NULL);
++  start_time = time(NULL);
+ 
+   retry.interval = 1;
+   retry.retries  = 5;
+   retry.backoff  = 0;
+ 
++  fprintf(stderr, "STATE: +connecting-to-device\n");
++
+   /* Loop forever trying to get an open session with the printer.  */
+   for (;;)
+   {
+     /* Make sure it's okay to use appletalk */
+     if (okayToUseAppleTalk())
+     {
++      /* Clear this printer-state-reason in case we've set it */
++      fprintf(stderr, "STATE: -apple-appletalk-disabled-warning\n");
++
+       /* Resolve the name into an address. Returns the number found or an error */
+       if ((err = nbp_lookup(&entity, &tuple, 1, &retry)) > 0)
+       {
+         if (err > 1)
+           fprintf(stderr, "DEBUG: Found more than one printer with the name \"%s\"\n", name);
+ 
+-	if (recoverableErrShown)
+-	{
+-	  fprintf(stderr, "INFO: recovered: \n");
+-	  sleep(5);
+-	  recoverableErrShown = false;
++        if (nbp_failures)
++        {
++	  fprintf(stderr, "STATE: -apple-nbp-lookup-warning\n");
++	  nbp_failures = 0;
+ 	}
+ 
+         /* Open a connection to the device */
+         if ((err = papOpen(&tuple, &gConnID, &gSockfd, &gSessionAddr, &flowQuantum)) == 0)
+           break;
+ 
+-        fprintf(stderr, "WARNING: Unable to open \"%s:%s\": %s\n", name, zone, strerror(errno));
++        fprintf(stderr, "WARNING: Unable to open \"%s:%s\": %s\n", name, zone, strerror(err));
+       }
+       else
+       {
+-	fprintf(stderr, "WARNING: recoverable: Printer not responding\n");
+-	recoverableErrShown = true;
++	/* It's not unusual to have to call nbp_lookup() twice before it's sucessful... */
++        if (++nbp_failures > 2)
++        {
++	  retry.interval = 2;
++	  retry.retries = 3;
++	  fprintf(stderr, "STATE: +apple-nbp-lookup-warning\n");
++	  fprintf(stderr, "WARNING: Printer not responding\n");
++	}
+       }
+     }
+     else
+     {
+-      fprintf(stderr, "WARNING: recoverable: AppleTalk disabled in System Preferences.\n");
+-      recoverableErrShown = true;
++      fprintf(stderr, "STATE: +apple-appletalk-disabled-warning\n");
++      fprintf(stderr, "INFO: AppleTalk disabled in System Preferences.\n");
+     }
+ 
+-    retry.retries = 3;
+-    elasped_time = time(NULL) - connect_time;
++    elasped_time = time(NULL) - start_time;
+ 
+     if (connect_timeout == -1)
+       connect_timeout = connectTimeout();
+@@ -475,9 +493,9 @@
+       err = ETIMEDOUT;
+       goto Exit;					 	/* Waiting too long... */
+     }
+-    else if (elasped_time < 30 /*(30 * 60)*/)
++    else if (elasped_time < (30 * 60))
+       sleep_time = 10;					/* Waiting < 30 minutes */
+-    else if (elasped_time < 60 /*(24 * 60 * 60)*/)
++    else if (elasped_time < (24 * 60 * 60))
+       sleep_time = 30;					/* Waiting < 24 hours */
+     else
+       sleep_time = 60;					/* Waiting > 24 hours */
+@@ -486,6 +504,8 @@
+     sleep(sleep_time);
+   }
+ 
++  fprintf(stderr, "STATE: -connecting-to-device\n");
++
+   /*
+   * Now that we are connected to the printer ignore SIGTERM so that we
+   * can finish out any page data the driver sends (e.g. to eject the
+@@ -536,21 +556,6 @@
+   val = fcntl(fdin, F_GETFL, 0);
+   fcntl(fdin, F_SETFL, val | O_NONBLOCK);
+ 
+-  /* Set non-blocking mode on our data destination descriptor */
+-  val = fcntl(fdout, F_GETFL, 0);
+-  if (val < 0)
+-  {
+-   /*
+-    * Map output to stdout if we don't have the backchannel pipe
+-    * available on file descriptor 3...
+-    */
+-
+-    if (fdout == 3 && errno == EBADF)
+-      fdout = 1;
+-  }
+-  else
+-    fcntl(fdout, F_SETFL, val | O_NONBLOCK);
+-
+   fileBufferNbytes = 0;
+   fileTbytes = 0;
+   fileEOFRead = fileEOFSent = false;
+@@ -666,7 +671,7 @@
+         }
+       }
+ 
+-      fprintf(stderr, "DEBUG: <- %s\n", PAPPacketStr(TYPE_OF(userdata)));
++      fprintf(stderr, "DEBUG: <- %s\n", packet_name(TYPE_OF(userdata)));
+ 
+       switch (TYPE_OF(userdata))
+       {
+@@ -707,10 +712,10 @@
+         break;
+     
+       case AT_PAP_TYPE_DATA:              /* Data packet */
+-        for (len=0, ind=0; ind < ATP_TRESP_MAX; ind++)
++        for (len=0, i=0; i < ATP_TRESP_MAX; i++)
+         {
+-          if (resp.bitmap & (1 << ind))
+-            len += resp.resp[ind].iov_len;
++          if (resp.bitmap & (1 << i))
++            len += resp.resp[i].iov_len;
+         }
+ 
+         fprintf(stderr, "DEBUG: <- PAP_DATA %d bytes %s\n", len, IS_PAP_EOF(userdata) ? "with EOF" : "");
+@@ -722,7 +727,7 @@
+           char logstr[512];
+           int  logstrlen;
+           
+-	  write(fdout, sockBuffer, len);
++	  cupsBackChannelWrite(sockBuffer, len, 1.0);
+           
+           sockBuffer[len] = '\0';     /* We always reserve room for the nul so we can use strstr() below*/
+           pLineBegin = sockBuffer;
+@@ -835,7 +840,7 @@
+   /*
+   * Close the socket and return...
+   */
+-  papClose(false);
++  papClose();
+ 
+   return err;
+ }
+@@ -854,37 +859,35 @@
+  *
+  * @result    A non-zero return value for errors
+  */
+-static int papOpen(at_nbptuple_t* tuple, u_char* connID, int* fd, at_inet_t* sessionAddr, u_char* flowQuantum)
++static int papOpen(at_nbptuple_t* tuple, u_char* connID, int* fd, 
++		   at_inet_t* sessionAddr, u_char* flowQuantum)
+ {
+   int		result,
+-		openResult;
+-  long		tm;
+-  char		data[10], rdata[ATP_DATA_SIZE];
+-  int		userdata;
+-  u_char	*puserdata = (u_char *)&userdata;
+-  at_socket	sock = 0;
+-  u_short	waitTime;
+-  int		status;
++		open_result,
++		userdata,
++		atp_err;
++  time_t	tm,
++		waitTime;
++  char		data[10], 
++		rdata[ATP_DATA_SIZE];
++  u_char	*puserdata;
++  at_socket	socketfd;
+   at_resp_t	resp;
+   at_retry_t	retry;
+ 
+-  if (tuple == NULL)
+-  {
+-    errno = EINVAL;
+-    return -1;
+-  }
++  result    = 0;
++  socketfd  = 0;
++  puserdata = (u_char *)&userdata;
+ 
+   fprintf(stderr, "INFO: Opening connection\n");
+ 
+-  errno  = 0;
+-  result  = 0;
+-
+-  *fd = atp_open(&sock);
+-  if (*fd < 0)
++  if ((*fd = atp_open(&socketfd)) < 0)
+     return -1;
+ 
+-  /* Build the open connection request packet.
++ /* 
++  * Build the open connection request packet.
+   */
++
+   tm = time(NULL);
+   srand(tm);
+ 
+@@ -901,64 +904,67 @@
+   resp.resp[0].iov_base = rdata;
+   resp.resp[0].iov_len = sizeof(rdata);
+ 
+-  data[0] = sock;
++  data[0] = socketfd;
+   data[1] = 8;
+ 
+   for (;;)
+   {
+-    waitTime = (u_short)(time(NULL) - tm);
+-    OSWriteBigInt16(&data[2], 0, waitTime);
+-
+-    fprintf(stderr, "DEBUG: -> %s\n", PAPPacketStr(AT_PAP_TYPE_OPEN_CONN));
++    waitTime = time(NULL) - tm;
++    OSWriteBigInt16(&data[2], 0, (u_short)waitTime);
+ 
+-    status = atp_sendreq(*fd, &tuple->enu_addr, data, 4, userdata, 1, 0, 0, &resp, &retry, 0);
++    fprintf(stderr, "DEBUG: -> %s\n", packet_name(AT_PAP_TYPE_OPEN_CONN));
+ 
+-    if (status < 0)
++    if ((atp_err = atp_sendreq(*fd, &tuple->enu_addr, data, 4, userdata, 1, 0, 
++			       0, &resp, &retry, 0)) < 0)
+     {
+       statusUpdate("Destination unreachable", 23);
+       result = EHOSTUNREACH;
+-      errno = EHOSTUNREACH;
+-      sleep(1);
+-      goto Exit;
++      break;
+     }
+-    else
+-    {
+-      puserdata = (u_char *)&resp.userdata[0];
+-      openResult = OSReadBigInt16(&rdata[2], 0);
+ 
+-      fprintf(stderr, "DEBUG: <- %s, status %d\n", PAPPacketStr(puserdata[1]), openResult);
++    puserdata = (u_char *)&resp.userdata[0];
++    open_result = OSReadBigInt16(&rdata[2], 0);
+ 
+-      /* Just for the sake of our sanity check the other fields in the packet
+-      */
+-      if (puserdata[1] != AT_PAP_TYPE_OPEN_CONN_REPLY ||
+-        (openResult == 0 && (puserdata[0] & 0xff) != *connID))
+-      {
+-	result = EINVAL;
+-	errno = EINVAL;
+-	goto Exit;
+-      }
+-  
+-      statusUpdate(&rdata[5], rdata[4] & 0xff);
++    fprintf(stderr, "DEBUG: <- %s, status %d\n", packet_name(puserdata[1]), 
++	    open_result);
+ 
+-      if (openResult == 0)
+-	break;        /* Connection established okay, exit from the loop */
++   /*
++    * Just for the sake of our sanity check the other fields in the packet
++    */
++
++    if (puserdata[1] != AT_PAP_TYPE_OPEN_CONN_REPLY ||
++	(open_result == 0 && (puserdata[0] & 0xff) != *connID))
++    {
++      result = EINVAL;
++      break;
+     }
+ 
++    statusUpdate(&rdata[5], rdata[4] & 0xff);
++
++   /*
++    * if the connection established okay exit from the loop
++    */
++
++    if (open_result == 0)
++      break;
++
+     sleep(1);
+   }
+ 
+-  /* Update the session address
+-  */
+-  sessionAddr->net  = tuple->enu_addr.net;
+-  sessionAddr->node  = tuple->enu_addr.node;
+-  sessionAddr->socket  = rdata[0];
+-  *flowQuantum    = rdata[1];
+-
+-Exit:
+-  if (result != 0)
++  if (result == 0)
++  {
++    /* Update the session address
++    */
++    sessionAddr->net  = tuple->enu_addr.net;
++    sessionAddr->node  = tuple->enu_addr.node;
++    sessionAddr->socket  = rdata[0];
++    *flowQuantum    = rdata[1];
++  }
++  else
+   {
+     atp_close(*fd);
+     *fd = 0;
++    sleep(1);
+   }
+ 
+   return result;
+@@ -970,12 +976,9 @@
+  * @abstract  End a PAP session by canceling outstanding send-data & tickle 
+  *            transactions and sending a PAP close request.
+  *
+- * @param  abort  If we're aborting then send the close request 
+- *		  with 0 retries (not yet implemented)
+- *
+  * @result  A non-zero return value for errors
+  */
+-static int papClose(int abortflag)
++static int papClose()
+ {
+   int		fd;
+   u_short	tmpID;
+@@ -1018,7 +1021,7 @@
+     if (gWaitEOF == false)
+       sleep(2);
+ 
+-    fprintf(stderr, "DEBUG: -> %s\n", PAPPacketStr(AT_PAP_TYPE_CLOSE_CONN));
++    fprintf(stderr, "DEBUG: -> %s\n", packet_name(AT_PAP_TYPE_CLOSE_CONN));
+   
+     puserdata[0] = gConnID;
+     puserdata[1] = AT_PAP_TYPE_CLOSE_CONN;
+@@ -1058,7 +1061,7 @@
+ static int papWrite(int sockfd, at_inet_t* dest, u_short tid, u_char connID, u_char flowQuantum, char* data, int len, int eof)
+ {
+   int		result;
+-  int		ind;
++  int		i;
+   u_char*	puserdata;
+   at_resp_t	resp;
+ 
+@@ -1076,26 +1079,26 @@
+   * response packets to reply to an incoming
+   * PAP 'SENDDATA' request
+   */
+-  for (ind = 0; ind < flowQuantum; ind++)
++  for (i = 0; i < flowQuantum; i++)
+   {
+-    resp.userdata[ind] = 0;
+-    puserdata = (u_char *)&resp.userdata[ind];
++    resp.userdata[i] = 0;
++    puserdata = (u_char *)&resp.userdata[i];
+ 
+     puserdata[PAP_CONNID]  = connID;
+     puserdata[PAP_TYPE]    = AT_PAP_TYPE_DATA;
+     puserdata[PAP_EOF]    = eof ? 1 : 0;
+ 
+-    resp.resp[ind].iov_base = (caddr_t)data;
++    resp.resp[i].iov_base = (caddr_t)data;
+ 
+     if (data)
+       data += AT_PAP_DATA_SIZE;
+ 
+-    resp.resp[ind].iov_len = MIN((int)len, (int)AT_PAP_DATA_SIZE);
+-    len -= resp.resp[ind].iov_len;
++    resp.resp[i].iov_len = MIN((int)len, (int)AT_PAP_DATA_SIZE);
++    len -= resp.resp[i].iov_len;
+     if (len == 0)
+       break;
+   }
+-  resp.bitmap = (1 << (ind + 1)) - 1;
++  resp.bitmap = (1 << (i + 1)) - 1;
+ 
+   /*
+   *  Write out the data as a PAP 'DATA' response
+@@ -1168,7 +1171,7 @@
+   at_resp_t	resp;
+   static u_short pap_send_count = 0;
+ 
+-  fprintf(stderr, "DEBUG: -> %s\n", PAPPacketStr(function));
++  fprintf(stderr, "DEBUG: -> %s\n", packet_name(function));
+ 
+   puserdata[0] = connID;
+   puserdata[1] = function;
+@@ -1274,7 +1277,7 @@
+  */
+ static int parseUri(const char* argv0, char* name, char* type, char* zone)
+ {
+-  char  scheme[255],		/* Scheme in URI */
++  char  method[255],		/* Method in URI */
+         hostname[1024],		/* Hostname */
+         username[255],		/* Username info (not used) */
+         resource[1024],		/* Resource info (device and options) */
+@@ -1290,8 +1293,10 @@
+   /*
+   * Extract the device name and options from the URI...
+   */
++  method[0] = username[0] = hostname[0] = resource[0] = '\0';
++  port = 0;
+ 
+-  httpSeparateURI(HTTP_URI_CODING_NONE, argv0, scheme, sizeof(scheme), 
++  httpSeparateURI(HTTP_URI_CODING_NONE, argv0, method, sizeof(method), 
+ 		  username, sizeof(username),
+ 		  hostname, sizeof(hostname), &port,
+ 		  resource, sizeof(resource));
+@@ -1528,6 +1533,31 @@
+ 
+ 
+ /*!
++ * @function  packet_name
++ * @abstract  Returns packet name string.
++ *
++ * @result    A string
++ */
++static const char *packet_name(u_char x)
++{
++  switch (x)
++  {
++  case AT_PAP_TYPE_OPEN_CONN:		return "PAP_OPEN_CONN";
++  case AT_PAP_TYPE_OPEN_CONN_REPLY:	return "PAP_OPEN_CONN_REPLY";
++  case AT_PAP_TYPE_SEND_DATA:		return "PAP_SEND_DATA";
++  case AT_PAP_TYPE_DATA:		return "PAP_DATA";
++  case AT_PAP_TYPE_TICKLE:		return "PAP_TICKLE";
++  case AT_PAP_TYPE_CLOSE_CONN:		return "PAP_CLOSE_CONN";
++  case AT_PAP_TYPE_CLOSE_CONN_REPLY:	return "PAP_CLOSE_CONN_REPLY";
++  case AT_PAP_TYPE_SEND_STATUS:		return "PAP_SEND_STATUS";
++  case AT_PAP_TYPE_SEND_STS_REPLY:	return "PAP_SEND_STS_REPLY";
++  case AT_PAP_TYPE_READ_LW:		return "PAP_READ_LW";
++  }
++  return "<Unknown>";
++}
++
++
++/*!
+  * @function  connectTimeout
+  * @abstract  Returns the connect timeout preference value.
+  */
+@@ -1562,7 +1592,7 @@
+ {
+   fprintf(stderr, "ERROR: There was a timeout error while sending data to the printer\n");
+ 
+-  papClose(true);
++  papClose();
+ 
+   _exit(1);
+ }
+diff -urNad cupsys-1.2.6~/backend/snmp.c cupsys-1.2.6/backend/snmp.c
+--- cupsys-1.2.6~/backend/snmp.c	2006-10-21 00:07:21.000000000 +0900
++++ cupsys-1.2.6/backend/snmp.c	2006-11-15 09:51:22.000000000 +0900
+@@ -1126,7 +1126,7 @@
+ {
+   if (integer > 0xfffffff)
+   {
+-    **buffer = (integer >> 14) & 0x7f;
++    **buffer = (integer >> 28) & 0x7f;
+     (*buffer) ++;
+   }
+ 
+@@ -1752,7 +1752,7 @@
+     alarm(0);
+   }
+ 
+-  if (http);
++  if (http)
+   {
+    /*
+     * IPP is supported...
+diff -urNad cupsys-1.2.6~/backend/usb-darwin.c cupsys-1.2.6/backend/usb-darwin.c
+--- cupsys-1.2.6~/backend/usb-darwin.c	2006-06-06 03:42:53.000000000 +0900
++++ cupsys-1.2.6/backend/usb-darwin.c	2006-11-15 09:51:22.000000000 +0900
+@@ -198,12 +198,13 @@
+ 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 load_printerdriver(printer_data_t *printer, CFStringRef *driverBundlePath);
++static kern_return_t registry_open(printer_data_t *printer, CFStringRef *driverBundlePath);
+ 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 CFStringRef cfstr_create_and_trim(const char *cstr);
+ static void parse_options(const char *options, char *serial, UInt32 *location, Boolean *waitEOF);
+ static void setup_cfLanguage(void);
+ static void *read_thread(void *reference);
+@@ -255,6 +256,7 @@
+   int		  countdown = INITIAL_LOG_INTERVAL;	/* Logging interval */
+   pthread_cond_t  *readCompleteConditionPtr = NULL;	/* Read complete condition */
+   pthread_mutex_t *readMutexPtr = NULL;			/* Read mutex */
++  CFStringRef	  driverBundlePath;			/* Class driver path */
+ 
+   setup_cfLanguage();
+   parse_options(options, serial, &printer_data.location, &printer_data.waitEOF);
+@@ -263,9 +265,10 @@
+     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);
++  
++  printer_data.make   = cfstr_create_and_trim(hostname);
++  printer_data.model  = cfstr_create_and_trim(resource);
++  printer_data.serial = cfstr_create_and_trim(serial);
+ 
+   fputs("STATE: +connecting-to-device\n", stderr);
+ 
+@@ -281,7 +284,9 @@
+     iterate_printers(find_device_callback, &printer_data);		
+ 
+     fprintf(stderr, "INFO: Opening Connection\n");
+-    status = registry_open(&printer_data);
++
++    driverBundlePath = NULL;
++    status = registry_open(&printer_data, &driverBundlePath);
+ #if defined(__i386__)
+     /*
+      * If we were unable to load the class drivers for this printer it's probably because they're ppc-only.
+@@ -292,6 +297,26 @@
+       /* Never returns here */
+     }
+ #endif /* __i386__ */
++    if (status ==  -2) {
++     /*
++      * If we still were unable to load the class drivers for this printer log
++      * the error and stop the queue...
++      */
++
++      if (driverBundlePath == NULL || !CFStringGetCString(driverBundlePath, buffer, sizeof(buffer), kCFStringEncodingUTF8))
++        strlcpy(buffer, "USB class driver", sizeof(buffer));
++
++      fprintf(stderr, "STATE: +apple-missing-usbclassdriver-error\n" \
++		      "FATAL: Could not load %s\n", buffer);
++
++      if (driverBundlePath)
++	CFRelease(driverBundlePath);
++
++      return CUPS_BACKEND_STOP;
++    }
++
++    if (driverBundlePath)
++      CFRelease(driverBundlePath);
+ 
+     if (status != noErr) {
+       sleep( PRINTER_POLLING_INTERVAL );
+@@ -508,7 +533,7 @@
+       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) {
++	    if (serial != NULL && CFStringCompare(serial, userData->serial, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
+ 	      IOObjectRetain(obj);
+ 	      userData->printerObj = obj;
+ 	      keepLooking = false;
+@@ -728,9 +753,11 @@
+ 
+ /*
+  * 'load_printerdriver()' - Load a vendor's (or generic) classdriver.
++ *
++ * If driverBundlePath is not NULL on return it is the callers responsbility to release it!
+  */
+ 
+-static kern_return_t load_printerdriver(printer_data_t *printer)
++static kern_return_t load_printerdriver(printer_data_t *printer, CFStringRef *driverBundlePath)
+ {
+   IOCFPlugInInterface **iodev = NULL;
+   SInt32 score;
+@@ -744,11 +771,10 @@
+ 
+       kr = IORegistryEntryCreateCFProperties(printer->printerObj, &properties, NULL, kNilOptions);
+       if (kr == kIOReturnSuccess) {
+-	CFStringRef driverBundlePath = NULL;
+ 	if (properties != NULL) {
+-	  driverBundlePath = (CFStringRef) CFDictionaryGetValue(properties, kUSBClassDriverProperty);
++	  *driverBundlePath = (CFStringRef) CFDictionaryGetValue(properties, kUSBClassDriverProperty);
+ 	}
+-	kr = load_classdriver(driverBundlePath, intf, &printer->printerDriver);
++	kr = load_classdriver(*driverBundlePath, intf, &printer->printerDriver);
+       }
+ 
+       if (kr != kIOReturnSuccess)
+@@ -764,9 +790,9 @@
+  * 'registry_open()' - Open a connection to the printer.
+  */
+ 
+-static kern_return_t registry_open(printer_data_t *printer)
++static kern_return_t registry_open(printer_data_t *printer, CFStringRef *driverBundlePath)
+ {
+-  kern_return_t kr = load_printerdriver(printer);
++  kern_return_t kr = load_printerdriver(printer, driverBundlePath);
+   if (kr != kIOReturnSuccess) {
+     kr = -2;
+   }
+@@ -975,6 +1001,27 @@
+ }
+ 
+ 
++/*
++ * 'cfstr_create_and_trim()' - Create a CFString from a c-string and 
++ *			       trim it's whitespace characters.
++ */
++
++CFStringRef cfstr_create_and_trim(const char *cstr)
++{
++  CFStringRef		cfstr;
++  CFMutableStringRef	cfmutablestr = NULL;
++  
++  if ((cfstr = CFStringCreateWithCString(NULL, cstr, kCFStringEncodingUTF8)) != NULL)
++  {
++    if ((cfmutablestr = CFStringCreateMutableCopy(NULL, 1024, cfstr)) != NULL)
++      CFStringTrimWhitespace(cfmutablestr);
++
++    CFRelease(cfstr);
++  }
++  return (CFStringRef) cfmutablestr;
++}
++
++
+ #pragma mark -
+ /*
+  * 'parse_options()' - Parse uri options.
+@@ -1344,7 +1391,6 @@
+   return NULL;
+ }
+ 
+-
+ /*
+  * End of "$Id: usb-darwin.c 5630 2006-06-05 18:42:53Z mike $".
+  */
+diff -urNad cupsys-1.2.6~/backend/usb-darwin.c.orig cupsys-1.2.6/backend/usb-darwin.c.orig
+--- cupsys-1.2.6~/backend/usb-darwin.c.orig	1970-01-01 09:00:00.000000000 +0900
++++ cupsys-1.2.6/backend/usb-darwin.c.orig	2006-06-06 03:42:53.000000000 +0900
+@@ -0,0 +1,1350 @@
++/*
++ * "$Id: usb-darwin.c 5630 2006-06-05 18:42:53Z mike $"
++ *
++ * © 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.
++ *
++ * 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.
++ *
++ * 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.
++ */
++
++/*
++ *   USB port on Darwin backend for the Common UNIX Printing System (CUPS).
++ */
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <signal.h>
++#include <fcntl.h>
++#include <termios.h>
++#include <unistd.h>
++#include <sys/sysctl.h>
++#include <libgen.h>
++#include <mach/mach.h>	
++#include <mach/mach_error.h>
++#include <mach/mach_time.h>
++#include <cups/debug.h>
++
++#include <CoreFoundation/CoreFoundation.h>
++#include <IOKit/usb/IOUSBLib.h>
++#include <IOKit/IOCFPlugIn.h>
++
++#include <pthread.h>
++
++/* 
++ * 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	USB_INTERFACE_KIND		CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190)
++#define kUSBLanguageEnglish		0x409
++
++#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 kUSBClassDriverProperty		CFSTR("USB Printing Class")
++
++#define kUSBGenericTOPrinterClassDriver	CFSTR("/System/Library/Printers/Libraries/USBGenericTOPrintingClass.plugin")
++#define kUSBPrinterClassDeviceNotOpen	-9664	/*kPMInvalidIOMContext*/
++
++
++#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 iodevice_request_s		/**** Device request ****/
++{
++  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;		/* 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 );
++
++  /* 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 );
++
++  /* 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 );
++
++  /* 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 );
++
++} classdriver_context_t;
++
++
++typedef Boolean (*iterator_callback_t)(void *refcon, io_service_t obj);
++
++typedef struct iterator_reference_s {		/**** Iterator reference data */
++  iterator_callback_t callback;
++  void		*userdata;
++  Boolean	keepRunning;
++} iterator_reference_t;
++
++typedef struct printer_data_s {			/**** Printer context data ****/
++  io_service_t		  printerObj;
++  classdriver_context_t  **printerDriver;
++
++  pthread_cond_t	readCompleteCondition;
++  pthread_mutex_t	readMutex;
++  int			done;
++
++  const char		*uri;
++  CFStringRef		make;
++  CFStringRef		model;
++  CFStringRef		serial;
++
++  UInt32		location;
++  Boolean		waitEOF;
++
++} printer_data_t;
++
++
++/*
++ * Local functions...
++ */
++
++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 -
++
++/*
++ * 'list_devices()' - List all USB devices.
++ */
++
++void list_devices()
++{
++  iterate_printers(list_device_callback, NULL);
++}
++
++
++/*
++ * 'print_device()' - Print a file to a USB device.
++ */
++
++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 */
++{
++  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;
++    }
++
++    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 */
++    }
++#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);
++
++  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...)
++   */
++
++  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));
++
++    sigemptyset(&action.sa_mask);
++    action.sa_handler = SIG_IGN;
++    sigaction(SIGTERM, &action, NULL);
++#else
++    signal(SIGTERM, SIG_IGN);
++#endif /* HAVE_SIGSET */
++  }
++
++  if (status == noErr) {
++    if (pthread_cond_init(&printer_data.readCompleteCondition, NULL) == 0)	
++      readCompleteConditionPtr = &printer_data.readCompleteCondition;
++
++    if (pthread_mutex_init(&printer_data.readMutex, NULL) == 0)
++      readMutexPtr = &printer_data.readMutex;
++
++    if (pthread_create(&thr, NULL, read_thread, &printer_data) == 0)
++      thread_created = 1;
++
++    if (thread_created == 0) 
++      fprintf(stderr, "WARNING: Couldn't create read channel\n");
++  }
++
++  /*
++   * The main thread sends the print file...
++   */
++
++  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 */
++
++    fprintf(stderr, "INFO: Sending data\n");
++
++    if (STDIN_FILENO != fd) {
++      fputs("PAGE: 1 1", stderr);
++      lseek( fd, 0, SEEK_SET );
++    }
++
++    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;
++	}
++
++	nbytes -= wbytes;
++	bufptr += wbytes;
++      }
++
++      if (fd != 0 && status == noErr)
++	fprintf(stderr, "DEBUG: Sending print file, %qd bytes...\n", (off_t)tbytes);
++    }
++  }
++
++  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 */
++  }
++
++  /*
++   * Close the connection and input file and general clean up...
++   */
++  registry_close(&printer_data);
++
++  if (STDIN_FILENO != fd)
++    close(fd);
++
++  if (readCompleteConditionPtr != NULL)
++    pthread_cond_destroy(&printer_data.readCompleteCondition);
++
++  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_device_callback()' - list_device iterator callback.
++ */
++
++static Boolean list_device_callback(void *refcon, io_service_t obj)
++{
++  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];
++      char idstr[1024];
++
++      copy_deviceinfo(deviceIDString, &make, &model, &serial);
++
++      modelstr[0] = '/';
++
++      CFStringGetCString(deviceIDString, idstr, sizeof(idstr),    kCFStringEncodingUTF8);
++      CFStringGetCString(make, makestr, sizeof(makestr),    kCFStringEncodingUTF8);
++      CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1, kCFStringEncodingUTF8);
++
++     /*
++      * Fix common HP 1284 bug...
++      */
++
++      if (!strcasecmp(makestr, "Hewlett-Packard"))
++        strcpy(makestr, "HP");
++
++      if (!strncasecmp(modelstr + 1, "hp ", 3))
++        _cups_strcpy(modelstr + 1, modelstr + 4);
++
++      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 %s USB\" \"%s\"\n", uristr, makestr,
++             &modelstr[1], makestr, &modelstr[1], idstr);
++
++      release_deviceinfo(&make, &model, &serial);
++      CFRelease(deviceIDString);
++    }
++  }
++
++  return keepRunning;
++}
++
++
++/*
++ * 'find_device_callback()' - print_device iterator callback.
++ */
++
++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 (userData->printerObj != 0) {
++	      IOObjectRetain(userData->printerObj);
++	    }
++	    userData->printerObj = obj;
++	    IOObjectRetain(obj);
++
++	    if (userData->location == 0 || userData->location == location) {
++	      keepLooking = false;
++	    }
++	  }
++	}
++      }
++
++      release_deviceinfo(&make, &model, &serial);
++      CFRelease(idString);
++    }
++  }
++  else {		
++    keepLooking = (refcon != NULL && ((printer_data_t *)refcon)->printerObj == 0);
++  }
++
++  return keepLooking;
++}
++
++
++#pragma mark -
++/*
++ * 'iterate_printers()' - iterate over all the printers.
++ */
++
++static void iterate_printers(iterator_callback_t callBack, void *userdata)
++{
++  mach_port_t	masterPort = 0x0;
++  kern_return_t kr = IOMasterPort (bootstrap_port, &masterPort);
++
++  if (kr == kIOReturnSuccess && masterPort != 0x0) {
++    io_iterator_t addIterator = 0x0;
++
++    iterator_reference_t reference = { callBack, userdata, true };
++    IONotificationPortRef addNotification = IONotificationPortCreate(masterPort);
++
++    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);
++
++    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);
++  }
++}
++
++
++/*
++ * 'device_added()' - device added notifier.
++ */
++
++static void device_added(void *userdata, io_iterator_t iterator)
++{	
++  iterator_reference_t *reference = userdata;
++
++  io_service_t obj;
++  while (reference->keepRunning && (obj = IOIteratorNext(iterator)) != 0x0) {
++    if (reference->callback != NULL) {
++      reference->keepRunning = reference->callback(reference->userdata, obj);
++    }
++    IOObjectRelease(obj);
++  }
++
++  /* 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);
++
++  if (!reference->keepRunning) {
++    CFRunLoopStop(CFRunLoopGetCurrent());
++  }
++}
++
++
++#pragma mark -
++/*
++ * 'copy_deviceinfo()' - Copy strings from the 1284 device ID.
++ */
++
++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);
++}
++
++
++/*
++ * 'release_deviceinfo()' - Release deviceinfo strings.
++ */
++
++static void release_deviceinfo(CFStringRef *make, CFStringRef *model, CFStringRef *serial)
++{
++  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);
++      }
++    }
++  }
++
++#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 kr;
++}
++
++
++/*
++ * 'unload_classdriver()' - Unload a classdriver.
++ */
++
++static kern_return_t unload_classdriver(classdriver_context_t ***classDriver)
++{
++  if (*classDriver != NULL) {
++    (**classDriver)->Release(*classDriver);
++    *classDriver = NULL;
++  }
++
++  return kIOReturnSuccess;
++}
++
++
++/*
++ * 'load_printerdriver()' - Load a vendor's (or generic) classdriver.
++ */
++
++static kern_return_t load_printerdriver(printer_data_t *printer)
++{
++  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;
++	}
++      }
++    }
++  }
++
++  if (kr != kIOReturnSuccess) {
++    unload_classdriver(&printer->printerDriver);
++  }
++
++  return kr;
++}
++
++
++/*
++ * 'registry_close()' - Close the connection to the printer.
++ */
++
++static kern_return_t registry_close(printer_data_t *printer)
++{
++  if (printer->printerDriver != NULL) {
++    (*(printer->printerDriver))->Close(printer->printerDriver);
++  }
++  unload_classdriver(&printer->printerDriver);
++  return kIOReturnSuccess;
++}
++
++
++/*
++ * 'copy_deviceid()' - Copy the 1284 device id string.
++ */
++
++static OSStatus copy_deviceid(classdriver_context_t **printer, CFStringRef *deviceID)
++{
++  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);
++	}
++      }
++
++      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 (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);
++	}
++      }
++
++      if (devID != NULL) {
++	CFStringAppend(newDevID, devID);
++	CFRelease(devID);
++      }
++
++      *deviceID = newDevID;
++    }
++  }
++  else {
++    *deviceID = devID;
++  }
++  release_deviceinfo(&deviceMake, &deviceModel, &deviceSerial);
++
++  return err;
++}
++
++
++/*
++ * 'copy_devicestring()' - Copy the 1284 device id string.
++ */
++
++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);
++	}
++
++	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);
++
++	if (properties != NULL)
++	  CFRelease(properties);
++      }
++
++      /* (*intf)->Release(intf); */
++    }		
++    IODestroyPlugInInterface(iodev);
++  }
++}
++
++
++#pragma mark -
++/*
++ * 'copy_value_for_key()' - Copy value string associated with a key.
++ */
++
++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);
++
++	  CFStringTrimWhitespace(theString2);
++	  value = theString2;
++	}
++      }
++      idxx++;
++    }
++    idx++;
++  }
++
++  if (kvPairs != NULL)
++    CFRelease(kvPairs);	
++  return value;
++}
++
++
++#pragma mark -
++/*
++ * 'parse_options()' - Parse uri options.
++ */
++
++static void parse_options(const char *options, char *serial, UInt32 *location, Boolean *waitEOF)
++{
++  char	*serialnumber;		/* ?serial=<serial> or ?location=<location> */
++  char	optionName[255],	/* Name of option */
++	value[255],		/* Value of option */
++	*ptr;			/* Pointer into name or value */
++
++  if (serial)
++    *serial = '\0';
++  if (location)
++    *location = 0;
++
++  if (!options)
++    return;
++
++  serialnumber = NULL;
++
++  while (*options != '\0') {
++    /* Get the name... */
++    for (ptr = optionName; *options && *options != '=' && *options != '+'; )
++      *ptr++ = *options++;
++
++    *ptr = '\0';
++    value[0] = '\0';
++
++    if (*options == '=') {
++      /* Get the value... */
++      options ++;
++
++      for (ptr = value; *options && *options != '+';)
++	*ptr++ = *options++;
++
++      *ptr = '\0';
++
++      if (*options == '+')
++	options ++;
++    }
++    else if (*options == '+') {
++      options ++;
++    }
++
++    /*
++     * 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);
++    }
++  }
++
++  return;
++}
++
++
++/*!
++ * @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");
++  }
++}
++
++#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;
++
++  /*
++   * 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...)
++     */
++
++    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 */
++    }
++
++    if ((child_pid = fork()) == 0) {
++      /* Child comes here. */
++      setenv("USB_PPC_STATUS", "1", false);
++
++      /* 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);
++
++      /* 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];
++
++      my_argv[i] = NULL;
++
++      execv("/usr/libexec/cups/backend/usb", my_argv);
++
++      fprintf(stderr, "DEBUG: execv: %s\n", strerror(errno));
++      exitstatus = errno;
++    }
++    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);
++      }
++    }
++    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;
++  }
++
++  exit(exitstatus);
++}
++
++/*
++ * 'sigterm_handler()' - SIGTERM handler.
++ */
++
++static void sigterm_handler(int sig)
++{
++  /* If we started a child process pass the signal on to it...
++   */
++  if (child_pid)
++    kill(child_pid, sig);
++
++  exit(1);
++}
++
++#endif /* __i386__ */
++
++
++#ifdef PARSE_PS_ERRORS
++/*
++ * 'next_line()' - Find the next line in a buffer.
++ */
++
++static const char *next_line (const char *buffer)
++{
++  const char *cptr, *lptr = NULL;
++
++  for (cptr = buffer; *cptr && lptr == NULL; cptr++)
++    if (*cptr == '\n' || *cptr == '\r')
++      lptr = cptr;
++  return lptr;
++}
++
++
++/*
++ * 'parse_pserror()' - Scan the backchannel data for postscript errors.
++ */
++
++static void parse_pserror (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 *)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);
++    }
++
++    /* move everything over... */
++    strcpy(gErrorBuffer, pLineEnd);
++    gErrorBufferPtr = gErrorBuffer;
++    pLineEnd = (char *)next_line((const char *)gErrorBuffer);
++  }
++}
++#endif /* PARSE_PS_ERRORS */
++
++
++/*
++ * 'read_thread()' - A thread to read the backchannel data.
++ */
++
++static void *read_thread(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;
++  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);
++    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
++    }
++
++    /* 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 */
++
++  /* 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 5630 2006-06-05 18:42:53Z mike $".
++ */
+diff -urNad cupsys-1.2.6~/config-scripts/cups-common.m4 cupsys-1.2.6/config-scripts/cups-common.m4
+--- cupsys-1.2.6~/config-scripts/cups-common.m4	2006-11-07 05:06:28.000000000 +0900
++++ cupsys-1.2.6/config-scripts/cups-common.m4	2006-11-15 09:51:42.000000000 +0900
+@@ -1,5 +1,5 @@
+ dnl
+-dnl "$Id: cups-common.m4 6052 2006-10-20 20:35:41Z mike $"
++dnl "$Id: cups-common.m4 6092 2006-11-14 16:36:36Z mike $"
+ dnl
+ dnl   Common configuration stuff for the Common UNIX Printing System (CUPS).
+ dnl
+@@ -28,12 +28,9 @@
+ dnl Set the name of the config header file...
+ AC_CONFIG_HEADER(config.h)
+ 
+-dnl Versio number information...
+-CUPS_VERSION=1.2.6
+-CUPS_REVISION=
+-if test -z "$CUPS_REVISION" -a -d .svn; then
+-	CUPS_REVISION="-r`svnversion . | awk -F: '{print $NF}' | sed -e '1,$s/[[a-zA-Z]]*//g'`"
+-fi
++dnl Version number information...
++CUPS_VERSION="1.2.7"
++CUPS_REVISION=""
+ 
+ AC_SUBST(CUPS_VERSION)
+ AC_SUBST(CUPS_REVISION)
+@@ -267,5 +264,5 @@
+ AC_DEFINE_UNQUOTED(CUPS_DEFAULT_IPP_PORT,$DEFAULT_IPP_PORT)
+ 
+ dnl
+-dnl End of "$Id: cups-common.m4 6052 2006-10-20 20:35:41Z mike $".
++dnl End of "$Id: cups-common.m4 6092 2006-11-14 16:36:36Z mike $".
+ dnl
+diff -urNad cupsys-1.2.6~/cups/cups.h cupsys-1.2.6/cups/cups.h
+--- cupsys-1.2.6~/cups/cups.h	2006-10-21 05:35:41.000000000 +0900
++++ cupsys-1.2.6/cups/cups.h	2006-11-15 09:51:22.000000000 +0900
+@@ -61,10 +61,10 @@
+  * Constants...
+  */
+ 
+-#  define CUPS_VERSION		1.0206
++#  define CUPS_VERSION		1.0207
+ #  define CUPS_VERSION_MAJOR	1
+ #  define CUPS_VERSION_MINOR	2
+-#  define CUPS_VERSION_PATCH	6
++#  define CUPS_VERSION_PATCH	7
+ #  define CUPS_DATE_ANY		-1
+ 
+ 
+diff -urNad cupsys-1.2.6~/cups/http-private.h cupsys-1.2.6/cups/http-private.h
+--- cupsys-1.2.6~/cups/http-private.h	2006-05-11 03:57:46.000000000 +0900
++++ cupsys-1.2.6/cups/http-private.h	2006-11-15 09:51:22.000000000 +0900
+@@ -70,7 +70,8 @@
+ #  if defined HAVE_LIBSSL
+ /*
+  * The OpenSSL library provides its own SSL/TLS context structure for its
+- * IO and protocol management...
++ * IO and protocol management.  However, we need to provide our own BIO
++ * (basic IO) implementation to do timeouts...
+  */
+ 
+ #    include <openssl/err.h>
+@@ -79,6 +80,8 @@
+ 
+ typedef SSL http_tls_t;
+ 
++extern BIO_METHOD *_httpBIOMethods(void);
++
+ #  elif defined HAVE_GNUTLS
+ /*
+  * The GNU TLS library is more of a "bare metal" SSL/TLS library...
+@@ -91,6 +94,11 @@
+   void			*credentials;	/* GNU TLS credentials object */
+ } http_tls_t;
+ 
++extern ssize_t	_httpReadGNUTLS(gnutls_transport_ptr ptr, void *data,
++		                size_t length);
++extern ssize_t	_httpWriteGNUTLS(gnutls_transport_ptr ptr, const void *data,
++		                 size_t length);
++
+ #  elif defined(HAVE_CDSASSL)
+ /*
+  * Darwin's Security framework provides its own SSL/TLS context structure
+diff -urNad cupsys-1.2.6~/cups/http.c cupsys-1.2.6/cups/http.c
+--- cupsys-1.2.6~/cups/http.c	2006-09-17 04:08:36.000000000 +0900
++++ cupsys-1.2.6/cups/http.c	2006-11-15 09:51:22.000000000 +0900
+@@ -25,6 +25,7 @@
+  *
+  * Contents:
+  *
++ *   _httpBIOMethods()    - Get the OpenSSL BIO methods for HTTP connections.
+  *   httpBlocking()       - Set blocking/non-blocking behavior on a connection.
+  *   httpCheck()          - Check to see if there is a pending response from
+  *                          the server.
+@@ -60,7 +61,8 @@
+  *   httpPut()            - Send a PUT request to the server.
+  *   httpRead()           - Read data from a HTTP connection.
+  *   httpRead2()          - Read data from a HTTP connection.
+- *   _httpReadCDSA()      - Read function for CDSA decryption code.
++ *   _httpReadCDSA()      - Read function for the CDSA library.
++ *   _httpReadGNUTLS()    - Read function for the GNU TLS library.
+  *   httpReconnect()      - Reconnect to a HTTP server...
+  *   httpSetCookie()      - Set the cookie value(s)...
+  *   httpSetExpect()      - Set the Expect: header in a request.
+@@ -71,7 +73,14 @@
+  *   httpWait()           - Wait for data available on a connection.
+  *   httpWrite()          - Write data to a HTTP connection.
+  *   httpWrite2()         - Write data to a HTTP connection.
+- *   _httpWriteCDSA()     - Write function for CDSA encryption code.
++ *   _httpWriteCDSA()     - Write function for the CDSA library.
++ *   _httpWriteGNUTLS()   - Write function for the GNU TLS library.
++ *   http_bio_ctrl()      - Control the HTTP connection.
++ *   http_bio_free()      - Free OpenSSL data.
++ *   http_bio_new()       - Initialize an OpenSSL BIO structure.
++ *   http_bio_puts()      - Send a string for OpenSSL.
++ *   http_bio_read()      - Read data for OpenSSL.
++ *   http_bio_write()     - Write data for OpenSSL.
+  *   http_field()         - Return the field index for a field name.
+  *   http_read_ssl()      - Read from a SSL/TLS connection.
+  *   http_send()          - Send a request with all fields and the trailing
+@@ -118,7 +127,7 @@
+ static http_field_t	http_field(const char *name);
+ static int		http_send(http_t *http, http_state_t request,
+ 			          const char *uri);
+-static int		http_wait(http_t *http, int msec);
++static int		http_wait(http_t *http, int msec, int usessl);
+ static int		http_write(http_t *http, const char *buffer,
+ 			           int length);
+ static int		http_write_chunk(http_t *http, const char *buffer,
+@@ -168,6 +177,45 @@
+ 			};
+ 
+ 
++#if defined(HAVE_SSL) && defined(HAVE_LIBSSL)
++/*
++ * BIO methods for OpenSSL...
++ */
++
++static int		http_bio_write(BIO *h, const char *buf, int num);
++static int		http_bio_read(BIO *h, char *buf, int size);
++static int		http_bio_puts(BIO *h, const char *str);
++static long		http_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
++static int		http_bio_new(BIO *h);
++static int		http_bio_free(BIO *data);
++
++static BIO_METHOD	http_bio_methods =
++			{
++			  BIO_TYPE_SOCKET,
++			  "http",
++			  http_bio_write,
++			  http_bio_read,
++			  http_bio_puts,
++			  NULL, /* http_bio_gets, */
++			  http_bio_ctrl,
++			  http_bio_new,
++			  http_bio_free,
++			  NULL,
++			};
++
++
++/*
++ * '_httpBIOMethods()' - Get the OpenSSL BIO methods for HTTP connections.
++ */
++
++BIO_METHOD *				/* O - BIO methods for OpenSSL */
++_httpBIOMethods(void)
++{
++  return (&http_bio_methods);
++}
++#endif /* HAVE_SSL && HAVE_LIBSSL */
++
++
+ /*
+  * 'httpBlocking()' - Set blocking/non-blocking behavior on a connection.
+  */
+@@ -869,7 +917,7 @@
+       * No newline; see if there is more data to be read...
+       */
+ 
+-      if (!http->blocking && !http_wait(http, 10000))
++      if (!http->blocking && !http_wait(http, 10000, 1))
+       {
+         DEBUG_puts("httpGets: Timed out!");
+         http->error = ETIMEDOUT;
+@@ -1391,7 +1439,7 @@
+ 
+ #if defined(HAVE_SSL) && defined(HAVE_CDSASSL)
+ /*
+- * '_httpReadCDSA()' - Read function for CDSA decryption code.
++ * '_httpReadCDSA()' - Read function for the CDSA library.
+  */
+ 
+ OSStatus				/* O  - -1 on error, 0 on success */
+@@ -1435,6 +1483,40 @@
+ #endif /* HAVE_SSL && HAVE_CDSASSL */
+ 
+ 
++#if defined(HAVE_SSL) && defined(HAVE_GNUTLS)
++/*
++ * '_httpReadGNUTLS()' - Read function for the GNU TLS library.
++ */
++
++ssize_t					/* O - Number of bytes read or -1 on error */
++_httpReadGNUTLS(
++    gnutls_transport_ptr ptr,		/* I - HTTP connection */
++    void                 *data,		/* I - Buffer */
++    size_t               length)	/* I - Number of bytes to read */
++{
++  http_t	*http;			/* HTTP connection */
++
++
++  http = (http_t *)ptr;
++
++  if (!http->blocking)
++  {
++   /*
++    * Make sure we have data before we read...
++    */
++
++    if (!http_wait(http, 10000, 0))
++    {
++      http->error = ETIMEDOUT;
++      return (-1);
++    }
++  }
++
++  return (recv(http->fd, data, length, 0));
++}
++#endif /* HAVE_SSL && HAVE_GNUTLS */
++
++
+ /*
+  * 'httpReconnect()' - Reconnect to a HTTP server.
+  */
+@@ -1830,7 +1912,7 @@
+   * If not, check the SSL/TLS buffers and do a select() on the connection...
+   */
+ 
+-  return (http_wait(http, msec));
++  return (http_wait(http, msec, 1));
+ }
+ 
+ 
+@@ -1977,7 +2059,7 @@
+ 
+ #if defined(HAVE_SSL) && defined(HAVE_CDSASSL)
+ /*
+- * '_httpWriteCDSA()' - Write function for CDSA encryption code.
++ * '_httpWriteCDSA()' - Write function for the CDSA library.
+  */
+ 
+ OSStatus				/* O  - -1 on error, 0 on success */
+@@ -2019,6 +2101,159 @@
+ #endif /* HAVE_SSL && HAVE_CDSASSL */
+ 
+ 
++#if defined(HAVE_SSL) && defined(HAVE_GNUTLS)
++/*
++ * '_httpWriteGNUTLS()' - Write function for the GNU TLS library.
++ */
++
++ssize_t					/* O - Number of bytes written or -1 on error */
++_httpWriteGNUTLS(
++    gnutls_transport_ptr ptr,		/* I - HTTP connection */
++    const void           *data,		/* I - Data buffer */
++    size_t               length)	/* I - Number of bytes to write */
++{
++  return (send(((http_t *)ptr)->fd, data, length, 0));
++}
++#endif /* HAVE_SSL && HAVE_GNUTLS */
++
++
++#if defined(HAVE_SSL) && defined(HAVE_LIBSSL)
++/*
++ * 'http_bio_ctrl()' - Control the HTTP connection.
++ */
++
++static long				/* O - Result/data */
++http_bio_ctrl(BIO  *h,			/* I - BIO data */
++              int  cmd,			/* I - Control command */
++	      long arg1,		/* I - First argument */
++	      void *arg2)		/* I - Second argument */
++{
++  switch (cmd)
++  {
++    default :
++        return (0);
++
++    case BIO_CTRL_RESET :
++        h->ptr = NULL;
++	return (0);
++
++    case BIO_C_SET_FILE_PTR :
++        h->ptr  = arg2;
++	h->init = 1;
++	return (1);
++
++    case BIO_C_GET_FILE_PTR :
++        if (arg2)
++	{
++	  *((void **)arg2) = h->ptr;
++	  return (1);
++	}
++	else
++	  return (0);
++        
++    case BIO_CTRL_DUP :
++    case BIO_CTRL_FLUSH :
++        return (1);
++  }
++}
++
++
++/*
++ * 'http_bio_free()' - Free OpenSSL data.
++ */
++
++static int				/* O - 1 on success, 0 on failure */
++http_bio_free(BIO *h)			/* I - BIO data */
++{
++  if (!h)
++    return (0);
++
++  if (h->shutdown)
++  {
++    h->init  = 0;
++    h->flags = 0;
++  }
++
++  return (1);
++}
++
++
++/*
++ * 'http_bio_new()' - Initialize an OpenSSL BIO structure.
++ */
++
++static int				/* O - 1 on success, 0 on failure */
++http_bio_new(BIO *h)			/* I - BIO data */
++{
++  if (!h)
++    return (0);
++
++  h->init  = 0;
++  h->num   = 0;
++  h->ptr   = NULL;
++  h->flags = 0;
++
++  return (1);
++}
++
++
++/*
++ * 'http_bio_puts()' - Send a string for OpenSSL.
++ */
++
++static int				/* O - Bytes written */
++http_bio_puts(BIO        *h,		/* I - BIO data */
++              const char *str)		/* I - String to write */
++{
++  return (send(((http_t *)h->ptr)->fd, str, strlen(str), 0));
++}
++
++
++/*
++ * 'http_bio_read()' - Read data for OpenSSL.
++ */
++
++static int				/* O - Bytes read */
++http_bio_read(BIO  *h,			/* I - BIO data */
++              char *buf,		/* I - Buffer */
++	      int  size)		/* I - Number of bytes to read */
++{
++  http_t	*http;			/* HTTP connection */
++
++
++  http = (http_t *)h->ptr;
++
++  if (!http->blocking)
++  {
++   /*
++    * Make sure we have data before we read...
++    */
++
++    if (!http_wait(http, 10000, 0))
++    {
++      http->error = ETIMEDOUT;
++      return (-1);
++    }
++  }
++
++  return (recv(http->fd, buf, size, 0));
++}
++
++
++/*
++ * 'http_bio_write()' - Write data for OpenSSL.
++ */
++
++static int				/* O - Bytes written */
++http_bio_write(BIO        *h,		/* I - BIO data */
++               const char *buf,		/* I - Buffer to write */
++	       int        num)		/* I - Number of bytes to write */
++{
++  return (send(((http_t *)h->ptr)->fd, buf, num, 0));
++}
++#endif /* HAVE_SSL && HAVE_LIBSSL */
++
++
+ /*
+  * 'http_field()' - Return the field index for a field name.
+  */
+@@ -2247,6 +2482,7 @@
+ #  ifdef HAVE_LIBSSL
+   SSL_CTX	*context;		/* Context for encryption */
+   SSL		*conn;			/* Connection for encryption */
++  BIO		*bio;			/* BIO data */
+ #  elif defined(HAVE_GNUTLS)
+   http_tls_t	*conn;			/* TLS session object */
+   gnutls_certificate_client_credentials *credentials;
+@@ -2265,9 +2501,12 @@
+ 
+   SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
+ 
++  bio = BIO_new(_httpBIOMethods());
++  BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)http);
++
+   conn = SSL_new(context);
++  SSL_set_bio(conn, bio, bio);
+ 
+-  SSL_set_fd(conn, http->fd);
+   if (SSL_connect(conn) != 1)
+   {
+ #    ifdef DEBUG
+@@ -2316,8 +2555,9 @@
+   gnutls_init(&(conn->session), GNUTLS_CLIENT);
+   gnutls_set_default_priority(conn->session);
+   gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
+-  gnutls_transport_set_ptr(conn->session,
+-                           (gnutls_transport_ptr)((long)http->fd));
++  gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr)http);
++  gnutls_transport_set_pull_function(conn->session, _httpReadGNUTLS);
++  gnutls_transport_set_push_function(conn->session, _httpWriteGNUTLS);
+ 
+   if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS)
+   {
+@@ -2544,7 +2784,8 @@
+ 
+ static int				/* O - 1 if data is available, 0 otherwise */
+ http_wait(http_t *http,			/* I - HTTP connection */
+-          int    msec)			/* I - Milliseconds to wait */
++          int    msec,			/* I - Milliseconds to wait */
++	  int    usessl)		/* I - Use SSL context? */
+ {
+ #ifndef WIN32
+   struct rlimit		limit;          /* Runtime limit */
+@@ -2564,7 +2805,7 @@
+   */
+ 
+ #ifdef HAVE_SSL
+-  if (http->tls)
++  if (http->tls && usessl)
+   {
+ #  ifdef HAVE_LIBSSL
+     if (SSL_pending((SSL *)(http->tls)))
+diff -urNad cupsys-1.2.6~/doc/help/spec-ppd.html cupsys-1.2.6/doc/help/spec-ppd.html
+--- cupsys-1.2.6~/doc/help/spec-ppd.html	2006-10-11 23:59:20.000000000 +0900
++++ cupsys-1.2.6/doc/help/spec-ppd.html	2006-11-15 09:51:22.000000000 +0900
+@@ -95,11 +95,14 @@
+ <p>This boolean attribute notifies the RIP filters that the
+ destination printer does not require the top and bottom margins
+ of the <tt>ImageableArea</tt> swapped for the back page. The
+-default value is <code>true</code>.</p>
++default is <tt>true</tt> when <tt>cupsFlipDuplex</tt>  is <tt>true</tt> and <tt>false</tt> otherwise.</p>
+ 
+ <p>Example:</p>
+ 
+ <pre class='command'>
++<em>*% Flip the back side images</em>
++*cupsFlipDuplex: true
++
+ <em>*% Don't swap the top and bottom margins for the back side</em> 
+ *APDuplexRequiresFlippedMargin: false
+ </pre>
+diff -urNad cupsys-1.2.6~/filter/pstops.c cupsys-1.2.6/filter/pstops.c
+--- cupsys-1.2.6~/filter/pstops.c	2006-10-11 23:59:20.000000000 +0900
++++ cupsys-1.2.6/filter/pstops.c	2006-11-15 09:51:22.000000000 +0900
+@@ -949,7 +949,7 @@
+ 	}
+ 	else
+ 	{
+-	  printf("%%%%Page: %s %d\n", pageinfo->label, number);
++          printf("%%%%Page: %s %d\n", pageinfo->label, number);
+ 	  printf("%%%%PageBoundingBox: %d %d %d %d\n",
+ 		 pageinfo->bounding_box[0], pageinfo->bounding_box[1],
+ 		 pageinfo->bounding_box[2], pageinfo->bounding_box[3]);
+@@ -1263,6 +1263,44 @@
+         memcpy(bounding_box, doc->bounding_box,
+ 	       sizeof(bounding_box));
+       }
++      else if (doc->number_up == 1 && !doc->fitplot)
++      {
++        int	temp_bbox[4];		/* Temporary bounding box */
++
++
++        switch (Orientation)
++	{
++	  case 0 : /* Portrait */
++              break;
++
++	  case 1 : /* Landscape */
++	      temp_bbox[0] = PageWidth - bounding_box[3];
++	      temp_bbox[1] = bounding_box[0];
++	      temp_bbox[2] = PageWidth - bounding_box[1];
++	      temp_bbox[3] = bounding_box[2];
++
++	      memcpy(bounding_box, temp_bbox, sizeof(bounding_box));
++              break;
++
++	  case 2 : /* Reverse Portrait */
++	      temp_bbox[0] = PageWidth - bounding_box[0];
++	      temp_bbox[1] = PageLength - bounding_box[1];
++	      temp_bbox[2] = PageWidth - bounding_box[2];
++	      temp_bbox[3] = PageLength - bounding_box[3];
++
++	      memcpy(bounding_box, temp_bbox, sizeof(bounding_box));
++              break;
++
++	  case 3 : /* Reverse Landscape */
++	      temp_bbox[0] = bounding_box[1];
++	      temp_bbox[1] = PageLength - bounding_box[2];
++	      temp_bbox[2] = bounding_box[3];
++	      temp_bbox[3] = PageLength - bounding_box[0];
++
++	      memcpy(bounding_box, temp_bbox, sizeof(bounding_box));
++              break;
++	}
++      }
+     }
+ #if 0
+     else if (!strncmp(line, "%%PageCustomColors:", 19) ||
+diff -urNad cupsys-1.2.6~/scheduler/client.c cupsys-1.2.6/scheduler/client.c
+--- cupsys-1.2.6~/scheduler/client.c	2006-10-12 06:04:58.000000000 +0900
++++ cupsys-1.2.6/scheduler/client.c	2006-11-15 09:51:23.000000000 +0900
+@@ -426,7 +426,8 @@
+ 
+     con->http.encryption = HTTP_ENCRYPT_ALWAYS;
+ 
+-    encrypt_client(con);
++    if (!encrypt_client(con))
++      cupsdCloseClient(con);
+   }
+   else
+     con->auto_ssl = 1;
+@@ -745,7 +746,9 @@
+                       "cupsdReadClient: Saw first byte %02X, auto-negotiating SSL/TLS session...",
+                       buf[0] & 255);
+ 
+-      encrypt_client(con);
++      if (!encrypt_client(con))
++        return (cupsdCloseClient(con));
++
+       return (1);
+     }
+   }
+@@ -1056,7 +1059,8 @@
+ 	if (cupsdFlushHeader(con) < 0)
+ 	  return (cupsdCloseClient(con));
+ 
+-        encrypt_client(con);
++        if (!encrypt_client(con))
++	  return (cupsdCloseClient(con));
+ #else
+ 	if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED))
+ 	  return (cupsdCloseClient(con));
+@@ -1103,7 +1107,8 @@
+ 	if (cupsdFlushHeader(con) < 0)
+ 	  return (cupsdCloseClient(con));
+ 
+-        encrypt_client(con);
++        if (!encrypt_client(con))
++	  return (cupsdCloseClient(con));
+ #else
+ 	if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED))
+ 	  return (cupsdCloseClient(con));
+@@ -2587,6 +2592,7 @@
+ #  ifdef HAVE_LIBSSL
+   SSL_CTX	*context;		/* Context for encryption */
+   SSL		*conn;			/* Connection for encryption */
++  BIO		*bio;			/* BIO data */
+   unsigned long	error;			/* Error code */
+ 
+ 
+@@ -2614,9 +2620,12 @@
+   SSL_CTX_use_PrivateKey_file(context, ServerKey, SSL_FILETYPE_PEM);
+   SSL_CTX_use_certificate_file(context, ServerCertificate, SSL_FILETYPE_PEM);
+ 
++  bio = BIO_new(_httpBIOMethods());
++  BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)HTTP(con));
++
+   conn = SSL_new(context);
++  SSL_set_bio(conn, bio, bio);
+ 
+-  SSL_set_fd(conn, con->http.fd);
+   if (SSL_accept(conn) != 1)
+   {
+     cupsdLogMessage(CUPSD_LOG_ERROR,
+@@ -2689,8 +2698,9 @@
+   gnutls_init(&(conn->session), GNUTLS_SERVER);
+   gnutls_set_default_priority(conn->session);
+   gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
+-  gnutls_transport_set_ptr(conn->session,
+-                           (gnutls_transport_ptr)((long)con->http.fd));
++  gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr)HTTP(con));
++  gnutls_transport_set_pull_function(conn->session, _httpReadGNUTLS);
++  gnutls_transport_set_push_function(conn->session, _httpWriteGNUTLS);
+ 
+   error = gnutls_handshake(conn->session);
+ 
+@@ -2743,7 +2753,7 @@
+   if (!conn->certsArray)
+   {
+     cupsdLogMessage(CUPSD_LOG_ERROR,
+-        	    "EncryptClient: Could not find signing key in keychain "
++        	    "encrypt_client: Could not find signing key in keychain "
+ 		    "\"%s\"", ServerCertificate);
+     error = errSSLBadCert; /* errSSLBadConfiguration is a better choice, but not available on 10.2.x */
+   }
+diff -urNad cupsys-1.2.6~/scheduler/dirsvc.c cupsys-1.2.6/scheduler/dirsvc.c
+--- cupsys-1.2.6~/scheduler/dirsvc.c	2006-10-03 01:26:04.000000000 +0900
++++ cupsys-1.2.6/scheduler/dirsvc.c	2006-11-15 09:51:23.000000000 +0900
+@@ -160,6 +160,17 @@
+ 
+ 
+  /*
++  * Don't load the cache if the CUPS remote protocol is disabled...
++  */
++
++  if (!(BrowseRemoteProtocols & BROWSE_CUPS))
++  {
++    cupsdLogMessage(CUPSD_LOG_DEBUG,
++                    "cupsdLoadRemoteCache: Not loading remote cache.");
++    return;
++  }
++
++ /*
+   * Open the remote.cache file...
+   */
+ 
+diff -urNad cupsys-1.2.6~/scheduler/main.c cupsys-1.2.6/scheduler/main.c
+--- cupsys-1.2.6~/scheduler/main.c	2006-08-25 00:55:42.000000000 +0900
++++ cupsys-1.2.6/scheduler/main.c	2006-11-15 09:51:23.000000000 +0900
+@@ -32,9 +32,11 @@
+  *   cupsdSetStringf()         - Set a formatted string value.
+  *   launchd_checkin()         - Check-in with launchd and collect the
+  *                               listening fds.
++ *   launchd_create_dict()     - Create a dictionary representing the launchd
++ *			         config file org.cups.cupsd.plist.
+  *   launchd_reload()          - Tell launchd to reload the configuration
+  *                               file to pick up the new listening directives.
+- *   launchd_sync_conf()       - Re-write the launchd(8) config file
++ *   launchd_sync_conf()       - Re-write the launchd config file
+  *			         org.cups.cupsd.plist based on cupsd.conf.
+  *   parent_handler()          - Catch USR1/CHLD signals...
+  *   process_children()        - Process all dead children...
+@@ -75,31 +77,41 @@
+  */
+ 
+ #ifdef HAVE_LAUNCHD
+-static void	launchd_checkin(void);
+-static void	launchd_reload(void);
+-static int	launchd_sync_conf(void);
++static void		launchd_checkin(void);
++static CFDictionaryRef	launchd_create_dict(void);
++static void		launchd_reload(void);
++static int		launchd_sync_conf(void);
+ #endif /* HAVE_LAUNCHD */
+-
+-static void	parent_handler(int sig);
+-static void	process_children(void);
+-static void	sigchld_handler(int sig);
+-static void	sighup_handler(int sig);
+-static void	sigterm_handler(int sig);
+-static long	select_timeout(int fds);
+-static void	usage(int status);
++static void		parent_handler(int sig);
++static void		process_children(void);
++static void		sigchld_handler(int sig);
++static void		sighup_handler(int sig);
++static void		sigterm_handler(int sig);
++static long		select_timeout(int fds);
++static void		usage(int status);
+ 
+ 
+ /*
+  * Local globals...
+  */
+ 
+-static int	parent_signal = 0;	/* Set to signal number from child */
+-static int	holdcount = 0;		/* Number of times "hold" was called */
++static int		parent_signal = 0;
++					/* Set to signal number from child */
++static int		holdcount = 0;	/* Number of times "hold" was called */
+ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+-static sigset_t	holdmask;		/* Old POSIX signal mask */
++static sigset_t		holdmask;	/* Old POSIX signal mask */
+ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+-static int	dead_children = 0;	/* Dead children? */
+-static int	stop_scheduler = 0;	/* Should the scheduler stop? */
++static int		dead_children = 0;
++					/* Dead children? */
++static int		stop_scheduler = 0;
++					/* Should the scheduler stop? */
++
++#ifdef HAVE_LAUNCHD
++static CFURLRef		launchd_conf_url = NULL;
++					/* org.cups.cupsd.plist url */
++static CFDictionaryRef	launchd_conf_dict = NULL;
++					/* org.cups.cupsd.plist dict */
++#endif /* HAVE_LAUNCHD */
+ 
+ 
+ /*
+@@ -123,8 +135,11 @@
+ 			activity,	/* Client activity timer */
+ 			browse_time,	/* Next browse send time */
+ 			senddoc_time,	/* Send-Document time */
+-			expire_time;	/* Subscription expire time */
+-  time_t		mallinfo_time;	/* Malloc information time */
++			expire_time,	/* Subscription expire time */
++#ifndef __APPLE__
++			netif_time,	/* Network interface poll time */
++#endif /* !__APPLE__ */
++			mallinfo_time;	/* Malloc information time */
+   size_t		string_count,	/* String count */
+ 			alloc_bytes,	/* Allocated string bytes */
+ 			total_bytes;	/* Total string bytes */
+@@ -536,6 +551,9 @@
+   senddoc_time  = time(NULL);
+   expire_time   = time(NULL);
+   fds           = 1;
++#ifndef __APPLE__
++  netif_time    = 0;
++#endif /* !__APPLE__ */
+ 
+   while (!stop_scheduler)
+   {
+@@ -656,7 +674,7 @@
+ #if HAVE_LAUNCHD
+    /*
+     * If no other work is scheduled and we're being controlled by
+-    * launchd(8) then timeout after 'LaunchdTimeout' seconds of
++    * launchd then timeout after 'LaunchdTimeout' seconds of
+     * inactivity...
+     */
+ 
+@@ -761,7 +779,7 @@
+ 
+ #if HAVE_LAUNCHD
+    /*
+-    * If no other work was scheduled and we're being controlled by launchd(8)
++    * If no other work was scheduled and we're being controlled by launchd
+     * then timeout after 'LaunchdTimeout' seconds of inactivity...
+     */
+ 
+@@ -810,8 +828,23 @@
+     */
+ 
+ #ifdef __APPLE__
++   /*
++    * Mac OS X provides the SystemConfiguration framework for system
++    * configuration change events...
++    */
++
+     if (SysEventPipes[0] >= 0 && FD_ISSET(SysEventPipes[0], input))
+       cupsdUpdateSystemMonitor();
++#else
++   /*
++    * All other operating systems need to poll for changes...
++    */
++
++    if ((current_time - netif_time) >= 60)
++    {
++      NetIFUpdate = 1;
++      netif_time  = current_time;
++    }
+ #endif	/* __APPLE__ */
+ 
+    /*
+@@ -1082,6 +1115,12 @@
+   */
+ 
+   launchd_sync_conf();
++
++  if (launchd_conf_url)
++    CFRelease(launchd_conf_url);
++
++  if (launchd_conf_dict)
++    CFRelease(launchd_conf_dict);
+ #endif /* HAVE_LAUNCHD */
+ 
+ #ifdef __sgi
+@@ -1449,7 +1488,7 @@
+ 	{
+ 	  if (BrowseSocket != -1)
+ 	    close(BrowseSocket);
+-  
++
+ 	  BrowseSocket = launch_data_get_fd(tmp);
+ 	}
+ 	else
+@@ -1473,6 +1512,222 @@
+ 
+ 
+ /*
++ * 'launchd_create_dict()' - Create a dictionary representing the launchd
++ *			     config file org.cups.cupsd.plist.
++ */
++
++static CFDictionaryRef			/* O - CFDictionary */
++launchd_create_dict(void)
++{
++  int			  portnum;	/* Port number */
++  bool			  runatload;	/* Run at load? */
++  CFMutableDictionaryRef  cupsd_dict,	/* org.cups.cupsd.plist dictionary */
++			  sockets,	/* Sockets dictionary */
++			  listener;	/* Listener dictionary */
++  CFMutableArrayRef	  array;	/* Array */
++  CFNumberRef		  socket_mode;	/* Domain socket mode bits */
++  CFStringRef		  socket_path;	/* Domain socket path */
++  CFTypeRef		  value;	/* CF values */
++  cupsd_listener_t	  *lis;		/* Current listening socket */
++  struct servent	  *service;	/* Services data base entry */
++  char			  temp[1024];	/* Temporary buffer for value */
++
++
++  if ((cupsd_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
++				&kCFTypeDictionaryKeyCallBacks,
++				&kCFTypeDictionaryValueCallBacks)) == NULL)
++    return NULL;
++
++  CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_LABEL),
++		       CFSTR("org.cups.cupsd"));
++  CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_ONDEMAND),
++		       kCFBooleanTrue);
++
++ /*
++  * Run-at-load if there are active jobs, polling or shared printers
++  * to advertise...
++  */
++  
++  runatload = (cupsArrayCount(ActiveJobs) || NumPolled || 
++	       (Browsing && BrowseLocalProtocols && 
++	        NumBrowsers && cupsArrayCount(Printers))) ? true : false;
++
++  CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_RUNATLOAD),
++		       runatload ? kCFBooleanTrue : kCFBooleanFalse);
++#  ifdef LAUNCH_JOBKEY_SERVICEIPC
++  CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_SERVICEIPC),
++		       kCFBooleanTrue);
++#  endif /* LAUNCH_JOBKEY_SERVICEIPC */
++
++  if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 2,
++				    &kCFTypeArrayCallBacks)) != NULL)
++  {
++    CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS),
++			 array);
++    CFArrayAppendValue(array, CFSTR("/usr/sbin/cupsd"));
++    CFArrayAppendValue(array, CFSTR("-l"));
++    CFRelease(array);
++  }
++
++ /*
++  * Add a sockets dictionary...
++  */
++
++  if ((sockets = (CFMutableDictionaryRef)CFDictionaryCreateMutable(
++			      kCFAllocatorDefault, 0,
++			      &kCFTypeDictionaryKeyCallBacks,
++			      &kCFTypeDictionaryValueCallBacks)) != NULL)
++  {
++    CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_SOCKETS), sockets);
++
++   /*
++    * Add a Listeners array to the sockets dictionary...
++    */
++
++    if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
++				      &kCFTypeArrayCallBacks)) != NULL)
++    {
++      CFDictionaryAddValue(sockets, CFSTR("Listeners"), array);
++
++     /*
++      * For each listener add a dictionary to the listeners array...
++      */
++
++      for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
++	   lis;
++	   lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
++      {
++	if ((listener = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
++			      &kCFTypeDictionaryKeyCallBacks,
++			      &kCFTypeDictionaryValueCallBacks)) != NULL)
++	{
++	  CFArrayAppendValue(array, listener);
++
++#  ifdef AF_LOCAL
++	  if (lis->address.addr.sa_family == AF_LOCAL)
++	  {
++	    if ((socket_path = CFStringCreateWithCString(kCFAllocatorDefault,
++				      lis->address.un.sun_path,
++				      kCFStringEncodingUTF8)))
++	    {
++	      CFDictionaryAddValue(listener,
++				   CFSTR(LAUNCH_JOBSOCKETKEY_PATHNAME),
++				   socket_path);
++	      CFRelease(socket_path);
++	    }
++	    portnum = 0140777; /* (S_IFSOCK|S_IRWXU|S_IRWXG|S_IRWXO) or *
++				* 49663d decimal                        */
++	    if ((socket_mode = CFNumberCreate(kCFAllocatorDefault,
++					      kCFNumberIntType, &portnum)))
++	    {
++	      CFDictionaryAddValue(listener, CFSTR("SockPathMode"),
++				   socket_mode);
++	      CFRelease(socket_mode);
++	    }
++	  }
++	  else
++#  endif /* AF_LOCAL */
++	  {
++#  ifdef AF_INET6
++	    if (lis->address.addr.sa_family == AF_INET6)
++	    {
++	      CFDictionaryAddValue(listener,
++				   CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
++				   CFSTR("IPv6"));
++	      portnum = lis->address.ipv6.sin6_port;
++	    }
++	    else
++#  endif /* AF_INET6 */
++	    {
++	      CFDictionaryAddValue(listener,
++				   CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
++				   CFSTR("IPv4"));
++	      portnum = lis->address.ipv4.sin_port;
++	    }
++
++	    if ((service = getservbyport(portnum, NULL)))
++	      value = CFStringCreateWithCString(kCFAllocatorDefault,
++						service->s_name,
++						kCFStringEncodingUTF8);
++	    else
++	      value = CFNumberCreate(kCFAllocatorDefault,
++				     kCFNumberIntType, &portnum);
++
++	    if (value)
++	    {
++	      CFDictionaryAddValue(listener,
++				   CFSTR(LAUNCH_JOBSOCKETKEY_SERVICENAME),
++				   value);
++	      CFRelease(value);
++	    }	
++
++	    httpAddrString(&lis->address, temp, sizeof(temp));
++	    if ((value = CFStringCreateWithCString(kCFAllocatorDefault, temp,
++						   kCFStringEncodingUTF8)))
++	    {
++	      CFDictionaryAddValue(listener,
++				   CFSTR(LAUNCH_JOBSOCKETKEY_NODENAME),
++				   value);
++	      CFRelease(value);
++	    }
++	  }
++
++	  CFRelease(listener);
++	}
++      }
++
++      CFRelease(array);
++    }
++
++   /*
++    * Add the BrowseSocket to the sockets dictionary...
++    */
++
++    if (Browsing && (BrowseRemoteProtocols & BROWSE_CUPS))
++    {
++      if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
++					&kCFTypeArrayCallBacks)) != NULL)
++      {
++	CFDictionaryAddValue(sockets, CFSTR("BrowseSockets"), array);
++
++	if ((listener = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
++				&kCFTypeDictionaryKeyCallBacks,
++				&kCFTypeDictionaryValueCallBacks)) != NULL)
++	{
++	  CFArrayAppendValue(array, listener);
++
++	  CFDictionaryAddValue(listener, CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
++			       CFSTR("IPv4"));
++	  CFDictionaryAddValue(listener, CFSTR(LAUNCH_JOBSOCKETKEY_TYPE),
++			       CFSTR("dgram"));
++
++	  if ((service = getservbyport(BrowsePort, NULL)))
++	    value = CFStringCreateWithCString(kCFAllocatorDefault,
++					      service->s_name,
++					      kCFStringEncodingUTF8);
++	  else
++	    value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType,
++				   &BrowsePort);
++
++	  CFDictionaryAddValue(listener,
++			       CFSTR(LAUNCH_JOBSOCKETKEY_SERVICENAME), value);
++	  CFRelease(value);
++
++	  CFRelease(listener);
++	}
++
++	CFRelease(array);
++      }
++    }
++
++    CFRelease(sockets);
++  }
++
++  return (cupsd_dict);
++}
++
++
++/*
+  * 'launchd_reload()' - Tell launchd to reload the configuration file to pick
+  *                      up the new listening directives.
+  */
+@@ -1573,272 +1828,104 @@
+ 
+ 
+ /*
+- * 'launchd_sync_conf()' - Re-write the launchd(8) config file
++ * 'launchd_sync_conf()' - Rewrite the launchd config file
+  *			   org.cups.cupsd.plist based on cupsd.conf.
+  */
+ 
+ static int				/* O - 1 if the file was updated */
+ launchd_sync_conf(void)
+ {
+-  int			  portnum;	/* Port number */
+-  CFMutableDictionaryRef  cupsd_dict,	/* org.cups.cupsd.plist dictionary */
+-			  sockets,	/* Sockets dictionary */
+-			  listener;	/* Listener dictionary */
+-  CFDataRef		  resourceData;	/* XML property list */
+-  CFMutableArrayRef	  array;	/* Array */
+-  CFNumberRef		  socket_mode;	/* Domain socket mode bits */
+-  CFStringRef		  socket_path;	/* Domain socket path */
+-  CFTypeRef		  value;	/* CF value */
+-  CFURLRef		  fileURL;	/* File URL */
+-  SInt32		  errorCode;	/* Error code */
+-  cupsd_listener_t	  *lis;		/* Current listening socket */
+-  struct servent	  *service;	/* Services data base entry */
+-  char			  temp[1024];	/* Temporary buffer for value */
+-  struct stat		  cupsd_sb,	/* File info for cupsd.conf */
+-			  launchd_sb;	/* File info for org.cups.cupsd.plist */
++  SInt32		errorCode;	/* Error code */
++  CFDataRef		resourceData;	/* XML property list */
++  CFDictionaryRef	cupsd_dict;	/* New org.cups.cupsd.plist dict */
+ 
+ 
+  /*
+-  * If the launchd conf file modification time is newer than the cupsd.conf
+-  * time then there's nothing to do...
++  * If needed reconstitute the existing org.cups.cupsd.plist...
+   */
+ 
+-  if (!stat(ConfigurationFile, &cupsd_sb) &&
+-      !stat(LaunchdConf, &launchd_sb) &&
+-      launchd_sb.st_mtimespec.tv_sec >= cupsd_sb.st_mtimespec.tv_sec)
++  if (!launchd_conf_url && 
++      !(launchd_conf_url = CFURLCreateFromFileSystemRepresentation(
++				kCFAllocatorDefault,
++				(const unsigned char *)LaunchdConf,
++				strlen(LaunchdConf), false)))
+   {
+-    cupsdLogMessage(CUPSD_LOG_DEBUG,
+-                    "launchd_sync_conf: Nothing to do, pid=%d.",
+-		    (int)getpid());
++    cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_sync_conf: "
++		    "Unable to create file URL for \"%s\"\n", LaunchdConf);
+     return (0);
+   }
+ 
+- /*
+-  * Time to write a new 'org.cups.cupsd.plist' file.
+-  * Create the new dictionary and populate it with values...
+-  */
+-
+-  if ((cupsd_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+-				&kCFTypeDictionaryKeyCallBacks,
+-				&kCFTypeDictionaryValueCallBacks)) != NULL)
++  if (!launchd_conf_dict)
+   {
+-    CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_LABEL),
+-                         CFSTR("org.cups.cupsd"));
+-    CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_ONDEMAND),
+-                         kCFBooleanTrue);
+-
+-    if ((Browsing && BrowseLocalProtocols && cupsArrayCount(Printers)) ||
+-        cupsArrayCount(ActiveJobs) || NumPolled)
+-      CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_RUNATLOAD),
+-                           kCFBooleanTrue);
+-    else
+-      CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_RUNATLOAD),
+-                           kCFBooleanFalse);
+-
+-#ifdef LAUNCH_JOBKEY_SERVICEIPC
+-    CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_SERVICEIPC),
+-			 kCFBooleanTrue);
+-#endif  /* LAUNCH_JOBKEY_SERVICEIPC */
++    if (CFURLCreateDataAndPropertiesFromResource(NULL, launchd_conf_url, 
++				&resourceData, NULL, NULL, &errorCode))
++    {
++      launchd_conf_dict = CFPropertyListCreateFromXMLData(NULL, resourceData,
++					      kCFPropertyListImmutable, NULL);
++      CFRelease(resourceData);
++    }
+ 
+-    if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 2,
+-                                      &kCFTypeArrayCallBacks)) != NULL)
++    if (!launchd_conf_dict)
+     {
+-      CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS),
+-                           array);
+-      CFArrayAppendValue(array, CFSTR("/usr/sbin/cupsd"));
+-      CFArrayAppendValue(array, CFSTR("-l"));
+-      CFRelease(array);
++      cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_sync_conf: "
++		      "Unable to create dictionary for \"%s\"\n", LaunchdConf);
+     }
++  }
+ 
+-   /*
+-    * Add a sockets dictionary...
+-    */
++ /*
++  * Create a new org.cups.cupsd.plist dictionary...
++  */
+ 
+-    if ((sockets = (CFMutableDictionaryRef)CFDictionaryCreateMutable(
+-				kCFAllocatorDefault, 0,
+-				&kCFTypeDictionaryKeyCallBacks,
+-				&kCFTypeDictionaryValueCallBacks)) != NULL)
+-    {
+-      CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_SOCKETS), sockets);
++  if ((cupsd_dict = launchd_create_dict()) == NULL)
++  {
++    cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_sync_conf: "
++		    "Unable to create file URL for \"%s\"\n", LaunchdConf);
++    return (0);
++  }
+ 
+-     /*
+-      * Add a Listeners array to the sockets dictionary...
+-      */
++ /*
++  * If the dictionaries are different write a new org.cups.cupsd.plist...
++  */
+ 
+-      if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+-                                        &kCFTypeArrayCallBacks)) != NULL)
++  if (!CFEqual(cupsd_dict, launchd_conf_dict))
++  {
++    if ((resourceData = CFPropertyListCreateXMLData(kCFAllocatorDefault,
++						  cupsd_dict)))
++    {
++      if (CFURLWriteDataAndPropertiesToResource(launchd_conf_url, resourceData,
++						 NULL, &errorCode))
+       {
+-	CFDictionaryAddValue(sockets, CFSTR("Listeners"), array);
+-
+        /*
+-	* For each listener add a dictionary to the listeners array...
+-	*/
+-
+-	for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+-	     lis;
+-	     lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+-	{
+-	  if ((listener = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+-				&kCFTypeDictionaryKeyCallBacks,
+-				&kCFTypeDictionaryValueCallBacks)) != NULL)
+-	  {
+-	    CFArrayAppendValue(array, listener);
+-
+-#  ifdef AF_LOCAL
+-	    if (lis->address.addr.sa_family == AF_LOCAL)
+-	    {
+-	      if ((socket_path = CFStringCreateWithCString(kCFAllocatorDefault,
+-					lis->address.un.sun_path,
+-					kCFStringEncodingUTF8)))
+-	      {
+-		CFDictionaryAddValue(listener,
+-		                     CFSTR(LAUNCH_JOBSOCKETKEY_PATHNAME),
+-		                     socket_path);
+-		CFRelease(socket_path);
+-	      }
+-	      portnum = 0140777; /* (S_IFSOCK|S_IRWXU|S_IRWXG|S_IRWXO) or *
+-	                          * 49663d decimal                        */
+-	      if ((socket_mode = CFNumberCreate(kCFAllocatorDefault,
+-	                                        kCFNumberIntType, &portnum)))
+-	      {
+-		CFDictionaryAddValue(listener, CFSTR("SockPathMode"),
+-		                     socket_mode);
+-		CFRelease(socket_mode);
+-	      }
+-	    }
+-	    else
+-#  endif /* AF_LOCAL */
+-	    {
+-#  ifdef AF_INET6
+-	      if (lis->address.addr.sa_family == AF_INET6)
+-	      {
+-		CFDictionaryAddValue(listener,
+-		                     CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
+-		                     CFSTR("IPv6"));
+-		portnum = lis->address.ipv6.sin6_port;
+-	      }
+-	      else
+-#  endif /* AF_INET6 */
+-	      {
+-		CFDictionaryAddValue(listener,
+-		                     CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
+-		                     CFSTR("IPv4"));
+-		portnum = lis->address.ipv4.sin_port;
+-	      }
+-
+-	      if ((service = getservbyport(portnum, NULL)))
+-		value = CFStringCreateWithCString(kCFAllocatorDefault,
+-						  service->s_name,
+-						  kCFStringEncodingUTF8);
+-	      else
+-		value = CFNumberCreate(kCFAllocatorDefault,
+-				       kCFNumberIntType, &portnum);
+-
+-	      if (value)
+-	      {
+-		CFDictionaryAddValue(listener,
+-		                     CFSTR(LAUNCH_JOBSOCKETKEY_SERVICENAME),
+-				     value);
+-		CFRelease(value);
+-	      }	
+-
+-	      httpAddrString(&lis->address, temp, sizeof(temp));
+-	      if ((value = CFStringCreateWithCString(kCFAllocatorDefault, temp,
+-						     kCFStringEncodingUTF8)))
+-	      {
+-		CFDictionaryAddValue(listener,
+-		                     CFSTR(LAUNCH_JOBSOCKETKEY_NODENAME),
+-				     value);
+-		CFRelease(value);
+-	      }
+-	    }
++        * The new cupsd dictionary becomes the on-disk launchd dictionary...
++        */
+ 
+-	    CFRelease(listener);
+-	  }
+-	}
++	if (launchd_conf_dict)
++	  CFRelease(launchd_conf_dict);
+ 
+-	CFRelease(array);
++	launchd_conf_dict = cupsd_dict;
+       }
+-
+-     /*
+-      * Add the BrowseSocket to the sockets dictionary...
+-      */
+-
+-      if (Browsing && (BrowseRemoteProtocols & BROWSE_CUPS))
++      else
+       {
+-	if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+-					  &kCFTypeArrayCallBacks)) != NULL)
+-	{
+-	  CFDictionaryAddValue(sockets, CFSTR("BrowseSockets"), array);
+-
+-	  if ((listener = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+-				  &kCFTypeDictionaryKeyCallBacks,
+-				  &kCFTypeDictionaryValueCallBacks)) != NULL)
+-	  {
+-	    CFArrayAppendValue(array, listener);
+-
+-	    CFDictionaryAddValue(listener, CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
+-	                         CFSTR("IPv4"));
+-	    CFDictionaryAddValue(listener, CFSTR(LAUNCH_JOBSOCKETKEY_TYPE),
+-	                         CFSTR("dgram"));
+-
+-	    if ((service = getservbyport(BrowsePort, NULL)))
+-	      value = CFStringCreateWithCString(kCFAllocatorDefault,
+-						service->s_name,
+-						kCFStringEncodingUTF8);
+-	    else
+-	      value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType,
+-				     &BrowsePort);
+-
+-	    CFDictionaryAddValue(listener,
+-	                         CFSTR(LAUNCH_JOBSOCKETKEY_SERVICENAME), value);
+-	    CFRelease(value);
+-
+-	    CFRelease(listener);
+-	  }
++	cupsdLogMessage(CUPSD_LOG_WARN,
++			"launchd_sync_conf: "
++			"CFURLWriteDataAndPropertiesToResource(\"%s\") "
++			"failed: %d\n",
++			LaunchdConf, (int)errorCode);
+ 
+-	  CFRelease(array);
+-	}
++	CFRelease(cupsd_dict);
+       }
+-
+-      CFRelease(sockets);
++  
++      CFRelease(resourceData);
+     }
+ 
+-    cupsdLogMessage(CUPSD_LOG_DEBUG,
+-                    "launchd_sync_conf: Updating \"%s\", pid=%d\n",
+-		    LaunchdConf, (int)getpid());
+-
+-    if ((fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
+-				(const unsigned char *)LaunchdConf,
+-				strlen(LaunchdConf), false)))
+-    {
+-      if ((resourceData = CFPropertyListCreateXMLData(kCFAllocatorDefault,
+-                                                      cupsd_dict)))
+-      {
+-	if (!CFURLWriteDataAndPropertiesToResource(fileURL, resourceData,
+-	                                           NULL, &errorCode))
+-	{
+-	  cupsdLogMessage(CUPSD_LOG_WARN,
+-	                  "launchd_sync_conf: "
+-			  "CFURLWriteDataAndPropertiesToResource(\"%s\") "
+-			  "failed: %d\n",
+-			  LaunchdConf, (int)errorCode);
+-        }
+-
+-	CFRelease(resourceData);
+-      }
+-
+-      CFRelease(fileURL);
+-    }
++   /*
++    * Let the caller know we updated the file...
++    */
+ 
+-    CFRelease(cupsd_dict);
++    return (1);
+   }
+ 
+- /*
+-  * Let the caller know we updated the file...
+-  */
+-
+-  return (1);
++  return (0);
+ }
+ #endif /* HAVE_LAUNCHD */
+ 
+diff -urNad cupsys-1.2.6~/scheduler/network.c cupsys-1.2.6/scheduler/network.c
+--- cupsys-1.2.6~/scheduler/network.c	2006-04-19 05:45:30.000000000 +0900
++++ cupsys-1.2.6/scheduler/network.c	2006-11-15 09:51:23.000000000 +0900
+@@ -60,7 +60,8 @@
+   * Update the interface list as needed...
+   */
+ 
+-  cupsdNetIFUpdate();
++  if (NetIFUpdate)
++    cupsdNetIFUpdate();
+ 
+  /*
+   * Search for the named interface...
+@@ -113,14 +114,13 @@
+ 
+ 
+  /*
+-  * Update the network interface list no more often than once a
+-  * minute...
++  * Only update the list if we need to...
+   */
+ 
+-  if ((time(NULL) - NetIFTime) < 60)
++  if (!NetIFUpdate)
+     return;
+ 
+-  NetIFTime = time(NULL);
++  NetIFUpdate = 0;
+ 
+  /*
+   * Free the old interfaces...
+diff -urNad cupsys-1.2.6~/scheduler/network.h cupsys-1.2.6/scheduler/network.h
+--- cupsys-1.2.6~/scheduler/network.h	2006-02-02 03:55:16.000000000 +0900
++++ cupsys-1.2.6/scheduler/network.h	2006-11-15 09:51:23.000000000 +0900
+@@ -43,8 +43,8 @@
+  * Globals...
+  */
+ 
+-VAR time_t		NetIFTime	VALUE(0);
+-					/* Network interface list time */
++VAR int			NetIFUpdate	VALUE(1);
++					/* Network interface list needs updating */
+ VAR cups_array_t	*NetIFList	VALUE(NULL);
+ 					/* Array of network interfaces */
+ 
+diff -urNad cupsys-1.2.6~/scheduler/sysman.c cupsys-1.2.6/scheduler/sysman.c
+--- cupsys-1.2.6~/scheduler/sysman.c	2006-08-17 05:05:58.000000000 +0900
++++ cupsys-1.2.6/scheduler/sysman.c	2006-11-15 09:51:23.000000000 +0900
+@@ -115,11 +115,17 @@
+ 					/* The runloop. Access must be protected! */
+ static CFStringRef	ComputerNameKey = NULL,
+ 					/* Computer name key */
+-			NetworkGlobalKey = NULL,
+-					/* Network global key */
++			NetworkGlobalKeyIPv4 = NULL,
++					/* Network global IPv4 key */
++			NetworkGlobalKeyIPv6 = NULL,
++					/* Network global IPv6 key */
++			NetworkGlobalKeyDNS = NULL,
++					/* Network global DNS key */
+ 			HostNamesKey = NULL,
+ 					/* Host name key */
+-			NetworkInterfaceKey = NULL;
++			NetworkInterfaceKeyIPv4 = NULL,
++					/* Netowrk interface key */
++			NetworkInterfaceKeyIPv6 = NULL;
+ 					/* Netowrk interface key */
+ 
+ 
+@@ -306,7 +312,6 @@
+ 	}
+ 	else
+ 	{
+-	 /* TODO: Possibly update when MDNS support is added? */
+ 	  cupsdLogMessage(CUPSD_LOG_DEBUG,
+ 	                  "Deregistering local printer \"%s\"", p->name);
+ 	  cupsdSendBrowseDelete(p);
+@@ -334,12 +339,6 @@
+ 	                "System network configuration changed");
+ 
+        /*
+-        * Force an update of the list of network interfaces in 2 seconds.
+-        */
+-
+-        NetIFTime = time(NULL) - 58;
+-
+-       /*
+         * Resetting browse_time before calling cupsdSendBrowseList causes
+ 	* browse packets to be sent for local shared printers.
+         */
+@@ -407,8 +406,8 @@
+   SCDynamicStoreRef	store    = NULL;/* System Config dynamic store */
+   CFRunLoopSourceRef	powerRLS = NULL,/* Power runloop source */
+ 			storeRLS = NULL;/* System Config runloop source */
+-  CFStringRef		key[3],		/* System Config keys */
+-			pattern[1];	/* System Config patterns */
++  CFStringRef		key[5],		/* System Config keys */
++			pattern[2];	/* System Config patterns */
+   CFArrayRef		keys = NULL,	/* System Config key array*/
+ 			patterns = NULL;/* System Config pattern array */
+   SCDynamicStoreContext	storeContext;	/* Dynamic store context */
+@@ -449,33 +448,58 @@
+   if (!ComputerNameKey)
+     ComputerNameKey = SCDynamicStoreKeyCreateComputerName(NULL);
+ 
+-  if (!NetworkGlobalKey)
+-    NetworkGlobalKey =
++  if (!NetworkGlobalKeyIPv4)
++    NetworkGlobalKeyIPv4 =
+         SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
+                                                    kSCDynamicStoreDomainState,
+ 						   kSCEntNetIPv4);
+ 
++  if (!NetworkGlobalKeyIPv6)
++    NetworkGlobalKeyIPv6 =
++        SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
++                                                   kSCDynamicStoreDomainState,
++						   kSCEntNetIPv6);
++
++  if (!NetworkGlobalKeyDNS)
++    NetworkGlobalKeyDNS = 
++	SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, 
++						   kSCDynamicStoreDomainState,
++						   kSCEntNetDNS);
++
+   if (!HostNamesKey)
+     HostNamesKey = SCDynamicStoreKeyCreateHostNames(NULL);
+ 
+-  if (!NetworkInterfaceKey)
+-    NetworkInterfaceKey =
++  if (!NetworkInterfaceKeyIPv4)
++    NetworkInterfaceKeyIPv4 =
+         SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+ 	                                              kSCDynamicStoreDomainState,
+ 						      kSCCompAnyRegex,
+ 						      kSCEntNetIPv4);
+ 
+-  if (store && ComputerNameKey && NetworkGlobalKey && HostNamesKey &&
+-      NetworkInterfaceKey)
++  if (!NetworkInterfaceKeyIPv6)
++    NetworkInterfaceKeyIPv6 =
++        SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
++	                                              kSCDynamicStoreDomainState,
++						      kSCCompAnyRegex,
++						      kSCEntNetIPv6);
++
++  if (store && ComputerNameKey && HostNamesKey &&
++      NetworkGlobalKeyIPv4 && NetworkGlobalKeyIPv6 && NetworkGlobalKeyDNS &&
++      NetworkInterfaceKeyIPv4 && NetworkInterfaceKeyIPv6)
+   {
+     key[0]     = ComputerNameKey;
+-    key[1]     = NetworkGlobalKey;
+-    key[2]     = HostNamesKey;
+-    pattern[0] = NetworkInterfaceKey;
++    key[1]     = NetworkGlobalKeyIPv4;
++    key[2]     = NetworkGlobalKeyIPv6;
++    key[3]     = NetworkGlobalKeyDNS;
++    key[4]     = HostNamesKey;
++
++    pattern[0] = NetworkInterfaceKeyIPv4;
++    pattern[1] = NetworkInterfaceKeyIPv6;
+ 
+     keys     = CFArrayCreate(NULL, (const void **)key,
+                                     sizeof(key) / sizeof(key[0]),
+ 				    &kCFTypeArrayCallBacks);
++
+     patterns = CFArrayCreate(NULL, (const void **)pattern,
+                              sizeof(pattern) / sizeof(pattern[0]),
+ 			     &kCFTypeArrayCallBacks);
+@@ -682,12 +706,17 @@
+ 
+   if (CFArrayContainsValue(changedKeys, range, ComputerNameKey))
+     threadData->sysevent.event |= SYSEVENT_NAMECHANGED;
+-
+-  if (CFArrayContainsValue(changedKeys, range, NetworkGlobalKey) ||
+-      CFArrayContainsValue(changedKeys, range, HostNamesKey) ||
+-      CFArrayContainsValue(changedKeys, range, NetworkInterfaceKey))
++  else
++  {
+     threadData->sysevent.event |= SYSEVENT_NETCHANGED;
+ 
++   /*
++    * Indicate the network interface list needs updating...
++    */
++
++    NetIFUpdate = 1;
++  }
++
+  /*
+   * Because we registered for several different kinds of change notifications 
+   * this callback usually gets called several times in a row. We use a timer to 
+@@ -695,7 +724,7 @@
+   */
+ 
+   CFRunLoopTimerSetNextFireDate(threadData->timerRef, 
+-  				CFAbsoluteTimeGetCurrent() + 2);
++  				CFAbsoluteTimeGetCurrent() + 5);
+ }
+ 
+ 
+diff -urNad cupsys-1.2.6~/systemv/lpstat.c cupsys-1.2.6/systemv/lpstat.c
+--- cupsys-1.2.6~/systemv/lpstat.c	2006-11-03 05:01:54.000000000 +0900
++++ cupsys-1.2.6/systemv/lpstat.c	2006-11-15 09:51:22.000000000 +0900
+@@ -2038,7 +2038,7 @@
+ 	  if (reasons)
+ 	  {
+ 	    _cupsLangPuts(stdout, _("\tAlerts:"));
+-	    for (j = 0; j < reasons->num_values; i ++)
++	    for (j = 0; j < reasons->num_values; j ++)
+ 	      _cupsLangPrintf(stdout, " %s",
+ 	                      reasons->values[j].string.text);
+ 	    _cupsLangPuts(stdout, "\n");

Modified: cupsys/branches/cups-1.2/debian/patches/00list
==============================================================================
--- cupsys/branches/cups-1.2/debian/patches/00list	(original)
+++ cupsys/branches/cups-1.2/debian/patches/00list	Wed Nov 15 01:58:16 2006
@@ -1,3 +1,4 @@
+00_r6100.dpatch
 02_configure.dpatch
 #03_manext.dpatch
 03_clean.dpatch

Modified: cupsys/branches/cups-1.2/debian/patches/47_pid.dpatch
==============================================================================
--- cupsys/branches/cups-1.2/debian/patches/47_pid.dpatch	(original)
+++ cupsys/branches/cups-1.2/debian/patches/47_pid.dpatch	Wed Nov 15 01:58:16 2006
@@ -5,9 +5,9 @@
 ## DP: No description.
 
 @DPATCH@
-diff -urNad cupsys-1.1.99.b2~/scheduler/conf.c cupsys-1.1.99.b2/scheduler/conf.c
---- cupsys-1.1.99.b2~/scheduler/conf.c	2006-03-11 13:31:04.000000000 +0000
-+++ cupsys-1.1.99.b2/scheduler/conf.c	2006-03-11 13:31:16.000000000 +0000
+diff -urNad cupsys-1.2.6~/scheduler/conf.c cupsys-1.2.6/scheduler/conf.c
+--- cupsys-1.2.6~/scheduler/conf.c	2006-11-15 09:52:47.000000000 +0900
++++ cupsys-1.2.6/scheduler/conf.c	2006-11-15 09:52:47.000000000 +0900
 @@ -170,7 +170,8 @@
    { "StateDir",			&StateDir,		CUPSD_VARTYPE_STRING },
    { "TempDir",			&TempDir,		CUPSD_VARTYPE_STRING },
@@ -18,18 +18,18 @@
  };
  #define NUM_VARS	(sizeof(variables) / sizeof(variables[0]))
  
-@@ -287,6 +288,7 @@
+@@ -288,6 +289,7 @@
    cupsdSetString(&RemoteRoot, "remroot");
    cupsdSetString(&ServerHeader, "CUPS/1.2");
    cupsdSetString(&StateDir, CUPS_STATEDIR);
 +  cupsdSetString(&PidFile, "/var/run/cups/cupsd.pid");
  
-   strlcpy(temp, ConfigurationFile, sizeof(temp));
-   if ((slash = strrchr(temp, '/')) != NULL)
-diff -urNad cupsys-1.1.99.b2~/scheduler/conf.h cupsys-1.1.99.b2/scheduler/conf.h
---- cupsys-1.1.99.b2~/scheduler/conf.h	2006-03-11 13:31:04.000000000 +0000
-+++ cupsys-1.1.99.b2/scheduler/conf.h	2006-03-11 13:31:16.000000000 +0000
-@@ -186,6 +186,7 @@
+   if (!strcmp(CUPS_DEFAULT_PRINTCAP, "/etc/printers.conf"))
+     PrintcapFormat = PRINTCAP_SOLARIS;
+diff -urNad cupsys-1.2.6~/scheduler/conf.h cupsys-1.2.6/scheduler/conf.h
+--- cupsys-1.2.6~/scheduler/conf.h	2006-06-27 03:34:20.000000000 +0900
++++ cupsys-1.2.6/scheduler/conf.h	2006-11-15 09:52:47.000000000 +0900
+@@ -187,6 +187,7 @@
  					/* Server key file */
  #  endif /* HAVE_LIBSSL || HAVE_GNUTLS */
  #endif /* HAVE_SSL */
@@ -37,22 +37,21 @@
  
  #ifdef HAVE_LAUNCHD
  VAR int			LaunchdTimeout		VALUE(DEFAULT_TIMEOUT);
-diff -urNad cupsys-1.1.99.b2~/scheduler/main.c cupsys-1.1.99.b2/scheduler/main.c
---- cupsys-1.1.99.b2~/scheduler/main.c	2006-03-11 13:31:04.000000000 +0000
-+++ cupsys-1.1.99.b2/scheduler/main.c	2006-03-11 13:32:41.000000000 +0000
-@@ -89,7 +89,8 @@
- static void	sigterm_handler(int sig);
- static long	select_timeout(int fds);
- static void	usage(int status);
--
-+int write_pid(void);
-+int remvoe_pid(void);
+diff -urNad cupsys-1.2.6~/scheduler/main.c cupsys-1.2.6/scheduler/main.c
+--- cupsys-1.2.6~/scheduler/main.c	2006-11-15 09:52:46.000000000 +0900
++++ cupsys-1.2.6/scheduler/main.c	2006-11-15 09:54:01.000000000 +0900
+@@ -92,6 +92,8 @@
+ static void		sigterm_handler(int sig);
+ static long		select_timeout(int fds);
+ static void		usage(int status);
++int			write_pid(void);
++int			remove_pid(void);
+ 
  
  /*
-  * Local globals...
-@@ -501,6 +502,11 @@
-       kill(i, SIGUSR1);
+@@ -506,6 +508,11 @@
    }
+ #endif /* __sgi */
  
 +  if (write_pid() == 0) {
 +    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to write pid file");
@@ -60,9 +59,9 @@
 +  }
 +
   /*
-   * Start power management framework...
+   * Initialize authentication certificates...
    */
-@@ -1095,9 +1101,39 @@
+@@ -1161,9 +1168,39 @@
    free(input);
    free(output);
  



More information about the Pkg-cups-devel mailing list