[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