summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorDidier Raboud <odyx@debian.org>2012-10-25 21:01:59 +0200
committerDidier Raboud <odyx@debian.org>2012-10-25 21:01:59 +0200
commitb1469ea9a3a5b5b652dcd733f7d419dd1fdfe844 (patch)
tree5531f93b7c293790552944e6981a1745baaf7226 /backend
parent4ddc0bb6de85d409501de745bf1d3df896b15c02 (diff)
downloadcups-b1469ea9a3a5b5b652dcd733f7d419dd1fdfe844.tar.gz
Imported Upstream version 1.5.3upstream/1.5.3
Diffstat (limited to 'backend')
-rw-r--r--backend/Dependencies110
-rw-r--r--backend/Makefile10
-rw-r--r--backend/dnssd.c23
-rw-r--r--backend/ipp.c411
-rw-r--r--backend/lpd.c104
-rw-r--r--backend/runloop.c34
-rw-r--r--backend/snmp-supplies.c58
-rw-r--r--backend/usb-libusb.c1094
-rw-r--r--backend/usb.c10
9 files changed, 1375 insertions, 479 deletions
diff --git a/backend/Dependencies b/backend/Dependencies
index 4f99c17e..afc21fa9 100644
--- a/backend/Dependencies
+++ b/backend/Dependencies
@@ -3,77 +3,83 @@
ipp.o: backend-private.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
ipp.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
ipp.o: ../cups/language.h ../cups/string-private.h ../config.h
-ipp.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
-ipp.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
-ipp.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
-ipp.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
-ipp.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
-ipp.o: ../cups/sidechannel.h ../cups/array-private.h
+ipp.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h
+ipp.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+ipp.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+ipp.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+ipp.o: ../cups/transcode.h ../cups/thread-private.h ../cups/snmp-private.h
+ipp.o: ../cups/backend.h ../cups/sidechannel.h ../cups/array-private.h
+ipp.o: ../cups/array.h
lpd.o: ../cups/http-private.h ../config.h ../cups/http.h
lpd.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
lpd.o: backend-private.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
lpd.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
lpd.o: ../cups/language.h ../cups/string-private.h ../cups/debug-private.h
-lpd.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
-lpd.o: ../cups/pwg-private.h ../cups/http-private.h
+lpd.o: ../cups/versioning.h ../cups/ppd-private.h ../cups/ppd.h
+lpd.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
lpd.o: ../cups/language-private.h ../cups/transcode.h
lpd.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
lpd.o: ../cups/sidechannel.h
dnssd.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
dnssd.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
dnssd.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
-dnssd.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
-dnssd.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
-dnssd.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
-dnssd.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
-dnssd.o: ../cups/transcode.h ../cups/thread-private.h ../cups/snmp-private.h
-dnssd.o: ../cups/backend.h ../cups/sidechannel.h ../cups/array.h
+dnssd.o: ../config.h ../cups/debug-private.h ../cups/versioning.h
+dnssd.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+dnssd.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+dnssd.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+dnssd.o: ../cups/language-private.h ../cups/transcode.h
+dnssd.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
+dnssd.o: ../cups/sidechannel.h ../cups/array.h
parallel.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
parallel.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
parallel.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
-parallel.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
-parallel.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
-parallel.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
-parallel.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
-parallel.o: ../cups/transcode.h ../cups/thread-private.h
-parallel.o: ../cups/snmp-private.h ../cups/backend.h ../cups/sidechannel.h
+parallel.o: ../config.h ../cups/debug-private.h ../cups/versioning.h
+parallel.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+parallel.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+parallel.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+parallel.o: ../cups/language-private.h ../cups/transcode.h
+parallel.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
+parallel.o: ../cups/sidechannel.h
serial.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
serial.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
serial.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
-serial.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
-serial.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
-serial.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
-serial.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
-serial.o: ../cups/transcode.h ../cups/thread-private.h ../cups/snmp-private.h
-serial.o: ../cups/backend.h ../cups/sidechannel.h
+serial.o: ../config.h ../cups/debug-private.h ../cups/versioning.h
+serial.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+serial.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+serial.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+serial.o: ../cups/language-private.h ../cups/transcode.h
+serial.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
+serial.o: ../cups/sidechannel.h
snmp.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
snmp.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
snmp.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
-snmp.o: ../config.h ../cups/debug-private.h ../cups/ppd-private.h
-snmp.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
-snmp.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
-snmp.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
-snmp.o: ../cups/transcode.h ../cups/thread-private.h ../cups/snmp-private.h
-snmp.o: ../cups/backend.h ../cups/sidechannel.h ../cups/array.h
-snmp.o: ../cups/file.h ../cups/http-private.h
+snmp.o: ../config.h ../cups/debug-private.h ../cups/versioning.h
+snmp.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+snmp.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+snmp.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+snmp.o: ../cups/language-private.h ../cups/transcode.h
+snmp.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
+snmp.o: ../cups/sidechannel.h ../cups/array.h ../cups/file.h
+snmp.o: ../cups/http-private.h
socket.o: ../cups/http-private.h ../config.h ../cups/http.h
socket.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
socket.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
socket.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h ../cups/http.h
socket.o: ../cups/array.h ../cups/language.h ../cups/string-private.h
-socket.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
-socket.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
-socket.o: ../cups/language-private.h ../cups/transcode.h
-socket.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
-socket.o: ../cups/sidechannel.h
+socket.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h
+socket.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+socket.o: ../cups/http-private.h ../cups/language-private.h
+socket.o: ../cups/transcode.h ../cups/thread-private.h ../cups/snmp-private.h
+socket.o: ../cups/backend.h ../cups/sidechannel.h
test1284.o: ../cups/string-private.h ../config.h ieee1284.c backend-private.h
test1284.o: ../cups/cups-private.h ../cups/cups.h ../cups/file.h
test1284.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
test1284.o: ../cups/language.h ../cups/string-private.h
-test1284.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
-test1284.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
-test1284.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
-test1284.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
+test1284.o: ../cups/debug-private.h ../cups/versioning.h
+test1284.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
+test1284.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
+test1284.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
+test1284.o: ../cups/language-private.h ../cups/transcode.h
test1284.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
test1284.o: ../cups/sidechannel.h
testbackend.o: ../cups/string-private.h ../config.h ../cups/cups.h
@@ -84,18 +90,18 @@ testsupplies.o: backend-private.h ../cups/cups-private.h ../cups/cups.h
testsupplies.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h
testsupplies.o: ../cups/http.h ../cups/array.h ../cups/language.h
testsupplies.o: ../cups/string-private.h ../config.h ../cups/debug-private.h
-testsupplies.o: ../cups/ppd-private.h ../cups/ppd.h ../cups/cups.h
-testsupplies.o: ../cups/pwg-private.h ../cups/http-private.h ../cups/http.h
-testsupplies.o: ../cups/md5-private.h ../cups/ipp-private.h ../cups/ipp.h
-testsupplies.o: ../cups/language-private.h ../cups/transcode.h
+testsupplies.o: ../cups/versioning.h ../cups/ppd-private.h ../cups/ppd.h
+testsupplies.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
+testsupplies.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
+testsupplies.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
testsupplies.o: ../cups/thread-private.h ../cups/snmp-private.h
testsupplies.o: ../cups/backend.h ../cups/sidechannel.h
usb.o: backend-private.h ../cups/cups-private.h ../cups/cups.h ../cups/file.h
usb.o: ../cups/versioning.h ../cups/ipp.h ../cups/http.h ../cups/array.h
usb.o: ../cups/language.h ../cups/string-private.h ../config.h
-usb.o: ../cups/debug-private.h ../cups/ppd-private.h ../cups/ppd.h
-usb.o: ../cups/cups.h ../cups/pwg-private.h ../cups/http-private.h
-usb.o: ../cups/http.h ../cups/md5-private.h ../cups/ipp-private.h
-usb.o: ../cups/ipp.h ../cups/language-private.h ../cups/transcode.h
-usb.o: ../cups/thread-private.h ../cups/snmp-private.h ../cups/backend.h
-usb.o: ../cups/sidechannel.h
+usb.o: ../cups/debug-private.h ../cups/versioning.h ../cups/ppd-private.h
+usb.o: ../cups/ppd.h ../cups/cups.h ../cups/pwg-private.h
+usb.o: ../cups/http-private.h ../cups/http.h ../cups/md5-private.h
+usb.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
+usb.o: ../cups/transcode.h ../cups/thread-private.h ../cups/snmp-private.h
+usb.o: ../cups/backend.h ../cups/sidechannel.h
diff --git a/backend/Makefile b/backend/Makefile
index 47feac9e..643ee0cd 100644
--- a/backend/Makefile
+++ b/backend/Makefile
@@ -1,9 +1,9 @@
#
-# "$Id: Makefile 9737 2011-05-04 04:28:00Z mike $"
+# "$Id: Makefile 10425 2012-04-23 17:42:12Z mike $"
#
# Backend makefile for CUPS.
#
-# Copyright 2007-2011 by Apple Inc.
+# Copyright 2007-2012 by Apple Inc.
# Copyright 1997-2007 by Easy Software Products, all rights reserved.
#
# These coded instructions, statements, and computer programs are the
@@ -98,7 +98,7 @@ install-exec: $(INSTALLXPC)
$(RM) $(SERVERBIN)/backend/$$file; \
$(LN) ipp $(SERVERBIN)/backend/$$file; \
done
- if test "x$(DNSSD_BACKEND)" != x; then \
+ if test "x$(DNSSD_BACKEND)" != x -a `uname` = Darwin; then \
$(RM) $(SERVERBIN)/backend/mdns; \
$(LN) $(DNSSD_BACKEND) $(SERVERBIN)/backend/mdns; \
fi
@@ -268,7 +268,7 @@ socket: socket.o ../cups/$(LIBCUPS) libbackend.a
usb: usb.o ../cups/$(LIBCUPS) libbackend.a
echo Linking $@...
- $(CC) $(LDFLAGS) -o usb usb.o libbackend.a $(LIBUSB) \
+ $(CC) $(ARCHFLAGS) $(LDFLAGS) -o usb usb.o libbackend.a $(LIBUSB) \
$(BACKLIBS) $(LIBS)
usb.o: usb.c usb-darwin.c usb-libusb.c usb-unix.c
@@ -281,5 +281,5 @@ include Dependencies
#
-# End of "$Id: Makefile 9737 2011-05-04 04:28:00Z mike $".
+# End of "$Id: Makefile 10425 2012-04-23 17:42:12Z mike $".
#
diff --git a/backend/dnssd.c b/backend/dnssd.c
index f37e8123..02c78754 100644
--- a/backend/dnssd.c
+++ b/backend/dnssd.c
@@ -1,9 +1,9 @@
/*
- * "$Id: dnssd.c 10017 2011-09-26 18:46:46Z mike $"
+ * "$Id: dnssd.c 10379 2012-03-23 22:16:22Z mike $"
*
* DNS-SD discovery backend for CUPS.
*
- * Copyright 2008-2011 by Apple Inc.
+ * Copyright 2008-2012 by Apple Inc.
*
* These coded instructions, statements, and computer programs are the
* property of Apple Inc. and are protected by Federal copyright
@@ -43,8 +43,8 @@
typedef enum
{
CUPS_DEVICE_PRINTER = 0, /* lpd://... */
- CUPS_DEVICE_IPP, /* ipp://... */
CUPS_DEVICE_IPPS, /* ipps://... */
+ CUPS_DEVICE_IPP, /* ipp://... */
CUPS_DEVICE_FAX_IPP, /* ipp://... */
CUPS_DEVICE_PDL_DATASTREAM, /* socket://... */
CUPS_DEVICE_RIOUSBPRINT /* riousbprint://... */
@@ -84,7 +84,8 @@ static void browse_callback(DNSServiceRef sdRef,
DNSServiceErrorType errorCode,
const char *serviceName,
const char *regtype,
- const char *replyDomain, void *context);
+ const char *replyDomain, void *context)
+ __attribute__((nonnull(1,5,6,7,8)));
static void browse_local_callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
@@ -92,13 +93,15 @@ static void browse_local_callback(DNSServiceRef sdRef,
const char *serviceName,
const char *regtype,
const char *replyDomain,
- void *context);
+ void *context)
+ __attribute__((nonnull(1,5,6,7,8)));
static int compare_devices(cups_device_t *a, cups_device_t *b);
static void exec_backend(char **argv);
static cups_device_t *get_device(cups_array_t *devices,
const char *serviceName,
const char *regtype,
- const char *replyDomain);
+ const char *replyDomain)
+ __attribute__((nonnull(1,2,3,4)));
static void query_callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
@@ -106,9 +109,11 @@ static void query_callback(DNSServiceRef sdRef,
const char *fullName, uint16_t rrtype,
uint16_t rrclass, uint16_t rdlen,
const void *rdata, uint32_t ttl,
- void *context);
+ void *context)
+ __attribute__((nonnull(1,5,9,11)));
static void sigterm_handler(int sig);
-static void unquote(char *dst, const char *src, size_t dstsize);
+static void unquote(char *dst, const char *src, size_t dstsize)
+ __attribute__((nonnull(1,2)));
/*
@@ -961,5 +966,5 @@ unquote(char *dst, /* I - Destination buffer */
/*
- * End of "$Id: dnssd.c 10017 2011-09-26 18:46:46Z mike $".
+ * End of "$Id: dnssd.c 10379 2012-03-23 22:16:22Z mike $".
*/
diff --git a/backend/ipp.c b/backend/ipp.c
index 23dab618..e27f38ee 100644
--- a/backend/ipp.c
+++ b/backend/ipp.c
@@ -1,9 +1,9 @@
/*
- * "$Id: ipp.c 10112 2011-11-07 06:08:44Z mike $"
+ * "$Id: ipp.c 10452 2012-05-04 23:00:01Z mike $"
*
* IPP backend for CUPS.
*
- * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2007-2012 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
@@ -63,6 +63,7 @@ typedef struct _cups_monitor_s /**** Monitoring data ****/
int port, /* Port number */
version, /* IPP version */
job_id; /* Job ID for submitted job */
+ const char *job_name; /* Job name for submitted job */
http_encryption_t encryption; /* Use encryption? */
ipp_jstate_t job_state; /* Current job state */
ipp_pstate_t printer_state; /* Current printer state */
@@ -82,12 +83,16 @@ static const char * const jattrs[] = /* Job attributes we want */
{
"job-impressions-completed",
"job-media-sheets-completed",
+ "job-name",
+ "job-originating-user-name",
"job-state",
"job-state-reasons"
};
static int job_canceled = 0;
/* Job cancelled? */
-static char *password = NULL;
+static char username[256] = "",
+ /* Username for device URI */
+ *password = NULL;
/* Password for device URI */
static int password_tries = 0;
/* Password tries */
@@ -186,7 +191,6 @@ main(int argc, /* I - Number of command-line args */
const char *device_uri; /* Device URI */
char scheme[255], /* Scheme in URI */
hostname[1024], /* Hostname */
- username[255], /* Username info */
resource[1024], /* Resource info (printer name) */
addrname[256], /* Address name */
*optptr, /* Pointer to URI options */
@@ -205,6 +209,7 @@ main(int argc, /* I - Number of command-line args */
int port; /* Port number (not used) */
char portname[255]; /* Port name */
char uri[HTTP_MAX_URI]; /* Updated URI without user/pass */
+ char print_job_name[1024]; /* Update job-name for Print-Job */
http_status_t http_status; /* Status of HTTP request */
ipp_status_t ipp_status; /* Status of IPP request */
http_t *http; /* HTTP connection */
@@ -231,7 +236,9 @@ main(int argc, /* I - Number of command-line args */
ipp_attribute_t *doc_handling_sup; /* multiple-document-handling-supported */
ipp_attribute_t *printer_state; /* printer-state attribute */
ipp_attribute_t *printer_accepting; /* printer-is-accepting-jobs */
- int validate_job; /* Does printer support Validate-Job? */
+ int create_job = 0, /* Does printer support Create-Job? */
+ send_document = 0, /* Does printer support Send-Document? */
+ validate_job = 0; /* Does printer support Validate-Job? */
int copies, /* Number of copies for job */
copies_remaining; /* Number of copies remaining */
const char *content_type, /* CONTENT_TYPE environment variable */
@@ -604,7 +611,10 @@ main(int argc, /* I - Number of command-line args */
const char *ptr = getenv("AUTH_USERNAME");
if (ptr)
+ {
+ strlcpy(username, ptr, sizeof(username));
cupsSetUser(ptr);
+ }
password = getenv("AUTH_PASSWORD");
}
@@ -789,7 +799,6 @@ main(int argc, /* I - Number of command-line args */
supported = NULL;
operations_sup = NULL;
doc_handling_sup = NULL;
- validate_job = 0;
do
{
@@ -834,7 +843,9 @@ main(int argc, /* I - Number of command-line args */
fprintf(stderr, "DEBUG: Get-Printer-Attributes: %s (%s)\n",
ippErrorString(ipp_status), cupsLastErrorString());
- if (ipp_status > IPP_OK_CONFLICT)
+ if (ipp_status <= IPP_OK_CONFLICT)
+ password_tries = 0;
+ else
{
fprintf(stderr, "DEBUG: Get-Printer-Attributes returned %s.\n",
ippErrorString(ipp_status));
@@ -891,16 +902,21 @@ main(int argc, /* I - Number of command-line args */
return (CUPS_BACKEND_STOP);
}
- else if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
+ else if (ipp_status == IPP_FORBIDDEN ||
+ ipp_status == IPP_AUTHENTICATION_CANCELED)
{
- if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
- "Negotiate", 9))
+ const char *www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE);
+ /* WWW-Authenticate field value */
+
+ if (!strncmp(www_auth, "Negotiate", 9))
auth_info_required = "negotiate";
+ else if (www_auth[0])
+ auth_info_required = "username,password";
fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
return (CUPS_BACKEND_AUTH_REQUIRED);
}
- else
+ else if (ipp_status != IPP_NOT_AUTHORIZED)
{
_cupsLangPrintFilter(stderr, "ERROR",
_("Unable to get printer status."));
@@ -1042,11 +1058,21 @@ main(int argc, /* I - Number of command-line args */
"cups-ipp-missing-get-printer-attributes");
for (i = 0; i < operations_sup->num_values; i ++)
+ {
if (operations_sup->values[i].integer == IPP_VALIDATE_JOB)
- {
validate_job = 1;
- break;
- }
+ else if (operations_sup->values[i].integer == IPP_CREATE_JOB)
+ create_job = 1;
+ else if (operations_sup->values[i].integer == IPP_SEND_DOCUMENT)
+ send_document = 1;
+ }
+
+ if (!send_document)
+ {
+ fputs("DEBUG: Printer supports Create-Job but not Send-Document.\n",
+ stderr);
+ create_job = 0;
+ }
if (!validate_job)
update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
@@ -1116,7 +1142,7 @@ main(int argc, /* I - Number of command-line args */
{
copies_remaining = 1;
- if (argc < 7 && !send_options)
+ if (argc < 7 && !_cups_strncasecmp(final_content_type, "image/", 6))
copies = 1;
}
else
@@ -1153,7 +1179,8 @@ main(int argc, /* I - Number of command-line args */
if (format_sup != NULL)
{
for (i = 0; i < format_sup->num_values; i ++)
- if (!_cups_strcasecmp(final_content_type, format_sup->values[i].string.text))
+ if (!_cups_strcasecmp(final_content_type,
+ format_sup->values[i].string.text))
{
document_format = final_content_type;
break;
@@ -1163,7 +1190,7 @@ main(int argc, /* I - Number of command-line args */
{
for (i = 0; i < format_sup->num_values; i ++)
if (!_cups_strcasecmp("application/octet-stream",
- format_sup->values[i].string.text))
+ format_sup->values[i].string.text))
{
document_format = "application/octet-stream";
break;
@@ -1171,6 +1198,9 @@ main(int argc, /* I - Number of command-line args */
}
}
+ fprintf(stderr, "DEBUG: final_content_type=\"%s\", document_format=\"%s\"\n",
+ final_content_type, document_format ? document_format : "(null)");
+
/*
* If the printer does not support HTTP/1.1 (which IPP requires), copy stdin
* to a temporary file so that we can do a HTTP/1.0 submission...
@@ -1188,8 +1218,17 @@ main(int argc, /* I - Number of command-line args */
_cupsLangPrintFilter(stderr, "INFO", _("Copying print data."));
- compatsize = backendRunLoop(-1, fd, snmp_fd, &(addrlist->addr), 0, 0,
- backendNetworkSideCB);
+ if ((compatsize = write(fd, buffer, bytes)) < 0)
+ {
+ perror("DEBUG: Unable to write temporary file");
+ return (CUPS_BACKEND_FAILED);
+ }
+
+ if ((bytes = backendRunLoop(-1, fd, snmp_fd, &(addrlist->addr), 0, 0,
+ backendNetworkSideCB)) < 0)
+ return (CUPS_BACKEND_FAILED);
+
+ compatsize += bytes;
close(fd);
@@ -1220,6 +1259,17 @@ main(int argc, /* I - Number of command-line args */
monitor.job_state = IPP_JOB_PENDING;
monitor.printer_state = IPP_PRINTER_IDLE;
+ if (create_job)
+ {
+ monitor.job_name = argv[3];
+ }
+ else
+ {
+ snprintf(print_job_name, sizeof(print_job_name), "%s - %s", argv[1],
+ argv[3]);
+ monitor.job_name = print_job_name;
+ }
+
_cupsThreadCreate((_cups_thread_func_t)monitor_printer, &monitor);
/*
@@ -1228,8 +1278,8 @@ main(int argc, /* I - Number of command-line args */
while (!job_canceled && validate_job)
{
- request = new_request(IPP_VALIDATE_JOB, version, uri, argv[2], argv[3],
- num_options, options, compression,
+ request = new_request(IPP_VALIDATE_JOB, version, uri, argv[2],
+ monitor.job_name, num_options, options, compression,
copies_sup ? copies : 1, document_format, pc,
media_col_sup, doc_handling_sup);
@@ -1248,26 +1298,16 @@ main(int argc, /* I - Number of command-line args */
_cupsLangPrintFilter(stderr, "INFO", _("The printer is busy."));
sleep(10);
}
- else if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN ||
+ else if (ipp_status == IPP_FORBIDDEN ||
ipp_status == IPP_AUTHENTICATION_CANCELED)
{
- /*
- * Update auth-info-required as needed...
- */
-
- fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n",
- httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE));
-
- /*
- * Normal authentication goes through the password callback, which sets
- * auth_info_required to "username,password". Kerberos goes directly
- * through GSSAPI, so look for Negotiate in the WWW-Authenticate header
- * here and set auth_info_required as needed...
- */
+ const char *www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE);
+ /* WWW-Authenticate field value */
- if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
- "Negotiate", 9))
+ if (!strncmp(www_auth, "Negotiate", 9))
auth_info_required = "negotiate";
+ else if (www_auth[0])
+ auth_info_required = "username,password";
goto cleanup;
}
@@ -1281,7 +1321,8 @@ main(int argc, /* I - Number of command-line args */
"cups-ipp-missing-validate-job");
break;
}
- else if (ipp_status < IPP_REDIRECTION_OTHER_SITE)
+ else if (ipp_status < IPP_REDIRECTION_OTHER_SITE ||
+ ipp_status == IPP_BAD_REQUEST)
break;
}
@@ -1306,16 +1347,17 @@ main(int argc, /* I - Number of command-line args */
if (job_canceled)
break;
- request = new_request(num_files > 1 ? IPP_CREATE_JOB : IPP_PRINT_JOB,
- version, uri, argv[2], argv[3], num_options, options,
- compression, copies_sup ? copies : 1, document_format,
- pc, media_col_sup, doc_handling_sup);
+ request = new_request((num_files > 1 || create_job) ? IPP_CREATE_JOB :
+ IPP_PRINT_JOB,
+ version, uri, argv[2], monitor.job_name, num_options,
+ options, compression, copies_sup ? copies : 1,
+ document_format, pc, media_col_sup, doc_handling_sup);
/*
* Do the request...
*/
- if (num_files > 1)
+ if (num_files > 1 || create_job)
response = cupsDoRequest(http, request, resource);
else
{
@@ -1333,7 +1375,13 @@ main(int argc, /* I - Number of command-line args */
if (http_status == HTTP_CONTINUE && request->state == IPP_DATA)
{
if (num_files == 1)
- fd = open(files[0], O_RDONLY);
+ {
+ if ((fd = open(files[0], O_RDONLY)) < 0)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
else
{
fd = 0;
@@ -1382,7 +1430,7 @@ main(int argc, /* I - Number of command-line args */
ipp_status = cupsLastError();
fprintf(stderr, "DEBUG: %s: %s (%s)\n",
- num_files > 1 ? "Create-Job" : "Print-Job",
+ (num_files > 1 || create_job) ? "Create-Job" : "Print-Job",
ippErrorString(ipp_status), cupsLastErrorString());
if (ipp_status > IPP_OK_CONFLICT)
@@ -1411,6 +1459,8 @@ main(int argc, /* I - Number of command-line args */
}
else if (ipp_status == IPP_ERROR_JOB_CANCELED)
goto cleanup;
+ else if (ipp_status == IPP_NOT_AUTHORIZED)
+ continue;
else
{
/*
@@ -1420,21 +1470,24 @@ main(int argc, /* I - Number of command-line args */
_cupsLangPrintFilter(stderr, "ERROR",
_("Print file was not accepted."));
- if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
+ if (ipp_status == IPP_FORBIDDEN ||
+ ipp_status == IPP_AUTHENTICATION_CANCELED)
{
- fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n",
- httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE));
+ const char *www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE);
+ /* WWW-Authenticate field value */
- /*
- * Normal authentication goes through the password callback, which sets
- * auth_info_required to "username,password". Kerberos goes directly
- * through GSSAPI, so look for Negotiate in the WWW-Authenticate header
- * here and set auth_info_required as needed...
+ if (!strncmp(www_auth, "Negotiate", 9))
+ auth_info_required = "negotiate";
+ else if (www_auth[0])
+ auth_info_required = "username,password";
+ }
+ else if (ipp_status == IPP_REQUEST_VALUE)
+ {
+ /*
+ * Print file is too large, abort this job...
*/
- if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
- "Negotiate", 9))
- auth_info_required = "negotiate";
+ goto cleanup;
}
else
sleep(10);
@@ -1461,19 +1514,21 @@ main(int argc, /* I - Number of command-line args */
}
else
{
+ password_tries = 0;
monitor.job_id = job_id = job_id_attr->values[0].integer;
_cupsLangPrintFilter(stderr, "INFO",
_("Print file accepted - job ID %d."), job_id);
}
+ fprintf(stderr, "DEBUG: job-id=%d\n", job_id);
ippDelete(response);
if (job_canceled)
break;
- if (job_id && num_files > 1)
+ if (job_id && (num_files > 1 || create_job))
{
- for (i = 0; i < num_files; i ++)
+ for (i = 0; num_files == 0 || i < num_files; i ++)
{
/*
* Check for side-channel requests...
@@ -1499,21 +1554,41 @@ main(int argc, /* I - Number of command-line args */
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
"requesting-user-name", NULL, argv[2]);
- if ((i + 1) == num_files)
+ if ((i + 1) >= num_files)
ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
- ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
- "document-format", NULL, content_type);
+ if (document_format)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
+ "document-format", NULL, document_format);
fprintf(stderr, "DEBUG: Sending file %d using chunking...\n", i + 1);
http_status = cupsSendRequest(http, request, resource, 0);
- if (http_status == HTTP_CONTINUE && request->state == IPP_DATA &&
- (fd = open(files[i], O_RDONLY)) >= 0)
+ if (http_status == HTTP_CONTINUE && request->state == IPP_DATA)
{
- while (!job_canceled &&
+ if (num_files == 0)
+ {
+ fd = 0;
+ http_status = cupsWriteRequestData(http, buffer, bytes);
+ }
+ else
+ {
+ if ((fd = open(files[i], O_RDONLY)) < 0)
+ {
+ _cupsLangPrintError("ERROR", _("Unable to open print file"));
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+ }
+ else
+ fd = -1;
+
+ if (fd >= 0)
+ {
+ while (!job_canceled && http_status == HTTP_CONTINUE &&
(bytes = read(fd, buffer, sizeof(buffer))) > 0)
{
- if (cupsWriteRequestData(http, buffer, bytes) != HTTP_CONTINUE)
+ if ((http_status = cupsWriteRequestData(http, buffer, bytes))
+ != HTTP_CONTINUE)
break;
else
{
@@ -1525,7 +1600,8 @@ main(int argc, /* I - Number of command-line args */
}
}
- close(fd);
+ if (fd > 0)
+ close(fd);
}
ippDelete(cupsGetResponse(http, resource));
@@ -1542,6 +1618,13 @@ main(int argc, /* I - Number of command-line args */
_("Unable to add document to print job."));
break;
}
+ else
+ {
+ password_tries = 0;
+
+ if (num_files == 0 || fd < 0)
+ break;
+ }
}
}
@@ -1554,6 +1637,14 @@ main(int argc, /* I - Number of command-line args */
ipp_status == IPP_NOT_POSSIBLE ||
ipp_status == IPP_PRINTER_BUSY)
continue;
+ else if (ipp_status == IPP_REQUEST_VALUE)
+ {
+ /*
+ * Print file is too large, abort this job...
+ */
+
+ goto cleanup;
+ }
else
copies_remaining --;
@@ -1621,16 +1712,16 @@ main(int argc, /* I - Number of command-line args */
fprintf(stderr, "DEBUG: Get-Job-Attributes: %s (%s)\n",
ippErrorString(ipp_status), cupsLastErrorString());
- if (ipp_status > IPP_OK_CONFLICT)
+ if (ipp_status <= IPP_OK_CONFLICT)
+ password_tries = 0;
+ else
{
if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
ipp_status != IPP_NOT_POSSIBLE &&
ipp_status != IPP_PRINTER_BUSY)
{
ippDelete(response);
-
- _cupsLangPrintFilter(stderr, "ERROR",
- _("Unable to get print job status."));
+ ipp_status = IPP_OK;
break;
}
}
@@ -1777,6 +1868,11 @@ main(int argc, /* I - Number of command-line args */
else if (ipp_status == IPP_DOCUMENT_FORMAT ||
ipp_status == IPP_CONFLICT)
return (CUPS_BACKEND_FAILED);
+ else if (ipp_status == IPP_REQUEST_VALUE)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR", _("Print job too large."));
+ return (CUPS_BACKEND_CANCEL);
+ }
else if (ipp_status > IPP_OK_CONFLICT && ipp_status != IPP_ERROR_JOB_CANCELED)
return (CUPS_BACKEND_RETRY_CURRENT);
else
@@ -1879,6 +1975,9 @@ check_printer_state(
fprintf(stderr, "DEBUG: Get-Printer-Attributes: %s (%s)\n",
ippErrorString(cupsLastError()), cupsLastErrorString());
+ if (cupsLastError() <= IPP_OK_CONFLICT)
+ password_tries = 0;
+
/*
* Return the printer-state value...
*/
@@ -1972,6 +2071,11 @@ monitor_printer(
ipp_attribute_t *attr; /* Attribute in response */
int delay, /* Current delay */
prev_delay; /* Previous delay */
+ ipp_op_t job_op; /* Operation to use */
+ int job_id; /* Job ID */
+ const char *job_name; /* Job name */
+ ipp_jstate_t job_state; /* Job state */
+ const char *job_user; /* Job originating user name */
/*
@@ -1981,6 +2085,8 @@ monitor_printer(
http = _httpCreate(monitor->hostname, monitor->port, NULL, monitor->encryption,
AF_UNSPEC);
httpSetTimeout(http, 30.0, timeout_cb, NULL);
+ if (username[0])
+ cupsSetUser(username);
cupsSetPasswordCB(password_cb);
/*
@@ -2006,47 +2112,99 @@ monitor_printer(
monitor->user,
monitor->version);
- if (monitor->job_id > 0)
- {
- /*
- * Check the status of the job itself...
- */
+ /*
+ * Check the status of the job itself...
+ */
- request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
- request->request.op.version[0] = monitor->version / 10;
- request->request.op.version[1] = monitor->version % 10;
+ job_op = monitor->job_id > 0 ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS;
+ request = ippNewRequest(job_op);
+ request->request.op.version[0] = monitor->version / 10;
+ request->request.op.version[1] = monitor->version % 10;
- ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
- NULL, monitor->uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, monitor->uri);
+ if (job_op == IPP_GET_JOB_ATTRIBUTES)
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
- monitor->job_id);
+ monitor->job_id);
- if (monitor->user && monitor->user[0])
- ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
- "requesting-user-name", NULL, monitor->user);
+ if (monitor->user && monitor->user[0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, monitor->user);
- ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
- "requested-attributes",
- (int)(sizeof(jattrs) / sizeof(jattrs[0])), NULL, jattrs);
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (int)(sizeof(jattrs) / sizeof(jattrs[0])), NULL, jattrs);
- /*
- * Do the request...
- */
+ /*
+ * Do the request...
+ */
- response = cupsDoRequest(http, request, monitor->resource);
+ response = cupsDoRequest(http, request, monitor->resource);
- fprintf(stderr, "DEBUG: Get-Job-Attributes: %s (%s)\n",
- ippErrorString(cupsLastError()), cupsLastErrorString());
+ fprintf(stderr, "DEBUG: %s: %s (%s)\n", ippOpString(job_op),
+ ippErrorString(cupsLastError()), cupsLastErrorString());
+ if (cupsLastError() <= IPP_OK_CONFLICT)
+ password_tries = 0;
+
+ if (job_op == IPP_GET_JOB_ATTRIBUTES)
+ {
if ((attr = ippFindAttribute(response, "job-state",
IPP_TAG_ENUM)) != NULL)
monitor->job_state = (ipp_jstate_t)attr->values[0].integer;
else
monitor->job_state = IPP_JOB_COMPLETED;
+ }
+ else if (response)
+ {
+ for (attr = response->attrs; attr; attr = attr->next)
+ {
+ job_id = 0;
+ job_name = NULL;
+ job_state = IPP_JOB_PENDING;
+ job_user = NULL;
- ippDelete(response);
+ while (attr && attr->group_tag != IPP_TAG_JOB)
+ attr = attr->next;
+
+ if (!attr)
+ break;
+
+ while (attr && attr->group_tag == IPP_TAG_JOB)
+ {
+ if (!strcmp(attr->name, "job-id") &&
+ attr->value_tag == IPP_TAG_INTEGER)
+ job_id = attr->values[0].integer;
+ else if (!strcmp(attr->name, "job-name") &&
+ (attr->value_tag == IPP_TAG_NAME ||
+ attr->value_tag == IPP_TAG_NAMELANG))
+ job_name = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "job-state") &&
+ attr->value_tag == IPP_TAG_ENUM)
+ job_state = attr->values[0].integer;
+ else if (!strcmp(attr->name, "job-originating-user-name") &&
+ (attr->value_tag == IPP_TAG_NAME ||
+ attr->value_tag == IPP_TAG_NAMELANG))
+ job_user = attr->values[0].string.text;
+
+ attr = attr->next;
+ }
+
+ if (job_id > 0 && job_name && !strcmp(job_name, monitor->job_name) &&
+ job_user && monitor->user && !strcmp(job_user, monitor->user))
+ {
+ monitor->job_id = job_id;
+ monitor->job_state = job_state;
+ break;
+ }
+
+ if (!attr)
+ break;
+ }
}
+ ippDelete(response);
+
/*
* Disconnect from the printer - we'll reconnect on the next poll...
*/
@@ -2064,6 +2222,15 @@ monitor_printer(
}
/*
+ * Cancel the job if necessary...
+ */
+
+ if (job_canceled && monitor->job_id > 0)
+ if (!httpReconnect(http))
+ cancel_job(http, monitor->uri, monitor->job_id, monitor->resource,
+ monitor->user, monitor->version);
+
+ /*
* Cleanup and return...
*/
@@ -2088,7 +2255,7 @@ new_request(
cups_option_t *options, /* I - Options to send */
const char *compression, /* I - compression value or NULL */
int copies, /* I - copies value or 0 */
- const char *format, /* I - documet-format value or NULL */
+ const char *format, /* I - document-format value or NULL */
_ppd_cache_t *pc, /* I - PPD cache and mapping data */
ipp_attribute_t *media_col_sup, /* I - media-col-supported values */
ipp_attribute_t *doc_handling_sup) /* I - multiple-document-handling-supported values */
@@ -2163,6 +2330,9 @@ new_request(
{
if (pc)
{
+ int num_finishings = 0, /* Number of finishing values */
+ finishings[10]; /* Finishing enum values */
+
/*
* Send standard IPP attributes...
*/
@@ -2284,6 +2454,7 @@ new_request(
}
if (doc_handling_sup &&
+ (!format || _cups_strncasecmp(format, "image/", 6)) &&
(keyword = cupsGetOption("collate", num_options, options)) != NULL)
{
if (!_cups_strcasecmp(keyword, "true"))
@@ -2299,6 +2470,43 @@ new_request(
break;
}
}
+
+ /*
+ * Map finishing options...
+ */
+
+ num_finishings = _ppdCacheGetFinishingValues(pc, num_options, options,
+ (int)(sizeof(finishings) /
+ sizeof(finishings[0])),
+ finishings);
+ if (num_finishings > 0)
+ ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings",
+ num_finishings, finishings);
+
+ /*
+ * Map FaxOut options...
+ */
+
+ if ((keyword = cupsGetOption("phone", num_options, options)) != NULL)
+ {
+ ipp_t *destination; /* destination collection */
+ char tel_uri[1024]; /* tel: URI */
+
+ destination = ippNew();
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, tel_uri, sizeof(tel_uri), "tel",
+ NULL, NULL, 0, keyword);
+ ippAddString(destination, IPP_TAG_JOB, IPP_TAG_URI, "destination-uri",
+ NULL, tel_uri);
+
+ if ((keyword = cupsGetOption("faxPrefix", num_options,
+ options)) != NULL && *keyword)
+ ippAddString(destination, IPP_TAG_JOB, IPP_TAG_TEXT,
+ "pre-dial-string", NULL, keyword);
+
+ ippAddCollection(request, IPP_TAG_JOB, "destination-uris", destination);
+ ippDelete(destination);
+ }
}
else
{
@@ -2324,6 +2532,9 @@ new_request(
static const char * /* O - Password */
password_cb(const char *prompt) /* I - Prompt (not used) */
{
+ fprintf(stderr, "DEBUG: password_cb(prompt=\"%s\"), password=%p, "
+ "password_tries=%d\n", prompt, password, password_tries);
+
(void)prompt;
/*
@@ -2386,17 +2597,23 @@ report_attr(ipp_attribute_t *attr) /* I - Attribute */
case IPP_TAG_TEXT :
case IPP_TAG_NAME :
case IPP_TAG_KEYWORD :
+ *valptr++ = '\'';
*valptr++ = '\"';
for (attrptr = attr->values[i].string.text;
*attrptr && valptr < (value + sizeof(value) - 10);
attrptr ++)
{
- if (*attrptr == '\\' || *attrptr == '\"')
+ if (*attrptr == '\\' || *attrptr == '\"' || *attrptr == '\'')
+ {
+ *valptr++ = '\\';
*valptr++ = '\\';
+ *valptr++ = '\\';
+ }
*valptr++ = *attrptr;
}
*valptr++ = '\"';
+ *valptr++ = '\'';
break;
default :
@@ -2988,5 +3205,5 @@ update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */
}
/*
- * End of "$Id: ipp.c 10112 2011-11-07 06:08:44Z mike $".
+ * End of "$Id: ipp.c 10452 2012-05-04 23:00:01Z mike $".
*/
diff --git a/backend/lpd.c b/backend/lpd.c
index cd2edc1f..7837b344 100644
--- a/backend/lpd.c
+++ b/backend/lpd.c
@@ -1,9 +1,9 @@
/*
- * "$Id: lpd.c 9793 2011-05-20 03:49:49Z mike $"
+ * "$Id: lpd.c 10265 2012-02-12 07:20:10Z mike $"
*
* Line Printer Daemon backend for CUPS.
*
- * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2007-2012 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
@@ -19,7 +19,6 @@
* main() - Send a file to the printer or server.
* lpd_command() - Send an LPR command sequence and wait for a reply.
* lpd_queue() - Queue a file using the Line Printer Daemon protocol.
- * lpd_timeout() - Handle timeout alarms...
* lpd_write() - Write a buffer of data to an LPD server.
* rresvport_af() - A simple implementation of rresvport_af().
* sigterm_handler() - Handle 'terminate' signals that stop the backend.
@@ -87,14 +86,13 @@ static int abort_job = 0; /* Non-zero if we get SIGTERM */
* Local functions...
*/
-static int lpd_command(int lpd_fd, int timeout, char *format, ...);
+static int lpd_command(int lpd_fd, char *format, ...);
static int lpd_queue(const char *hostname, http_addrlist_t *addrlist,
const char *printer, int print_fd, int snmp_fd,
int mode, const char *user, const char *title,
int copies, int banner, int format, int order,
int reserve, int manual_copies, int timeout,
int contimeout);
-static void lpd_timeout(int sig);
static int lpd_write(int lpd_fd, char *buffer, int length);
#ifndef HAVE_RRESVPORT_AF
static int rresvport_af(int *port, int family);
@@ -564,7 +562,6 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
static int /* O - Status of command */
lpd_command(int fd, /* I - Socket connection to LPD host */
- int timeout, /* I - Seconds to wait for a response */
char *format, /* I - printf()-style format string */
...) /* I - Additional args as necessary */
{
@@ -609,18 +606,12 @@ lpd_command(int fd, /* I - Socket connection to LPD host */
fputs("DEBUG: Reading command status...\n", stderr);
- alarm(timeout);
-
if (recv(fd, &status, 1, 0) < 1)
{
- _cupsLangPrintFilter(stderr, "WARNING",
- _("Printer did not respond after %d seconds."),
- timeout);
+ _cupsLangPrintFilter(stderr, "WARNING", _("Printer did not respond."));
status = errno;
}
- alarm(0);
-
fprintf(stderr, "DEBUG: lpd_command returning %d\n", status);
return (status);
@@ -666,26 +657,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */
size_t nbytes; /* Number of bytes written */
off_t tbytes; /* Total bytes written */
char buffer[32768]; /* Output buffer */
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Actions for POSIX signals */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-
-
- /*
- * Setup an alarm handler for timeouts...
- */
-
-#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
- sigset(SIGALRM, lpd_timeout);
-#elif defined(HAVE_SIGACTION)
- memset(&action, 0, sizeof(action));
-
- sigemptyset(&action.sa_mask);
- action.sa_handler = lpd_timeout;
- sigaction(SIGALRM, &action, NULL);
+#ifdef WIN32
+ DWORD tv; /* Timeout in milliseconds */
#else
- signal(SIGALRM, lpd_timeout);
-#endif /* HAVE_SIGSET */
+ struct timeval tv; /* Timeout in secs and usecs */
+#endif /* WIN32 */
+
/*
* Remember when we started trying to connect to the printer...
@@ -864,6 +841,23 @@ lpd_queue(const char *hostname, /* I - Host to connect to */
}
}
+ /*
+ * Set the timeout...
+ */
+
+#ifdef WIN32
+ tv = (DWORD)(timeout * 1000);
+
+ setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
+ setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
+#else
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+ setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+#endif /* WIN32 */
+
fputs("STATE: -connecting-to-device\n", stderr);
_cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));
@@ -926,7 +920,7 @@ lpd_queue(const char *hostname, /* I - Host to connect to */
* literal output...
*/
- if (lpd_command(fd, timeout, "\002%s\n",
+ if (lpd_command(fd, "\002%s\n",
printer)) /* Receive print job(s) */
{
close(fd);
@@ -978,7 +972,7 @@ lpd_queue(const char *hostname, /* I - Host to connect to */
* Send the control file...
*/
- if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
+ if (lpd_command(fd, "\002%d cfA%03.3d%.15s\n", strlen(control),
(int)getpid() % 1000, localhost))
{
close(fd);
@@ -997,17 +991,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */
}
else
{
- alarm(timeout);
-
if (read(fd, &status, 1) < 1)
{
_cupsLangPrintFilter(stderr, "WARNING",
- _("Printer did not respond after %d seconds."),
- timeout);
+ _("Printer did not respond."));
status = errno;
}
-
- alarm(0);
}
if (status != 0)
@@ -1033,7 +1022,7 @@ lpd_queue(const char *hostname, /* I - Host to connect to */
* Send the print file...
*/
- if (lpd_command(fd, timeout, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
+ if (lpd_command(fd, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
CUPS_LLCAST filestats.st_size, (int)getpid() % 1000,
localhost))
{
@@ -1084,17 +1073,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */
* want to requeue it over and over...
*/
- alarm(timeout);
-
if (recv(fd, &status, 1, 0) < 1)
{
_cupsLangPrintFilter(stderr, "WARNING",
- _("Printer did not respond after %d seconds."),
- timeout);
+ _("Printer did not respond."));
status = 0;
}
-
- alarm(0);
}
}
else
@@ -1121,7 +1105,7 @@ lpd_queue(const char *hostname, /* I - Host to connect to */
* Send control file...
*/
- if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
+ if (lpd_command(fd, "\002%d cfA%03.3d%.15s\n", strlen(control),
(int)getpid() % 1000, localhost))
{
close(fd);
@@ -1139,17 +1123,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */
}
else
{
- alarm(timeout);
-
if (read(fd, &status, 1) < 1)
{
_cupsLangPrintFilter(stderr, "WARNING",
- _("Printer did not respond after %d seconds."),
- timeout);
+ _("Printer did not respond."));
status = errno;
}
-
- alarm(0);
}
if (status != 0)
@@ -1193,21 +1172,6 @@ lpd_queue(const char *hostname, /* I - Host to connect to */
/*
- * 'lpd_timeout()' - Handle timeout alarms...
- */
-
-static void
-lpd_timeout(int sig) /* I - Signal number */
-{
- (void)sig;
-
-#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
- signal(SIGALRM, lpd_timeout);
-#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
-}
-
-
-/*
* 'lpd_write()' - Write a buffer of data to an LPD server.
*/
@@ -1338,5 +1302,5 @@ sigterm_handler(int sig) /* I - Signal */
/*
- * End of "$Id: lpd.c 9793 2011-05-20 03:49:49Z mike $".
+ * End of "$Id: lpd.c 10265 2012-02-12 07:20:10Z mike $".
*/
diff --git a/backend/runloop.c b/backend/runloop.c
index 21cf45df..6cb41783 100644
--- a/backend/runloop.c
+++ b/backend/runloop.c
@@ -1,9 +1,9 @@
/*
- * "$Id: runloop.c 9820 2011-06-10 22:06:26Z mike $"
+ * "$Id: runloop.c 10369 2012-03-21 04:31:19Z mike $"
*
* Common run loop APIs for CUPS backends.
*
- * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2007-2012 by Apple Inc.
* Copyright 2006-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
@@ -434,9 +434,11 @@ backendWaitLoop(
int use_bc, /* I - Use back-channel? */
_cups_sccb_t side_cb) /* I - Side-channel callback */
{
- fd_set input; /* Input set for reading */
- time_t curtime, /* Current time */
- snmp_update = 0; /* Last SNMP status update */
+ int nfds; /* Number of file descriptors */
+ fd_set input; /* Input set for reading */
+ time_t curtime, /* Current time */
+ snmp_update = 0;/* Last SNMP status update */
+ struct timeval timeout; /* Timeout for select() */
fprintf(stderr, "DEBUG: backendWaitLoop(snmp_fd=%d, addr=%p, side_cb=%p)\n",
@@ -446,6 +448,9 @@ backendWaitLoop(
* Now loop until we receive data from stdin...
*/
+ if (snmp_fd >= 0)
+ snmp_update = time(NULL) + 5;
+
for (;;)
{
/*
@@ -457,7 +462,18 @@ backendWaitLoop(
if (side_cb)
FD_SET(CUPS_SC_FD, &input);
- if (select(CUPS_SC_FD + 1, &input, NULL, NULL, NULL) < 0)
+ if (snmp_fd >= 0)
+ {
+ curtime = time(NULL);
+ timeout.tv_sec = curtime >= snmp_update ? 0 : snmp_update - curtime;
+ timeout.tv_usec = 0;
+
+ nfds = select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout);
+ }
+ else
+ nfds = select(CUPS_SC_FD + 1, &input, NULL, NULL, NULL);
+
+ if (nfds < 0)
{
/*
* Pause printing to clear any pending errors...
@@ -501,10 +517,10 @@ backendWaitLoop(
* Do SNMP updates periodically...
*/
- if (snmp_fd >= 0 && time(&curtime) >= snmp_update)
+ if (snmp_fd >= 0 && curtime >= snmp_update)
{
if (backendSNMPSupplies(snmp_fd, addr, NULL, NULL))
- snmp_update = INT_MAX;
+ snmp_fd = -1;
else
snmp_update = curtime + 5;
}
@@ -519,5 +535,5 @@ backendWaitLoop(
/*
- * End of "$Id: runloop.c 9820 2011-06-10 22:06:26Z mike $".
+ * End of "$Id: runloop.c 10369 2012-03-21 04:31:19Z mike $".
*/
diff --git a/backend/snmp-supplies.c b/backend/snmp-supplies.c
index 6d6bae8a..dc2b3f1a 100644
--- a/backend/snmp-supplies.c
+++ b/backend/snmp-supplies.c
@@ -1,9 +1,9 @@
/*
- * "$Id: snmp-supplies.c 10064 2011-10-07 21:41:07Z mike $"
+ * "$Id: snmp-supplies.c 10262 2012-02-12 05:48:09Z mike $"
*
* SNMP supplies functions for CUPS.
*
- * Copyright 2008-2011 by Apple Inc.
+ * Copyright 2008-2012 by Apple Inc.
*
* These coded instructions, statements, and computer programs are the
* property of Apple Inc. and are protected by Federal copyright
@@ -408,7 +408,7 @@ backend_init_supplies(
cachefilename[1024], /* Cache filename */
description[CUPS_SNMP_MAX_STRING],
/* Device description string */
- value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 2 + 3)],
+ value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 4 + 3)],
/* Value string */
*ptr, /* Pointer into value string */
*name_ptr; /* Pointer into name string */
@@ -659,7 +659,8 @@ backend_init_supplies(
fprintf(stderr, "ATTR: marker-colors=%s\n", value);
/*
- * Output the marker-names attribute...
+ * Output the marker-names attribute (the double quoting is necessary to deal
+ * with embedded quotes and commas in the marker names...)
*/
for (i = 0, ptr = value; i < num_supplies; i ++)
@@ -667,15 +668,21 @@ backend_init_supplies(
if (i)
*ptr++ = ',';
+ *ptr++ = '\'';
*ptr++ = '\"';
for (name_ptr = supplies[i].name; *name_ptr;)
{
- if (*name_ptr == '\\' || *name_ptr == '\"')
+ if (*name_ptr == '\\' || *name_ptr == '\"' || *name_ptr == '\'')
+ {
+ *ptr++ = '\\';
+ *ptr++ = '\\';
*ptr++ = '\\';
+ }
*ptr++ = *name_ptr++;
}
*ptr++ = '\"';
+ *ptr++ = '\'';
}
*ptr = '\0';
@@ -712,16 +719,33 @@ backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */
void *data) /* I - User data (unused) */
{
int i, j, k; /* Looping vars */
- static const char * const colors[8][2] =
+ static const char * const colors[][2] =
{ /* Standard color names */
- { "black", "#000000" },
- { "blue", "#0000FF" },
- { "cyan", "#00FFFF" },
- { "green", "#00FF00" },
- { "magenta", "#FF00FF" },
- { "red", "#FF0000" },
- { "white", "#FFFFFF" },
- { "yellow", "#FFFF00" }
+ { "black", "#000000" },
+ { "blue", "#0000FF" },
+ { "brown", "#A52A2A" },
+ { "cyan", "#00FFFF" },
+ { "dark-gray", "#404040" },
+ { "dark gray", "#404040" },
+ { "dark-yellow", "#FFCC00" },
+ { "dark yellow", "#FFCC00" },
+ { "gold", "#FFD700" },
+ { "gray", "#808080" },
+ { "green", "#00FF00" },
+ { "light-black", "#606060" },
+ { "light black", "#606060" },
+ { "light-cyan", "#E0FFFF" },
+ { "light cyan", "#E0FFFF" },
+ { "light-gray", "#D3D3D3" },
+ { "light gray", "#D3D3D3" },
+ { "light-magenta", "#FF77FF" },
+ { "light magenta", "#FF77FF" },
+ { "magenta", "#FF00FF" },
+ { "orange", "#FFA500" },
+ { "red", "#FF0000" },
+ { "silver", "#C0C0C0" },
+ { "white", "#FFFFFF" },
+ { "yellow", "#FFFF00" }
};
@@ -743,7 +767,8 @@ backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */
if (supplies[j].colorant == i)
{
for (k = 0; k < (int)(sizeof(colors) / sizeof(colors[0])); k ++)
- if (!strcmp(colors[k][0], (char *)packet->object_value.string.bytes))
+ if (!_cups_strcasecmp(colors[k][0],
+ (char *)packet->object_value.string.bytes))
{
strcpy(supplies[j].color, colors[k][1]);
break;
@@ -834,7 +859,6 @@ backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */
{
char *src, *dst; /* Pointers into strings */
-
/*
* Loop safe because both the object_value and supplies char arrays
* are CUPS_SNMP_MAX_STRING elements long.
@@ -982,5 +1006,5 @@ utf16_to_utf8(
/*
- * End of "$Id: snmp-supplies.c 10064 2011-10-07 21:41:07Z mike $".
+ * End of "$Id: snmp-supplies.c 10262 2012-02-12 05:48:09Z mike $".
*/
diff --git a/backend/usb-libusb.c b/backend/usb-libusb.c
index 7f23ed83..e3a02be9 100644
--- a/backend/usb-libusb.c
+++ b/backend/usb-libusb.c
@@ -1,7 +1,7 @@
/*
- * "$Id: usb-libusb.c 10198 2012-01-27 16:48:43Z mike $"
+ * "$Id: usb-libusb.c 10267 2012-02-12 08:35:28Z mike $"
*
- * Libusb interface code for CUPS.
+ * LIBUSB interface code for CUPS.
*
* Copyright 2007-2012 by Apple Inc.
*
@@ -13,25 +13,43 @@
*
* Contents:
*
- * list_devices() - List the available printers.
- * print_device() - Print a file to a USB device.
- * close_device() - Close the connection to the USB printer.
- * find_device() - Find or enumerate USB printers.
- * get_device_id() - Get the IEEE-1284 device ID for the printer.
- * list_cb() - List USB printers for discovery.
- * make_device_uri() - Create a device URI for a USB printer.
- * open_device() - Open a connection to the USB printer.
- * print_cb() - Find a USB printer for printing.
- * side_cb() - Handle side-channel requests.
+ * list_devices() - List the available printers.
+ * print_device() - Print a file to a USB device.
+ * close_device() - Close the connection to the USB printer.
+ * find_device() - Find or enumerate USB printers.
+ * get_device_id() - Get the IEEE-1284 device ID for the printer.
+ * list_cb() - List USB printers for discovery.
+ * make_device_uri() - Create a device URI for a USB printer.
+ * open_device() - Open a connection to the USB printer.
+ * print_cb() - Find a USB printer for printing.
+ * read_thread() - Thread to read the backchannel data on.
+ * sidechannel_thread() - Handle side-channel requests.
+ * soft_reset() - Send a soft reset to the device.
*/
/*
* Include necessary headers...
*/
-#include <usb.h>
-#include <poll.h>
+#include <libusb.h>
#include <cups/cups-private.h>
+#include <pthread.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+
+/*
+ * WAIT_EOF_DELAY is number of seconds we'll wait for responses from
+ * the printer after we've finished sending all the data
+ */
+
+#define WAIT_EOF 0
+#define WAIT_EOF_DELAY 7
+#define WAIT_SIDE_DELAY 3
+#define DEFAULT_TIMEOUT 5000L
/*
@@ -40,18 +58,55 @@
typedef struct usb_printer_s /**** USB Printer Data ****/
{
- struct usb_device *device; /* Device info */
+ struct libusb_device *device; /* Device info */
int conf, /* Configuration */
iface, /* Interface */
altset, /* Alternate setting */
write_endp, /* Write endpoint */
- read_endp; /* Read endpoint */
- struct usb_dev_handle *handle; /* Open handle to device */
+ read_endp, /* Read endpoint */
+ protocol, /* Protocol: 1 = Uni-di, 2 = Bi-di. */
+ usblp_attached; /* Is the "usblp" kernel module
+ attached? */
+ struct libusb_device_handle *handle; /* Open handle to device */
} usb_printer_t;
typedef int (*usb_cb_t)(usb_printer_t *, const char *, const char *,
const void *);
+typedef struct usb_globals_s
+{
+ usb_printer_t *printer; /* Printer */
+
+ pthread_mutex_t read_thread_mutex;
+ pthread_cond_t read_thread_cond;
+ int read_thread_stop;
+ int read_thread_done;
+
+ pthread_mutex_t readwrite_lock_mutex;
+ pthread_cond_t readwrite_lock_cond;
+ int readwrite_lock;
+
+ int print_fd; /* File descriptor to print */
+ ssize_t print_bytes; /* Print bytes read */
+
+ int wait_eof;
+ int drain_output; /* Drain all pending output */
+ int bidi_flag; /* 0=unidirectional, 1=bidirectional */
+
+ pthread_mutex_t sidechannel_thread_mutex;
+ pthread_cond_t sidechannel_thread_cond;
+ int sidechannel_thread_stop;
+ int sidechannel_thread_done;
+} usb_globals_t;
+
+
+/*
+ * Globals...
+ */
+
+usb_globals_t g = { 0 }; /* Globals */
+libusb_device **list; /* List of connected USB devices */
+
/*
* Local functions...
@@ -69,7 +124,9 @@ static char *make_device_uri(usb_printer_t *printer,
static int open_device(usb_printer_t *printer, int verbose);
static int print_cb(usb_printer_t *printer, const char *device_uri,
const char *device_id, const void *data);
-static ssize_t side_cb(usb_printer_t *printer, int print_fd);
+static void *read_thread(void *reference);
+static void *sidechannel_thread(void *reference);
+static void soft_reset(void);
/*
@@ -98,27 +155,46 @@ print_device(const char *uri, /* I - Device URI */
int argc, /* I - Number of command-line arguments (6 or 7) */
char *argv[]) /* I - Command-line arguments */
{
- usb_printer_t *printer; /* Printer */
- ssize_t bytes, /* Bytes read/written */
- tbytes; /* Total bytes written */
- char buffer[512]; /* Print data buffer */
+ int bytes; /* Bytes written */
+ ssize_t total_bytes; /* Total bytes written */
struct sigaction action; /* Actions for POSIX signals */
- struct pollfd pfds[2]; /* Poll descriptors */
+ int status = CUPS_BACKEND_OK,
+ /* Function results */
+ iostatus; /* Current IO status */
+ pthread_t read_thread_id, /* Read thread */
+ sidechannel_thread_id; /* Side-channel thread */
+ int have_sidechannel = 0; /* Was the side-channel thread started? */
+ struct stat sidechannel_info; /* Side-channel file descriptor info */
+ unsigned char print_buffer[8192], /* Print data buffer */
+ *print_ptr; /* Pointer into print data buffer */
+ fd_set input_set; /* Input set for select() */
+ int nfds; /* Number of file descriptors */
+ struct timeval *timeout, /* Timeout pointer */
+ tv; /* Time value */
+ struct timespec cond_timeout; /* pthread condition timeout */
+
+
+ /*
+ * See if the side-channel descriptor is valid...
+ */
+ have_sidechannel = !fstat(CUPS_SC_FD, &sidechannel_info) &&
+ S_ISSOCK(sidechannel_info.st_mode);
- fputs("DEBUG: print_device\n", stderr);
+ g.wait_eof = WAIT_EOF;
/*
* Connect to the printer...
*/
- while ((printer = find_device(print_cb, uri)) == NULL)
+ while ((g.printer = find_device(print_cb, uri)) == NULL)
{
_cupsLangPrintFilter(stderr, "INFO",
_("Waiting for printer to become available."));
sleep(5);
}
+ g.print_fd = print_fd;
/*
* If we are printing data from a print driver on stdin, ignore SIGTERM
@@ -136,74 +212,371 @@ print_device(const char *uri, /* I - Device URI */
sigaction(SIGTERM, &action, NULL);
}
- tbytes = 0;
+ /*
+ * Start the side channel thread if the descriptor is valid...
+ */
- pfds[0].fd = print_fd;
- pfds[0].events = POLLIN;
- pfds[1].fd = CUPS_SC_FD;
- pfds[1].events = POLLIN;
+ pthread_mutex_init(&g.readwrite_lock_mutex, NULL);
+ pthread_cond_init(&g.readwrite_lock_cond, NULL);
+ g.readwrite_lock = 1;
- while (copies > 0 && tbytes >= 0)
+ if (have_sidechannel)
{
- copies --;
+ g.sidechannel_thread_stop = 0;
+ g.sidechannel_thread_done = 0;
+
+ pthread_cond_init(&g.sidechannel_thread_cond, NULL);
+ pthread_mutex_init(&g.sidechannel_thread_mutex, NULL);
- if (print_fd != 0)
+ if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL))
+ {
+ fprintf(stderr, "DEBUG: Fatal USB error.\n");
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("There was an unrecoverable USB error."));
+ fputs("DEBUG: Couldn't create side-channel thread.\n", stderr);
+ close_device(g.printer);
+ return (CUPS_BACKEND_STOP);
+ }
+ }
+
+ /*
+ * Get the read thread going...
+ */
+
+ g.read_thread_stop = 0;
+ g.read_thread_done = 0;
+
+ pthread_cond_init(&g.read_thread_cond, NULL);
+ pthread_mutex_init(&g.read_thread_mutex, NULL);
+
+ if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
+ {
+ fprintf(stderr, "DEBUG: Fatal USB error.\n");
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("There was an unrecoverable USB error."));
+ fputs("DEBUG: Couldn't create read thread.\n", stderr);
+ close_device(g.printer);
+ return (CUPS_BACKEND_STOP);
+ }
+
+ /*
+ * The main thread sends the print file...
+ */
+
+ g.drain_output = 0;
+ g.print_bytes = 0;
+ total_bytes = 0;
+ print_ptr = print_buffer;
+
+ while (status == CUPS_BACKEND_OK && copies-- > 0)
+ {
+ _cupsLangPrintFilter(stderr, "INFO", _("Sending data to printer."));
+
+ if (print_fd != STDIN_FILENO)
{
fputs("PAGE: 1 1\n", stderr);
lseek(print_fd, 0, SEEK_SET);
}
- /*
- * TODO: Add back-channel support, along with better write error handling.
- */
-
- while (poll(pfds, 2, -1) > 0)
+ while (status == CUPS_BACKEND_OK)
{
+ FD_ZERO(&input_set);
+
+ if (!g.print_bytes)
+ FD_SET(print_fd, &input_set);
+
+ /*
+ * Calculate select timeout...
+ * If we have data waiting to send timeout is 100ms.
+ * else if we're draining print_fd timeout is 0.
+ * else we're waiting forever...
+ */
+
+ if (g.print_bytes)
+ {
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000; /* 100ms */
+ timeout = &tv;
+ }
+ else if (g.drain_output)
+ {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ timeout = &tv;
+ }
+ else
+ timeout = NULL;
+
+ /*
+ * I/O is unlocked around select...
+ */
+
+ pthread_mutex_lock(&g.readwrite_lock_mutex);
+ g.readwrite_lock = 0;
+ pthread_cond_signal(&g.readwrite_lock_cond);
+ pthread_mutex_unlock(&g.readwrite_lock_mutex);
+
+ nfds = select(print_fd + 1, &input_set, NULL, NULL, timeout);
+
+ /*
+ * Reacquire the lock...
+ */
+
+ pthread_mutex_lock(&g.readwrite_lock_mutex);
+ while (g.readwrite_lock)
+ pthread_cond_wait(&g.readwrite_lock_cond, &g.readwrite_lock_mutex);
+ g.readwrite_lock = 1;
+ pthread_mutex_unlock(&g.readwrite_lock_mutex);
+
+ if (nfds < 0)
+ {
+ if (errno == EINTR && total_bytes == 0)
+ {
+ fputs("DEBUG: Received an interrupt before any bytes were "
+ "written, aborting.\n", stderr);
+ close_device(g.printer);
+ return (CUPS_BACKEND_OK);
+ }
+ else if (errno != EAGAIN && errno != EINTR)
+ {
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to read print data."));
+ perror("DEBUG: select");
+ close_device(g.printer);
+ return (CUPS_BACKEND_FAILED);
+ }
+ }
+
/*
- * CUPS STR #3318: USB process hangs on end-of-file, making further
- * printing impossible
- *
- * From a strict interpretation of POSIX poll(), POLLHUP should never be
- * set without POLLIN, since POLLIN is the event you request. That said,
- * it appears that some versions of Linux break this.
+ * If drain output has finished send a response...
*/
- if (pfds[0].revents & (POLLIN | POLLHUP))
+ if (g.drain_output && !nfds && !g.print_bytes)
{
- if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
+ /* Send a response... */
+ cupsSideChannelWrite(CUPS_SC_CMD_DRAIN_OUTPUT, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
+ g.drain_output = 0;
+ }
+
+ /*
+ * Check if we have print data ready...
+ */
+
+ if (FD_ISSET(print_fd, &input_set))
+ {
+ g.print_bytes = read(print_fd, print_buffer, sizeof(print_buffer));
+
+ if (g.print_bytes < 0)
{
- if (usb_bulk_write(printer->handle, printer->write_endp, buffer,
- bytes, 3600000) < 0)
+ /*
+ * Read error - bail if we don't see EAGAIN or EINTR...
+ */
+
+ if (errno != EAGAIN && errno != EINTR)
{
_cupsLangPrintFilter(stderr, "ERROR",
- _("Unable to send data to printer."));
- tbytes = -1;
- break;
+ _("Unable to read print data."));
+ perror("DEBUG: read");
+ close_device(g.printer);
+ return (CUPS_BACKEND_FAILED);
}
- tbytes += bytes;
+ g.print_bytes = 0;
}
- else if (bytes == 0 || (bytes < 0 && errno != EAGAIN && errno != EINTR))
+ else if (g.print_bytes == 0)
+ {
+ /*
+ * End of file, break out of the loop...
+ */
+
+ break;
+ }
+
+ print_ptr = print_buffer;
+
+ fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
+ (int)g.print_bytes);
+ }
+
+ if (g.print_bytes)
+ {
+ iostatus = libusb_bulk_transfer(g.printer->handle,
+ g.printer->write_endp,
+ print_buffer, g.print_bytes,
+ &bytes, 60000);
+ /*
+ * Ignore timeout errors, but retain the number of bytes written to
+ * avoid sending duplicate data...
+ */
+
+ if (iostatus == LIBUSB_ERROR_TIMEOUT)
+ {
+ fputs("DEBUG: Got USB transaction timeout during write.\n", stderr);
+ iostatus = 0;
+ }
+
+ /*
+ * If we've stalled, retry the write...
+ */
+
+ else if (iostatus == LIBUSB_ERROR_PIPE)
+ {
+ fputs("DEBUG: Got USB pipe stalled during write.\n", stderr);
+
+ iostatus = libusb_bulk_transfer(g.printer->handle,
+ g.printer->write_endp,
+ print_buffer, g.print_bytes,
+ &bytes, 60000);
+ }
+
+ /*
+ * Retry a write after an aborted write since we probably just got
+ * SIGTERM...
+ */
+
+ else if (iostatus == LIBUSB_ERROR_INTERRUPTED)
+ {
+ fputs("DEBUG: Got USB return aborted during write.\n", stderr);
+
+ iostatus = libusb_bulk_transfer(g.printer->handle,
+ g.printer->write_endp,
+ print_buffer, g.print_bytes,
+ &bytes, 60000);
+ }
+
+ if (iostatus)
+ {
+ /*
+ * Write error - bail if we don't see an error we can retry...
+ */
+
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Unable to send data to printer."));
+ fprintf(stderr, "DEBUG: libusb write operation returned %x.\n",
+ iostatus);
+
+ status = CUPS_BACKEND_FAILED;
+ break;
+ }
+ else if (bytes > 0)
+ {
+ fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n",
+ (int)bytes);
+
+ g.print_bytes -= bytes;
+ print_ptr += bytes;
+ total_bytes += bytes;
+ }
+ }
+
+ if (print_fd != 0 && status == CUPS_BACKEND_OK)
+ fprintf(stderr, "DEBUG: Sending print file, " CUPS_LLFMT " bytes...\n",
+ CUPS_LLCAST total_bytes);
+ }
+ }
+
+ fprintf(stderr, "DEBUG: Sent " CUPS_LLFMT " bytes...\n",
+ CUPS_LLCAST total_bytes);
+
+ /*
+ * Signal the side channel thread to exit...
+ */
+
+ if (have_sidechannel)
+ {
+ close(CUPS_SC_FD);
+ pthread_mutex_lock(&g.readwrite_lock_mutex);
+ g.readwrite_lock = 0;
+ pthread_cond_signal(&g.readwrite_lock_cond);
+ pthread_mutex_unlock(&g.readwrite_lock_mutex);
+
+ g.sidechannel_thread_stop = 1;
+ pthread_mutex_lock(&g.sidechannel_thread_mutex);
+
+ if (!g.sidechannel_thread_done)
+ {
+ gettimeofday(&tv, NULL);
+ cond_timeout.tv_sec = tv.tv_sec + WAIT_SIDE_DELAY;
+ cond_timeout.tv_nsec = tv.tv_usec * 1000;
+
+ while (!g.sidechannel_thread_done)
+ {
+ if (pthread_cond_timedwait(&g.sidechannel_thread_cond,
+ &g.sidechannel_thread_mutex,
+ &cond_timeout) != 0)
break;
}
+ }
+
+ pthread_mutex_unlock(&g.sidechannel_thread_mutex);
+ }
+
+ /*
+ * Signal the read thread to exit then wait 7 seconds for it to complete...
+ */
+
+ g.read_thread_stop = 1;
+
+ pthread_mutex_lock(&g.read_thread_mutex);
+
+ if (!g.read_thread_done)
+ {
+ fputs("DEBUG: Waiting for read thread to exit...\n", stderr);
+
+ gettimeofday(&tv, NULL);
+ cond_timeout.tv_sec = tv.tv_sec + WAIT_EOF_DELAY;
+ cond_timeout.tv_nsec = tv.tv_usec * 1000;
+
+ while (!g.read_thread_done)
+ {
+ if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
+ &cond_timeout) != 0)
+ break;
+ }
+
+ /*
+ * If it didn't exit abort the pending read and wait an additional second...
+ */
+
+ if (!g.read_thread_done)
+ {
+ fputs("DEBUG: Read thread still active, aborting the pending read...\n",
+ stderr);
- if (pfds[1].revents & (POLLIN | POLLHUP))
+ g.wait_eof = 0;
+
+ gettimeofday(&tv, NULL);
+ cond_timeout.tv_sec = tv.tv_sec + 1;
+ cond_timeout.tv_nsec = tv.tv_usec * 1000;
+
+ while (!g.read_thread_done)
{
- if ((bytes = side_cb(printer, print_fd)) < 0)
- pfds[1].events = 0; /* Filter has gone away... */
- else
- tbytes += bytes;
+ if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
+ &cond_timeout) != 0)
+ break;
}
}
}
+ pthread_mutex_unlock(&g.read_thread_mutex);
+
+ if (print_fd)
+ close(print_fd);
+
/*
- * Close our connection and return...
+ * Close the connection and input file and general clean up...
*/
- close_device(printer);
+ close_device(g.printer);
- return (CUPS_BACKEND_OK);
+ /*
+ * Clean up ....
+ */
+
+ libusb_free_device_list(list, 1);
+ libusb_exit(NULL);
+
+ return (status);
}
@@ -214,6 +587,12 @@ print_device(const char *uri, /* I - Device URI */
static int /* I - 0 on success, -1 on failure */
close_device(usb_printer_t *printer) /* I - Printer */
{
+ struct libusb_device_descriptor devdesc;
+ /* Current device descriptor */
+ struct libusb_config_descriptor *confptr;
+ /* Pointer to current configuration */
+
+
if (printer->handle)
{
/*
@@ -221,19 +600,36 @@ close_device(usb_printer_t *printer) /* I - Printer */
* to the device...
*/
- int number = printer->device->config[printer->conf].
- interface[printer->iface].
- altsetting[printer->altset].bInterfaceNumber;
- usb_release_interface(printer->handle, number);
+ int number; /* Interface number */
+ libusb_get_device_descriptor (printer->device, &devdesc);
+ libusb_get_config_descriptor (printer->device, printer->conf, &confptr);
+ number = confptr->interface[printer->iface].
+ altsetting[printer->altset].bInterfaceNumber;
+ libusb_release_interface(printer->handle, number);
if (number != 0)
- usb_release_interface(printer->handle, 0);
+ libusb_release_interface(printer->handle, 0);
+
+ /*
+ * Re-attach "usblp" kernel module if it was attached before using this
+ * device
+ */
+
+ if (printer->usblp_attached == 1)
+ {
+ if (libusb_attach_kernel_driver(printer->handle, printer->iface) < 0)
+ fprintf(stderr,
+ "DEBUG: Failed to re-attach \"usblp\" kernel module to "
+ "%04x:%04x\n", devdesc.idVendor, devdesc.idProduct);
+ }
+
+ libusb_free_config_descriptor(confptr);
/*
* Close the interface and return...
*/
- usb_close(printer->handle);
+ libusb_close(printer->handle);
printer->handle = NULL;
}
@@ -249,15 +645,21 @@ static usb_printer_t * /* O - Found printer */
find_device(usb_cb_t cb, /* I - Callback function */
const void *data) /* I - User data for callback */
{
- struct usb_bus *bus; /* Current bus */
- struct usb_device *device; /* Current device */
- struct usb_config_descriptor *confptr;/* Pointer to current configuration */
- struct usb_interface *ifaceptr; /* Pointer to current interface */
- struct usb_interface_descriptor *altptr;
+ libusb_device **list; /* List of connected USB devices */
+ libusb_device *device = NULL; /* Current device */
+ struct libusb_device_descriptor devdesc;
+ /* Current device descriptor */
+ struct libusb_config_descriptor *confptr = NULL;
+ /* Pointer to current configuration */
+ const struct libusb_interface *ifaceptr = NULL;
+ /* Pointer to current interface */
+ const struct libusb_interface_descriptor *altptr = NULL;
/* Pointer to current alternate setting */
- struct usb_endpoint_descriptor *endpptr;
+ const struct libusb_endpoint_descriptor *endpptr = NULL;
/* Pointer to current endpoint */
- int conf, /* Current configuration */
+ ssize_t numdevs, /* number of connected devices */
+ i = 0;
+ uint8_t conf, /* Current configuration */
iface, /* Current interface */
altset, /* Current alternate setting */
protocol, /* Current protocol */
@@ -274,29 +676,34 @@ find_device(usb_cb_t cb, /* I - Callback function */
* Initialize libusb...
*/
- usb_init();
- fprintf(stderr, "DEBUG: usb_find_busses=%d\n", usb_find_busses());
- fprintf(stderr, "DEBUG: usb_find_devices=%d\n", usb_find_devices());
+ libusb_init(NULL);
+ numdevs = libusb_get_device_list(NULL, &list);
+ fprintf(stderr, "DEBUG: libusb_get_device_list=%d\n", (int)numdevs);
/*
* Then loop through the devices it found...
*/
- for (bus = usb_get_busses(); bus; bus = bus->next)
- for (device = bus->devices; device; device = device->next)
+ if (numdevs > 0)
+ for (i = 0; i < numdevs; i++)
{
+ device = list[i];
+
/*
* Ignore devices with no configuration data and anything that is not
* a printer...
*/
- if (!device->config || !device->descriptor.idVendor ||
- !device->descriptor.idProduct)
+ libusb_get_device_descriptor (device, &devdesc);
+
+ if (!devdesc.bNumConfigurations || !devdesc.idVendor ||
+ !devdesc.idProduct)
continue;
- for (conf = 0, confptr = device->config;
- conf < device->descriptor.bNumConfigurations;
- conf ++, confptr ++)
+ for (conf = 0; conf < devdesc.bNumConfigurations; conf ++)
+ {
+ if (libusb_get_config_descriptor (device, conf, &confptr) < 0)
+ continue;
for (iface = 0, ifaceptr = confptr->interface;
iface < confptr->bNumInterfaces;
iface ++, ifaceptr ++)
@@ -317,7 +724,7 @@ find_device(usb_cb_t cb, /* I - Callback function */
* 1284.4 (packet mode) protocol as well.
*/
- if (altptr->bInterfaceClass != USB_CLASS_PRINTER ||
+ if (altptr->bInterfaceClass != LIBUSB_CLASS_PRINTER ||
altptr->bInterfaceSubClass != 1 ||
(altptr->bInterfaceProtocol != 1 && /* Unidirectional */
altptr->bInterfaceProtocol != 2) || /* Bidirectional */
@@ -330,10 +737,10 @@ find_device(usb_cb_t cb, /* I - Callback function */
for (endp = 0, endpptr = altptr->endpoint;
endp < altptr->bNumEndpoints;
endp ++, endpptr ++)
- if ((endpptr->bmAttributes & USB_ENDPOINT_TYPE_MASK) ==
- USB_ENDPOINT_TYPE_BULK)
+ if ((endpptr->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) ==
+ LIBUSB_TRANSFER_TYPE_BULK)
{
- if (endpptr->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ if (endpptr->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
read_endp = endp;
else
write_endp = endp;
@@ -354,38 +761,37 @@ find_device(usb_cb_t cb, /* I - Callback function */
if (protocol > 0)
{
- printer.device = device;
- printer.conf = conf;
- printer.iface = iface;
- printer.handle = NULL;
+ printer.device = device;
+ printer.conf = conf;
+ printer.iface = iface;
+ printer.protocol = protocol;
+ printer.handle = NULL;
if (!open_device(&printer, data != NULL))
{
- if (!get_device_id(&printer, device_id, sizeof(device_id)))
- {
- make_device_uri(&printer, device_id, device_uri,
- sizeof(device_uri));
+ get_device_id(&printer, device_id, sizeof(device_id));
+ make_device_uri(&printer, device_id, device_uri,
+ sizeof(device_uri));
- if ((*cb)(&printer, device_uri, device_id, data))
- {
- printer.read_endp = printer.device->config[printer.conf].
- interface[printer.iface].
+ if ((*cb)(&printer, device_uri, device_id, data))
+ {
+ printer.read_endp = confptr->interface[printer.iface].
altsetting[printer.altset].
endpoint[printer.read_endp].
bEndpointAddress;
- printer.write_endp = printer.device->config[printer.conf].
- interface[printer.iface].
+ printer.write_endp = confptr->interface[printer.iface].
altsetting[printer.altset].
endpoint[printer.write_endp].
bEndpointAddress;
- return (&printer);
- }
+ return (&printer);
}
close_device(&printer);
}
}
}
+ libusb_free_config_descriptor(confptr);
+ }
}
/*
@@ -393,6 +799,13 @@ find_device(usb_cb_t cb, /* I - Callback function */
* to print to...
*/
+ /*
+ * Clean up ....
+ */
+
+ libusb_free_device_list(list, 1);
+ libusb_exit(NULL);
+
return (NULL);
}
@@ -409,10 +822,12 @@ get_device_id(usb_printer_t *printer, /* I - Printer */
int length; /* Length of device ID */
- if (usb_control_msg(printer->handle,
- USB_TYPE_CLASS | USB_ENDPOINT_IN | USB_RECIP_INTERFACE,
- 0, printer->conf, (printer->iface << 8) | printer->altset,
- buffer, bufsize, 5000) < 0)
+ if (libusb_control_transfer(printer->handle,
+ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_ENDPOINT_IN |
+ LIBUSB_RECIPIENT_INTERFACE,
+ 0, printer->conf,
+ (printer->iface << 8) | printer->altset,
+ (unsigned char *)buffer, bufsize, 5000) < 0)
{
*buffer = '\0';
return (-1);
@@ -482,7 +897,8 @@ list_cb(usb_printer_t *printer, /* I - Printer */
* Get the device URI and make/model strings...
*/
- backendGetMakeModel(device_id, make_model, sizeof(make_model));
+ if (backendGetMakeModel(device_id, make_model, sizeof(make_model)))
+ strlcpy(make_model, "Unknown", sizeof(make_model));
/*
* Report the printer...
@@ -510,12 +926,14 @@ make_device_uri(
char *uri, /* I - Device URI buffer */
size_t uri_size) /* I - Size of device URI buffer */
{
+ struct libusb_device_descriptor devdesc;
+ /* Current device descriptor */
char options[1024]; /* Device URI options */
int num_values; /* Number of 1284 parameters */
cups_option_t *values; /* 1284 parameters */
const char *mfg, /* Manufacturer */
*mdl, /* Model */
- *des, /* Description */
+ *des = NULL, /* Description */
*sern; /* Serial number */
size_t mfglen; /* Length of manufacturer string */
char tempmfg[256], /* Temporary manufacturer string */
@@ -532,16 +950,18 @@ make_device_uri(
if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL)
if ((sern = cupsGetOption("SERN", num_values, values)) == NULL)
if ((sern = cupsGetOption("SN", num_values, values)) == NULL &&
- printer->device->descriptor.iSerialNumber)
+ ((libusb_get_device_descriptor (printer->device, &devdesc) >= 0) &&
+ devdesc.iSerialNumber))
{
/*
* Try getting the serial number from the device itself...
*/
- int length = usb_get_string_simple(printer->handle,
- printer->device->descriptor.
- iSerialNumber,
- tempsern, sizeof(tempsern) - 1);
+ int length =
+ libusb_get_string_descriptor_ascii(printer->handle,
+ devdesc.iSerialNumber,
+ (unsigned char *)tempsern,
+ sizeof(tempsern) - 1);
if (length > 0)
{
tempsern[length] = '\0';
@@ -555,15 +975,6 @@ make_device_uri(
if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL)
mdl = cupsGetOption("MDL", num_values, values);
-#ifdef __APPLE__
- /*
- * To maintain compatibility with the original IOKit-based backend on Mac OS X,
- * don't map manufacturer names...
- */
-
- if (!mfg)
-
-#else
/*
* To maintain compatibility with the original character device backend on
* Linux and *BSD, map manufacturer names...
@@ -577,7 +988,6 @@ make_device_uri(
mfg = "Lexmark";
}
else
-#endif /* __APPLE__ */
{
/*
* No manufacturer? Use the model string or description...
@@ -597,6 +1007,19 @@ make_device_uri(
mfg = tempmfg;
}
+ if (!mdl)
+ {
+ /*
+ * No model? Use description...
+ */
+ if (des)
+ mdl = des; /* We remove the manufacturer name below */
+ else if (!strncasecmp(mfg, "Unknown", 7))
+ mdl = "Printer";
+ else
+ mdl = "Unknown Model";
+ }
+
mfglen = strlen(mfg);
if (!strncasecmp(mdl, mfg, mfglen) && _cups_isspace(mdl[mfglen]))
@@ -642,7 +1065,13 @@ static int /* O - 0 on success, -1 on error */
open_device(usb_printer_t *printer, /* I - Printer */
int verbose) /* I - Update connecting-to-device state? */
{
- int number; /* Configuration/interface/altset numbers */
+ struct libusb_device_descriptor devdesc;
+ /* Current device descriptor */
+ struct libusb_config_descriptor *confptr = NULL;
+ /* Pointer to current configuration */
+ int number1 = -1, /* Configuration/interface/altset */
+ number2 = -1, /* numbers */
+ errcode = 0;
char current; /* Current configuration */
@@ -657,7 +1086,7 @@ open_device(usb_printer_t *printer, /* I - Printer */
* Try opening the printer...
*/
- if ((printer->handle = usb_open(printer->device)) == NULL)
+ if (libusb_open(printer->device, &printer->handle) < 0)
return (-1);
if (verbose)
@@ -665,20 +1094,25 @@ open_device(usb_printer_t *printer, /* I - Printer */
/*
* Set the desired configuration, but only if it needs changing. Some
- * printers (e.g., Samsung) don't like usb_set_configuration. It will succeed,
- * but the following print job is sometimes silently lost by the printer.
+ * printers (e.g., Samsung) don't like libusb_set_configuration. It will
+ * succeed, but the following print job is sometimes silently lost by the
+ * printer.
*/
- if (usb_control_msg(printer->handle,
- USB_TYPE_STANDARD | USB_ENDPOINT_IN | USB_RECIP_DEVICE,
- 8, /* GET_CONFIGURATION */
- 0, 0, &current, 1, 5000) != 1)
+ if (libusb_control_transfer(printer->handle,
+ LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_ENDPOINT_IN |
+ LIBUSB_RECIPIENT_DEVICE,
+ 8, /* GET_CONFIGURATION */
+ 0, 0, (unsigned char *)&current, 1, 5000) < 0)
current = 0; /* Assume not configured */
- number = printer->device->config[printer->conf].bConfigurationValue;
- if (number != current)
+ libusb_get_device_descriptor (printer->device, &devdesc);
+ libusb_get_config_descriptor (printer->device, printer->conf, &confptr);
+ number1 = confptr->bConfigurationValue;
+
+ if (number1 != current)
{
- if (usb_set_configuration(printer->handle, number) < 0)
+ if ((errcode = libusb_set_configuration(printer->handle, number1)) < 0)
{
/*
* If the set fails, chances are that the printer only supports a
@@ -686,26 +1120,52 @@ open_device(usb_printer_t *printer, /* I - Printer */
* the USB printer specification, but otherwise they'll work...
*/
- if (errno != EBUSY)
+ if (errcode != LIBUSB_ERROR_BUSY)
fprintf(stderr, "DEBUG: Failed to set configuration %d for %04x:%04x\n",
- number, printer->device->descriptor.idVendor,
- printer->device->descriptor.idProduct);
+ number1, devdesc.idVendor, devdesc.idProduct);
+ }
+ }
+
+ /*
+ * Get the "usblp" kernel module out of the way. This backend only
+ * works without the module attached.
+ */
+
+ errcode = libusb_kernel_driver_active(printer->handle, printer->iface);
+ if (errcode == 0)
+ printer->usblp_attached = 0;
+ else if (errcode == 1)
+ {
+ printer->usblp_attached = 1;
+ if ((errcode =
+ libusb_detach_kernel_driver(printer->handle, printer->iface)) < 0)
+ {
+ fprintf(stderr, "DEBUG: Failed to detach \"usblp\" module from %04x:%04x\n",
+ devdesc.idVendor, devdesc.idProduct);
+ goto error;
}
}
+ else
+ {
+ printer->usblp_attached = 0;
+ fprintf(stderr, "DEBUG: Failed to check whether %04x:%04x has the \"usblp\" kernel module attached\n",
+ devdesc.idVendor, devdesc.idProduct);
+ goto error;
+ }
/*
* Claim interfaces as needed...
*/
- number = printer->device->config[printer->conf].interface[printer->iface].
- altsetting[printer->altset].bInterfaceNumber;
- while (usb_claim_interface(printer->handle, number) < 0)
+ number1 = confptr->interface[printer->iface].
+ altsetting[printer->altset].bInterfaceNumber;
+
+ while ((errcode = libusb_claim_interface(printer->handle, number1)) < 0)
{
- if (errno != EBUSY)
+ if (errcode != LIBUSB_ERROR_BUSY)
fprintf(stderr,
"DEBUG: Failed to claim interface %d for %04x:%04x: %s\n",
- number, printer->device->descriptor.idVendor,
- printer->device->descriptor.idProduct, strerror(errno));
+ number1, devdesc.idVendor, devdesc.idProduct, strerror(errno));
goto error;
}
@@ -715,24 +1175,29 @@ open_device(usb_printer_t *printer, /* I - Printer */
* printers (e.g., Samsung) don't like usb_set_altinterface.
*/
- if (printer->device->config[printer->conf].interface[printer->iface].
- num_altsetting > 1)
+ if (confptr->interface[printer->iface].num_altsetting > 1)
{
- number = printer->device->config[printer->conf].interface[printer->iface].
+ number1 = confptr->interface[printer->iface].
+ altsetting[printer->altset].bInterfaceNumber;
+ number2 = confptr->interface[printer->iface].
altsetting[printer->altset].bAlternateSetting;
- while (usb_set_altinterface(printer->handle, number) < 0)
+ while ((errcode =
+ libusb_set_interface_alt_setting(printer->handle, number1, number2))
+ < 0)
{
- if (errno != EBUSY)
+ if (errcode != LIBUSB_ERROR_BUSY)
fprintf(stderr,
"DEBUG: Failed to set alternate interface %d for %04x:%04x: "
- "%s\n", number, printer->device->descriptor.idVendor,
- printer->device->descriptor.idProduct, strerror(errno));
+ "%s\n",
+ number2, devdesc.idVendor, devdesc.idProduct, strerror(errno));
goto error;
}
}
+ libusb_free_config_descriptor(confptr);
+
if (verbose)
fputs("STATE: -connecting-to-device\n", stderr);
@@ -747,7 +1212,7 @@ open_device(usb_printer_t *printer, /* I - Printer */
if (verbose)
fputs("STATE: -connecting-to-device\n", stderr);
- usb_close(printer->handle);
+ libusb_close(printer->handle);
printer->handle = NULL;
return (-1);
@@ -849,94 +1314,293 @@ print_cb(usb_printer_t *printer, /* I - Printer */
/*
- * 'side_cb()' - Handle side-channel requests.
+ * 'read_thread()' - Thread to read the backchannel data on.
+ */
+
+static void *read_thread(void *reference)
+{
+ unsigned char readbuffer[512];
+ int rbytes;
+ int readstatus;
+ struct timeval now,
+ delay,
+ end,
+ timeleft;
+
+
+ (void)reference;
+
+ /*
+ * Read frequency: once every 250 milliseconds.
+ */
+
+ delay.tv_sec = 0;
+ delay.tv_usec = 250000;
+
+ do
+ {
+ /*
+ * Remember when we started so we can throttle the loop after the read
+ * call...
+ */
+
+ gettimeofday(&now, NULL);
+
+ /*
+ * Calculate what 250 milliSeconds are in absolute time...
+ */
+
+ timeradd(&now, &delay, &end);
+
+ rbytes = sizeof(readbuffer);
+ readstatus = libusb_bulk_transfer(g.printer->handle,
+ g.printer->read_endp,
+ readbuffer, rbytes,
+ &rbytes, 60000);
+ if (readstatus == LIBUSB_SUCCESS && rbytes > 0)
+ {
+ fprintf(stderr, "DEBUG: Read %d bytes of back-channel data...\n",
+ (int)rbytes);
+ cupsBackChannelWrite((const char *)readbuffer, rbytes, 1.0);
+ }
+ else if (readstatus == LIBUSB_ERROR_TIMEOUT)
+ fputs("DEBUG: Got USB transaction timeout during read.\n", stderr);
+ else if (readstatus == LIBUSB_ERROR_PIPE)
+ fputs("DEBUG: Got USB pipe stalled during read.\n", stderr);
+ else if (readstatus == LIBUSB_ERROR_INTERRUPTED)
+ fputs("DEBUG: Got USB return aborted during read.\n", stderr);
+
+ /*
+ * Make sure this loop executes no more than once every 250 miliseconds...
+ */
+
+ if ((readstatus != LIBUSB_SUCCESS || rbytes == 0) &&
+ (g.wait_eof || !g.read_thread_stop))
+ {
+ gettimeofday(&now, NULL);
+ if (timercmp(&now, &end, <))
+ {
+ timersub(&end, &now, &timeleft);
+ usleep(1000000 * timeleft.tv_sec + timeleft.tv_usec);
+ }
+ }
+ } while (g.wait_eof || !g.read_thread_stop);
+
+ /*
+ * Let the main thread know that we have completed the read thread...
+ */
+
+ pthread_mutex_lock(&g.read_thread_mutex);
+ g.read_thread_done = 1;
+ pthread_cond_signal(&g.read_thread_cond);
+ pthread_mutex_unlock(&g.read_thread_mutex);
+
+ return (NULL);
+}
+
+
+/*
+ * 'sidechannel_thread()' - Handle side-channel requests.
*/
-static ssize_t /* O - Number of bytes written */
-side_cb(usb_printer_t *printer, /* I - Printer */
- int print_fd) /* I - File to print */
+static void*
+sidechannel_thread(void *reference)
{
- ssize_t bytes, /* Bytes read/written */
- tbytes; /* Total bytes written */
- char buffer[512]; /* Print data buffer */
- struct pollfd pfd; /* Poll descriptor */
cups_sc_command_t command; /* Request command */
cups_sc_status_t status; /* Request/response status */
char data[2048]; /* Request/response data */
int datalen; /* Request/response data size */
- tbytes = 0;
- datalen = sizeof(data);
+ (void)reference;
- if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
- return (-1);
-
- switch (command)
+ do
{
- case CUPS_SC_CMD_DRAIN_OUTPUT :
- pfd.fd = print_fd;
- pfd.events = POLLIN;
+ datalen = sizeof(data);
- while (poll(&pfd, 1, 1000) > 0)
- {
- if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
- {
- while (usb_bulk_write(printer->handle, printer->write_endp, buffer,
- bytes, 5000) < 0)
- {
- _cupsLangPrintFilter(stderr, "ERROR",
- _("Unable to send data to printer."));
- tbytes = -1;
- break;
- }
+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
+ {
+ if (status == CUPS_SC_STATUS_TIMEOUT)
+ continue;
+ else
+ break;
+ }
+
+ switch (command)
+ {
+ case CUPS_SC_CMD_SOFT_RESET: /* Do a soft reset */
+ fputs("DEBUG: CUPS_SC_CMD_SOFT_RESET received from driver...\n",
+ stderr);
+
+ soft_reset();
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
+ fputs("DEBUG: Returning status CUPS_STATUS_OK with no bytes...\n",
+ stderr);
+ break;
- tbytes += bytes;
+ case CUPS_SC_CMD_DRAIN_OUTPUT: /* Drain all pending output */
+ fputs("DEBUG: CUPS_SC_CMD_DRAIN_OUTPUT received from driver...\n",
+ stderr);
+
+ g.drain_output = 1;
+ break;
+
+ case CUPS_SC_CMD_GET_BIDI: /* Is the connection bidirectional? */
+ fputs("DEBUG: CUPS_SC_CMD_GET_BIDI received from driver...\n",
+ stderr);
+
+ data[0] = (g.printer->protocol >= 2 ? 1 : 0);
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
+
+ fprintf(stderr,
+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n",
+ data[0]);
+ break;
+
+ case CUPS_SC_CMD_GET_DEVICE_ID: /* Return IEEE-1284 device ID */
+ fputs("DEBUG: CUPS_SC_CMD_GET_DEVICE_ID received from driver...\n",
+ stderr);
+
+ datalen = sizeof(data);
+ if (get_device_id(g.printer, data, sizeof(data)))
+ {
+ status = CUPS_SC_STATUS_IO_ERROR;
+ datalen = 0;
}
- else if (bytes < 0 && errno != EAGAIN && errno != EINTR)
- break;
- }
+ else
+ {
+ status = CUPS_SC_STATUS_OK;
+ datalen = strlen(data);
+ }
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, datalen, 1.0);
- if (tbytes < 0)
- status = CUPS_SC_STATUS_IO_ERROR;
- else
- status = CUPS_SC_STATUS_OK;
+ if (datalen < sizeof(data))
+ data[datalen] = '\0';
+ else
+ data[sizeof(data) - 1] = '\0';
- datalen = 0;
- break;
+ fprintf(stderr,
+ "DEBUG: Returning CUPS_SC_STATUS_OK with %d bytes (%s)...\n",
+ datalen, data);
+ break;
- case CUPS_SC_CMD_GET_BIDI :
- status = CUPS_SC_STATUS_OK;
- data[0] = 0; /* TODO: Change to 1 when read supported */
- datalen = 1;
- break;
+ case CUPS_SC_CMD_GET_STATE: /* Return device state */
+ fputs("DEBUG: CUPS_SC_CMD_GET_STATE received from driver...\n",
+ stderr);
- case CUPS_SC_CMD_GET_DEVICE_ID :
- if (get_device_id(printer, data, sizeof(data)))
- {
- status = CUPS_SC_STATUS_IO_ERROR;
- datalen = 0;
- }
- else
- {
- status = CUPS_SC_STATUS_OK;
- datalen = strlen(data);
- }
- break;
+ data[0] = CUPS_SC_STATE_ONLINE;
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
+
+ fprintf(stderr,
+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n",
+ data[0]);
+ break;
+
+ case CUPS_SC_CMD_GET_CONNECTED: /* Return whether device is
+ connected */
+ fputs("DEBUG: CUPS_SC_CMD_GET_CONNECTED received from driver...\n",
+ stderr);
- default :
- status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
- datalen = 0;
+ data[0] = (g.printer->handle ? 1 : 0);
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
+
+ fprintf(stderr,
+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n",
+ data[0]);
+ break;
+
+ default:
+ fprintf(stderr, "DEBUG: Unknown side-channel command (%d) received "
+ "from driver...\n", command);
+
+ cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED,
+ NULL, 0, 1.0);
+
+ fputs("DEBUG: Returned CUPS_SC_STATUS_NOT_IMPLEMENTED with no bytes...\n",
+ stderr);
+ break;
+ }
+ }
+ while (!g.sidechannel_thread_stop);
+
+ pthread_mutex_lock(&g.sidechannel_thread_mutex);
+ g.sidechannel_thread_done = 1;
+ pthread_cond_signal(&g.sidechannel_thread_cond);
+ pthread_mutex_unlock(&g.sidechannel_thread_mutex);
+
+ return (NULL);
+}
+
+
+/*
+ * 'soft_reset()' - Send a soft reset to the device.
+ */
+
+static void soft_reset(void)
+{
+ fd_set input_set; /* Input set for select() */
+ struct timeval tv; /* Time value */
+ char buffer[2048]; /* Buffer */
+ struct timespec cond_timeout; /* pthread condition timeout */
+
+ /*
+ * Send an abort once a second until the I/O lock is released by the main
+ * thread...
+ */
+
+ pthread_mutex_lock(&g.readwrite_lock_mutex);
+ while (g.readwrite_lock)
+ {
+ gettimeofday(&tv, NULL);
+ cond_timeout.tv_sec = tv.tv_sec + 1;
+ cond_timeout.tv_nsec = tv.tv_usec * 1000;
+
+ while (g.readwrite_lock)
+ {
+ if (pthread_cond_timedwait(&g.readwrite_lock_cond,
+ &g.readwrite_lock_mutex,
+ &cond_timeout) != 0)
break;
+ }
}
- cupsSideChannelWrite(command, status, data, datalen, 1.0);
+ g.readwrite_lock = 1;
+ pthread_mutex_unlock(&g.readwrite_lock_mutex);
+
+ /*
+ * Flush bytes waiting on print_fd...
+ */
+
+ g.print_bytes = 0;
+
+ FD_ZERO(&input_set);
+ FD_SET(g.print_fd, &input_set);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ while (select(g.print_fd+1, &input_set, NULL, NULL, &tv) > 0)
+ if (read(g.print_fd, buffer, sizeof(buffer)) <= 0)
+ break;
+
+ /*
+ * Send the reset...
+ */
+
+ libusb_reset_device (g.printer->handle);
+
+ /*
+ * Release the I/O lock...
+ */
- return (tbytes);
+ pthread_mutex_lock(&g.readwrite_lock_mutex);
+ g.readwrite_lock = 0;
+ pthread_cond_signal(&g.readwrite_lock_cond);
+ pthread_mutex_unlock(&g.readwrite_lock_mutex);
}
/*
- * End of "$Id: usb-libusb.c 10198 2012-01-27 16:48:43Z mike $".
+ * End of "$Id: usb-libusb.c 10267 2012-02-12 08:35:28Z mike $".
*/
diff --git a/backend/usb.c b/backend/usb.c
index 81736a1f..2cacb744 100644
--- a/backend/usb.c
+++ b/backend/usb.c
@@ -1,9 +1,9 @@
/*
- * "$Id: usb.c 9771 2011-05-12 05:21:56Z mike $"
+ * "$Id: usb.c 10265 2012-02-12 07:20:10Z mike $"
*
* USB port backend for CUPS.
*
- * Copyright 2007-2011 by Apple Inc.
+ * Copyright 2007-2012 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
@@ -55,7 +55,7 @@ int print_device(const char *uri, const char *hostname,
* Include the vendor-specific USB implementation...
*/
-#ifdef HAVE_USB_H
+#ifdef HAVE_LIBUSB
# include "usb-libusb.c"
#elif defined(__APPLE__)
# include "usb-darwin.c"
@@ -118,7 +118,7 @@ print_device(const char *uri, /* I - Device URI */
return (CUPS_BACKEND_FAILED);
}
-#endif /* __APPLE__ */
+#endif /* HAVE_LIBUSB */
/*
@@ -260,5 +260,5 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
/*
- * End of "$Id: usb.c 9771 2011-05-12 05:21:56Z mike $".
+ * End of "$Id: usb.c 10265 2012-02-12 07:20:10Z mike $".
*/