diff options
author | Didier Raboud <odyx@debian.org> | 2012-10-25 20:57:13 +0200 |
---|---|---|
committer | Didier Raboud <odyx@debian.org> | 2012-10-25 20:57:13 +0200 |
commit | 49a2853988b074d087e82c51aec4f9fc052a057d (patch) | |
tree | c38ece96005bc33bd4e133fd0037f3428fdc039d /backend | |
parent | a312f7e1ac68fb22275719f6208b670d9edd45b5 (diff) | |
download | cups-49a2853988b074d087e82c51aec4f9fc052a057d.tar.gz |
Imported Upstream version 1.5.0upstream/1.5.0
Diffstat (limited to 'backend')
-rw-r--r-- | backend/Dependencies | 169 | ||||
-rw-r--r-- | backend/Makefile | 75 | ||||
-rw-r--r-- | backend/backend-private.h | 37 | ||||
-rw-r--r-- | backend/dnssd.c | 123 | ||||
-rw-r--r-- | backend/easysw-firewire-design.txt | 71 | ||||
-rw-r--r-- | backend/easysw-firewire-linux.txt | 35 | ||||
-rw-r--r-- | backend/ieee1284.c | 59 | ||||
-rw-r--r-- | backend/ipp.c | 2439 | ||||
-rw-r--r-- | backend/lpd.c | 472 | ||||
-rw-r--r-- | backend/network.c | 14 | ||||
-rw-r--r-- | backend/pap.c | 1696 | ||||
-rw-r--r-- | backend/parallel.c | 46 | ||||
-rwxr-xr-x | backend/pseudo | 30 | ||||
-rw-r--r-- | backend/runloop.c | 145 | ||||
-rw-r--r-- | backend/scsi-irix.c | 241 | ||||
-rw-r--r-- | backend/scsi-linux.c | 260 | ||||
-rw-r--r-- | backend/scsi.c | 231 | ||||
-rw-r--r-- | backend/serial.c | 79 | ||||
-rw-r--r-- | backend/snmp-supplies.c | 22 | ||||
-rw-r--r-- | backend/snmp.c | 126 | ||||
-rw-r--r-- | backend/socket.c | 200 | ||||
-rw-r--r-- | backend/test1284.c | 13 | ||||
-rw-r--r-- | backend/testbackend.c | 13 | ||||
-rw-r--r-- | backend/testsupplies.c | 8 | ||||
-rw-r--r-- | backend/usb-darwin.c | 289 | ||||
-rw-r--r-- | backend/usb-libusb.c | 118 | ||||
-rw-r--r-- | backend/usb-unix.c | 56 | ||||
-rw-r--r-- | backend/usb.c | 19 |
28 files changed, 2961 insertions, 4125 deletions
diff --git a/backend/Dependencies b/backend/Dependencies index 9051be05..4f99c17e 100644 --- a/backend/Dependencies +++ b/backend/Dependencies @@ -1,76 +1,101 @@ # DO NOT DELETE THIS LINE -- make depend depends on it. -ipp.o: ../cups/http-private.h ../config.h ../cups/http.h ../cups/versioning.h -ipp.o: ../cups/md5.h ../cups/ipp-private.h ../cups/ipp.h backend-private.h -ipp.o: ../cups/backend.h ../cups/sidechannel.h ../cups/ppd-private.h -ipp.o: ../cups/cups.h ../cups/ppd.h ../cups/array.h ../cups/file.h -ipp.o: ../cups/language.h ../cups/debug.h ../cups/i18n.h ../cups/transcode.h -ipp.o: ../cups/snmp-private.h ../cups/string.h -lpd.o: ../cups/http-private.h ../config.h ../cups/http.h ../cups/versioning.h -lpd.o: ../cups/md5.h ../cups/ipp-private.h ../cups/ipp.h backend-private.h -lpd.o: ../cups/backend.h ../cups/sidechannel.h ../cups/ppd-private.h -lpd.o: ../cups/cups.h ../cups/ppd.h ../cups/array.h ../cups/file.h -lpd.o: ../cups/language.h ../cups/debug.h ../cups/i18n.h ../cups/transcode.h -lpd.o: ../cups/snmp-private.h ../cups/string.h -dnssd.o: backend-private.h ../cups/backend.h ../cups/versioning.h -dnssd.o: ../cups/sidechannel.h ../cups/ppd-private.h ../cups/cups.h -dnssd.o: ../cups/ipp.h ../cups/http.h ../cups/ppd.h ../cups/array.h -dnssd.o: ../cups/file.h ../cups/language.h ../cups/debug.h ../cups/i18n.h -dnssd.o: ../cups/transcode.h ../cups/snmp-private.h ../cups/string.h -dnssd.o: ../config.h ../cups/array.h -pap.o: ../config.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -pap.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h -pap.o: ../cups/language.h ../cups/backend.h ../cups/sidechannel.h -pap.o: ../cups/i18n.h ../cups/transcode.h -parallel.o: backend-private.h ../cups/backend.h ../cups/versioning.h -parallel.o: ../cups/sidechannel.h ../cups/ppd-private.h ../cups/cups.h -parallel.o: ../cups/ipp.h ../cups/http.h ../cups/ppd.h ../cups/array.h -parallel.o: ../cups/file.h ../cups/language.h ../cups/debug.h ../cups/i18n.h -parallel.o: ../cups/transcode.h ../cups/snmp-private.h ../cups/string.h -parallel.o: ../config.h -scsi.o: ../cups/backend.h ../cups/versioning.h ../cups/cups.h ../cups/ipp.h -scsi.o: ../cups/http.h ../cups/ppd.h ../cups/array.h ../cups/file.h -scsi.o: ../cups/language.h ../cups/i18n.h ../cups/transcode.h -scsi.o: ../cups/string.h ../config.h -serial.o: backend-private.h ../cups/backend.h ../cups/versioning.h -serial.o: ../cups/sidechannel.h ../cups/ppd-private.h ../cups/cups.h -serial.o: ../cups/ipp.h ../cups/http.h ../cups/ppd.h ../cups/array.h -serial.o: ../cups/file.h ../cups/language.h ../cups/debug.h ../cups/i18n.h -serial.o: ../cups/transcode.h ../cups/snmp-private.h ../cups/string.h -serial.o: ../config.h -snmp.o: backend-private.h ../cups/backend.h ../cups/versioning.h -snmp.o: ../cups/sidechannel.h ../cups/ppd-private.h ../cups/cups.h -snmp.o: ../cups/ipp.h ../cups/http.h ../cups/ppd.h ../cups/array.h -snmp.o: ../cups/file.h ../cups/language.h ../cups/debug.h ../cups/i18n.h -snmp.o: ../cups/transcode.h ../cups/snmp-private.h ../cups/string.h -snmp.o: ../config.h ../cups/array.h ../cups/file.h ../cups/http-private.h -snmp.o: ../cups/md5.h ../cups/ipp-private.h +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 +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/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 +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 +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 +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 socket.o: ../cups/http-private.h ../config.h ../cups/http.h -socket.o: ../cups/versioning.h ../cups/md5.h ../cups/ipp-private.h -socket.o: ../cups/ipp.h backend-private.h ../cups/backend.h -socket.o: ../cups/sidechannel.h ../cups/ppd-private.h ../cups/cups.h -socket.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h -socket.o: ../cups/debug.h ../cups/i18n.h ../cups/transcode.h -socket.o: ../cups/snmp-private.h ../cups/string.h -test1284.o: ../cups/string.h ../config.h ieee1284.c backend-private.h -test1284.o: ../cups/backend.h ../cups/versioning.h ../cups/sidechannel.h -test1284.o: ../cups/ppd-private.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -test1284.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h -test1284.o: ../cups/debug.h ../cups/i18n.h ../cups/transcode.h -test1284.o: ../cups/snmp-private.h -testbackend.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h -testbackend.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h -testbackend.o: ../cups/array.h ../cups/file.h ../cups/language.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 +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/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 +testbackend.o: ../cups/file.h ../cups/versioning.h ../cups/ipp.h +testbackend.o: ../cups/http.h ../cups/array.h ../cups/language.h testbackend.o: ../cups/sidechannel.h -testsupplies.o: backend-private.h ../cups/backend.h ../cups/versioning.h -testsupplies.o: ../cups/sidechannel.h ../cups/ppd-private.h ../cups/cups.h -testsupplies.o: ../cups/ipp.h ../cups/http.h ../cups/ppd.h ../cups/array.h -testsupplies.o: ../cups/file.h ../cups/language.h ../cups/debug.h -testsupplies.o: ../cups/i18n.h ../cups/transcode.h ../cups/snmp-private.h -testsupplies.o: ../cups/string.h ../config.h -usb.o: backend-private.h ../cups/backend.h ../cups/versioning.h -usb.o: ../cups/sidechannel.h ../cups/ppd-private.h ../cups/cups.h -usb.o: ../cups/ipp.h ../cups/http.h ../cups/ppd.h ../cups/array.h -usb.o: ../cups/file.h ../cups/language.h ../cups/debug.h ../cups/i18n.h -usb.o: ../cups/transcode.h ../cups/snmp-private.h ../cups/string.h -usb.o: ../config.h +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/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 diff --git a/backend/Makefile b/backend/Makefile index 16b66e2f..47feac9e 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -1,9 +1,9 @@ # -# "$Id: Makefile 8400 2009-03-03 19:39:21Z mike $" +# "$Id: Makefile 9737 2011-05-04 04:28:00Z mike $" # -# Backend makefile for the Common UNIX Printing System (CUPS). +# Backend makefile for CUPS. # -# Copyright 2007-2009 by Apple Inc. +# Copyright 2007-2011 by Apple Inc. # Copyright 1997-2007 by Easy Software Products, all rights reserved. # # These coded instructions, statements, and computer programs are the @@ -17,12 +17,16 @@ include ../Makedefs +# +# Object files... +# + RBACKENDS = ipp lpd $(DNSSD_BACKEND) -UBACKENDS = $(PAP) $(LEGACY_BACKENDS) serial snmp socket usb +UBACKENDS = $(LEGACY_BACKENDS) serial snmp socket usb UNITTESTS = test1284 testbackend testsupplies TARGETS = libbackend.a $(RBACKENDS) $(UBACKENDS) LIBOBJS = ieee1284.o network.o runloop.o snmp-supplies.o -OBJS = ipp.o lpd.o dnssd.o pap.o parallel.o scsi.o serial.o snmp.o \ +OBJS = ipp.o lpd.o dnssd.o parallel.o serial.o snmp.o \ socket.o test1284.o testbackend.o testsupplies.o usb.o @@ -81,7 +85,8 @@ install-data: # Install programs... # -install-exec: +install-exec: $(INSTALLXPC) + echo Installing backends in $(SERVERBIN)/backend $(INSTALL_DIR) -m 755 $(SERVERBIN)/backend for file in $(RBACKENDS); do \ $(LIBTOOL) $(INSTALL_BIN) -m 700 $$file $(SERVERBIN)/backend; \ @@ -89,8 +94,10 @@ install-exec: for file in $(UBACKENDS); do \ $(INSTALL_BIN) $$file $(SERVERBIN)/backend; \ done - $(RM) $(SERVERBIN)/backend/http - $(LN) ipp $(SERVERBIN)/backend/http + for file in $(IPPALIASES); do \ + $(RM) $(SERVERBIN)/backend/$$file; \ + $(LN) ipp $(SERVERBIN)/backend/$$file; \ + done if test "x$(DNSSD_BACKEND)" != x; then \ $(RM) $(SERVERBIN)/backend/mdns; \ $(LN) $(DNSSD_BACKEND) $(SERVERBIN)/backend/mdns; \ @@ -102,6 +109,15 @@ install-exec: done \ fi +install-xpc: ipp + echo Installing XPC backends in $(SERVERBIN)/apple + $(INSTALL_DIR) -m 755 $(SERVERBIN)/apple + $(LIBTOOL) $(INSTALL_BIN) ipp $(SERVERBIN)/apple + for file in $(IPPALIASES); do \ + $(RM) $(SERVERBIN)/apple/$$file; \ + $(LN) ipp $(SERVERBIN)/apple/$$file; \ + done + # # Install headers... @@ -122,10 +138,17 @@ install-libs: # uninstall: + $(RM) $(SERVERBIN)/apple/ipp + for file in $(IPPALIASES); do \ + $(RM) $(SERVERBIN)/apple/$$file; \ + done + -$(RMDIR) $(SERVERBIN)/apple for file in $(RBACKENDS) $(UBACKENDS); do \ $(RM) $(SERVERBIN)/backend/$$file; \ done - $(RM) $(SERVERBIN)/backend/http + for file in $(IPPALIASES); do \ + $(RM) $(SERVERBIN)/backend/$$file; \ + done -$(RMDIR) $(SERVERBIN)/backend -$(RMDIR) $(SERVERBIN) @@ -134,9 +157,9 @@ uninstall: # test1284 # -test1284: test1284.o ../cups/libcups.a +test1284: test1284.o ../cups/$(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o test1284 test1284.o ../cups/libcups.a \ + $(CC) $(LDFLAGS) -o test1284 test1284.o ../cups/$(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) @@ -144,9 +167,9 @@ test1284: test1284.o ../cups/libcups.a # testbackend # -testbackend: testbackend.o ../cups/libcups.a +testbackend: testbackend.o ../cups/$(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o testbackend testbackend.o ../cups/libcups.a \ + $(CC) $(LDFLAGS) -o testbackend testbackend.o ../cups/$(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) @@ -154,10 +177,10 @@ testbackend: testbackend.o ../cups/libcups.a # testsupplies # -testsupplies: testsupplies.o libbackend.a ../cups/libcups.a +testsupplies: testsupplies.o libbackend.a ../cups/$(LIBCUPSSTATIC) echo Linking $@... $(CC) $(LDFLAGS) -o testsupplies testsupplies.o libbackend.a \ - ../cups/libcups.a $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ + ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ $(COMMONLIBS) $(LIBZ) @@ -204,15 +227,6 @@ lpd: lpd.o ../cups/$(LIBCUPS) libbackend.a # -# pap -# - -pap: pap.o ../cups/$(LIBCUPS) - echo Linking $@... - $(CC) $(LDFLAGS) -o pap pap.o $(BACKLIBS) $(LIBS) -framework AppleTalk - - -# # parallel # @@ -222,17 +236,6 @@ parallel: parallel.o ../cups/$(LIBCUPS) libbackend.a # -# scsi -# - -scsi: scsi.o ../cups/$(LIBCUPS) - echo Linking $@... - $(CC) $(LDFLAGS) -o scsi scsi.o $(LIBS) - -scsi.o: scsi.c scsi-irix.c scsi-linux.c - - -# # serial # @@ -278,5 +281,5 @@ include Dependencies # -# End of "$Id: Makefile 8400 2009-03-03 19:39:21Z mike $". +# End of "$Id: Makefile 9737 2011-05-04 04:28:00Z mike $". # diff --git a/backend/backend-private.h b/backend/backend-private.h index df08a2c9..95dc2d88 100644 --- a/backend/backend-private.h +++ b/backend/backend-private.h @@ -1,9 +1,9 @@ /* - * "$Id: backend-private.h 8912 2009-12-08 02:13:42Z mike $" + * "$Id: backend-private.h 9577 2011-03-04 18:02:45Z mike $" * - * Backend support definitions for the Common UNIX Printing System (CUPS). + * Backend support definitions for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -23,15 +23,10 @@ * Include necessary headers. */ +# include <cups/cups-private.h> +# include <cups/snmp-private.h> # include <cups/backend.h> # include <cups/sidechannel.h> -# include <cups/ppd-private.h> -# include <cups/debug.h> -# include <cups/i18n.h> -# include <cups/snmp-private.h> -# include <stdlib.h> -# include <errno.h> -# include <cups/string.h> # include <signal.h> # ifdef __linux @@ -282,6 +277,14 @@ extern "C" { /* + * Types... + */ + +typedef int (*_cups_sccb_t)(int print_fd, int device_fd, int snmp_fd, + http_addr_t *addr, int use_bc); + + +/* * Prototypes... */ @@ -300,16 +303,14 @@ extern int backendNetworkSideCB(int print_fd, int device_fd, int snmp_fd, http_addr_t *addr, int use_bc); extern ssize_t backendRunLoop(int print_fd, int device_fd, int snmp_fd, - http_addr_t *addr, int use_bc, - int update_state, - int (*side_cb)(int print_fd, - int device_fd, - int snmp_fd, - http_addr_t *addr, - int use_bc)); + http_addr_t *addr, int use_bc, + int update_state, _cups_sccb_t side_cb); extern int backendSNMPSupplies(int snmp_fd, http_addr_t *addr, int *page_count, int *printer_state); +extern int backendWaitLoop(int snmp_fd, http_addr_t *addr, + int use_bc, _cups_sccb_t side_cb); + # ifdef __cplusplus } @@ -318,5 +319,5 @@ extern int backendSNMPSupplies(int snmp_fd, http_addr_t *addr, /* - * End of "$Id: backend-private.h 8912 2009-12-08 02:13:42Z mike $". + * End of "$Id: backend-private.h 9577 2011-03-04 18:02:45Z mike $". */ diff --git a/backend/dnssd.c b/backend/dnssd.c index 32dff816..10af920a 100644 --- a/backend/dnssd.c +++ b/backend/dnssd.c @@ -1,9 +1,9 @@ /* - * "$Id: dnssd.c 8758 2009-08-07 22:27:12Z mike $" + * "$Id: dnssd.c 9815 2011-06-05 16:58:33Z mike $" * - * DNS-SD discovery backend for the Common UNIX Printing System (CUPS). + * DNS-SD discovery backend for CUPS. * - * Copyright 2008-2009 by Apple Inc. + * Copyright 2008-2011 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -44,6 +44,7 @@ typedef enum { CUPS_DEVICE_PRINTER = 0, /* lpd://... */ CUPS_DEVICE_IPP, /* ipp://... */ + CUPS_DEVICE_IPPS, /* ipps://... */ CUPS_DEVICE_FAX_IPP, /* ipp://... */ CUPS_DEVICE_PDL_DATASTREAM, /* socket://... */ CUPS_DEVICE_RIOUSBPRINT /* riousbprint://... */ @@ -123,9 +124,11 @@ main(int argc, /* I - Number of command-line args */ fax_ipp_ref, /* IPP fax service reference */ ipp_ref, /* IPP service reference */ ipp_tls_ref, /* IPP w/TLS service reference */ + ipps_ref, /* IPP service reference */ local_fax_ipp_ref, /* Local IPP fax service reference */ local_ipp_ref, /* Local IPP service reference */ local_ipp_tls_ref, /* Local IPP w/TLS service reference */ + local_ipps_ref, /* Local IPP service reference */ local_printer_ref, /* Local LPD service reference */ pdl_datastream_ref, /* AppSocket service reference */ printer_ref, /* LPD service reference */ @@ -167,8 +170,9 @@ main(int argc, /* I - Number of command-line args */ exec_backend(argv); else if (argc != 1) { - fprintf(stderr, "Usage: %s job user title copies options [filename(s)]\n", - argv[0]); + _cupsLangPrintf(stderr, + _("Usage: %s job-id user title copies options [file]"), + argv[0]); return (1); } @@ -214,6 +218,10 @@ main(int argc, /* I - Number of command-line args */ DNSServiceBrowse(&ipp_tls_ref, kDNSServiceFlagsShareConnection, 0, "_ipp-tls._tcp", NULL, browse_callback, devices); + ipps_ref = main_ref; + DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0, + "_ipps._tcp", NULL, browse_callback, devices); + local_fax_ipp_ref = main_ref; DNSServiceBrowse(&local_fax_ipp_ref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexLocalOnly, @@ -229,12 +237,17 @@ main(int argc, /* I - Number of command-line args */ kDNSServiceInterfaceIndexLocalOnly, "_ipp-tls._tcp", NULL, browse_local_callback, devices); + local_ipps_ref = main_ref; + DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection, + kDNSServiceInterfaceIndexLocalOnly, + "_ipps._tcp", NULL, browse_local_callback, devices); + local_printer_ref = main_ref; DNSServiceBrowse(&local_printer_ref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexLocalOnly, "_printer._tcp", NULL, browse_local_callback, devices); - pdl_datastream_ref = main_ref; + pdl_datastream_ref = main_ref; DNSServiceBrowse(&pdl_datastream_ref, kDNSServiceFlagsShareConnection, 0, "_pdl-datastream._tcp", NULL, browse_callback, devices); @@ -255,8 +268,8 @@ main(int argc, /* I - Number of command-line args */ FD_ZERO(&input); FD_SET(fd, &input); - timeout.tv_sec = 1; - timeout.tv_usec = 0; + timeout.tv_sec = 0; + timeout.tv_usec = 250000; if (select(fd + 1, &input, NULL, NULL, &timeout) < 0) continue; @@ -279,19 +292,26 @@ main(int argc, /* I - Number of command-line args */ cups_device_t *best; /* Best matching device */ char device_uri[1024]; /* Device URI */ int count; /* Number of queries */ - + int sent; /* Number of sent */ for (device = (cups_device_t *)cupsArrayFirst(devices), - best = NULL, count = 0; + best = NULL, count = 0, sent = 0; device; device = (cups_device_t *)cupsArrayNext(devices)) + { + if (device->sent) + sent ++; + + if (device->ref) + count ++; + if (!device->ref && !device->sent) { /* * Found the device, now get the TXT record(s) for it... */ - if (count < 10) + if (count < 20) { device->ref = main_ref; @@ -324,8 +344,8 @@ main(int argc, /* I - Number of command-line args */ if (!best) best = device; - else if (strcasecmp(best->name, device->name) || - strcasecmp(best->domain, device->domain)) + else if (_cups_strcasecmp(best->name, device->name) || + _cups_strcasecmp(best->domain, device->domain)) { unquote(uriName, best->fullName, sizeof(uriName)); @@ -337,6 +357,8 @@ main(int argc, /* I - Number of command-line args */ best->name, best->device_id, NULL); best->sent = 1; best = device; + + sent ++; } else if (best->priority > device->priority || (best->priority == device->priority && @@ -344,10 +366,17 @@ main(int argc, /* I - Number of command-line args */ { best->sent = 1; best = device; + + sent ++; } else + { device->sent = 1; + + sent ++; + } } + } if (best) { @@ -360,7 +389,11 @@ main(int argc, /* I - Number of command-line args */ cupsBackendReport("network", device_uri, best->make_and_model, best->name, best->device_id, NULL); best->sent = 1; + sent ++; } + + if (sent == cupsArrayCount(devices)) + break; } } @@ -491,8 +524,14 @@ exec_backend(char **argv) /* I - Command-line arguments */ job_canceled = -1; - if ((resolved_uri = cupsBackendDeviceURI(argv)) == NULL) - exit(CUPS_BACKEND_FAILED); + while ((resolved_uri = cupsBackendDeviceURI(argv)) == NULL) + { + _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer.")); + sleep(10); + + if (getenv("CLASS") != NULL) + exit(CUPS_BACKEND_FAILED); + } /* * Extract the scheme from the URI... @@ -551,9 +590,11 @@ get_device(cups_array_t *devices, /* I - Device array */ key.name = (char *)serviceName; - if (!strcmp(regtype, "_ipp._tcp.") || - !strcmp(regtype, "_ipp-tls._tcp.")) + if (!strcmp(regtype, "_ipp._tcp.")) key.type = CUPS_DEVICE_IPP; + else if (!strcmp(regtype, "_ipps._tcp.") || + !strcmp(regtype, "_ipp-tls._tcp.")) + key.type = CUPS_DEVICE_IPPS; else if (!strcmp(regtype, "_fax-ipp._tcp.")) key.type = CUPS_DEVICE_FAX_IPP; else if (!strcmp(regtype, "_printer._tcp.")) @@ -566,12 +607,12 @@ get_device(cups_array_t *devices, /* I - Device array */ for (device = cupsArrayFind(devices, &key); device; device = cupsArrayNext(devices)) - if (strcasecmp(device->name, key.name)) + if (_cups_strcasecmp(device->name, key.name)) break; else if (device->type == key.type) { - if (!strcasecmp(device->domain, "local.") && - strcasecmp(device->domain, replyDomain)) + if (!_cups_strcasecmp(device->domain, "local.") && + _cups_strcasecmp(device->domain, replyDomain)) { /* * Update the .local listing to use the "global" domain name instead. @@ -673,9 +714,11 @@ query_callback( if ((ptr = strstr(name, "._")) != NULL) *ptr = '\0'; - if (strstr(fullName, "_ipp._tcp.") || - strstr(fullName, "_ipp-tls._tcp.")) + if (strstr(fullName, "_ipp._tcp.")) dkey.type = CUPS_DEVICE_IPP; + else if (strstr(fullName, "_ipps._tcp.") || + strstr(fullName, "_ipp-tls._tcp.")) + dkey.type = CUPS_DEVICE_IPPS; else if (strstr(fullName, "_fax-ipp._tcp.")) dkey.type = CUPS_DEVICE_FAX_IPP; else if (strstr(fullName, "_printer._tcp.")) @@ -689,8 +732,8 @@ query_callback( device; device = cupsArrayNext(devices)) { - if (strcasecmp(device->name, dkey.name) || - strcasecmp(device->domain, dkey.domain)) + if (_cups_strcasecmp(device->name, dkey.name) || + _cups_strcasecmp(device->domain, dkey.domain)) { device = NULL; break; @@ -747,11 +790,18 @@ query_callback( if (data < datanext) memcpy(value, data, datanext - data); value[datanext - data] = '\0'; + + fprintf(stderr, "DEBUG2: query_callback: \"%s=%s\".\n", + key, value); } else + { + fprintf(stderr, "DEBUG2: query_callback: \"%s\" with no value.\n", + key); continue; + } - if (!strncasecmp(key, "usb_", 4)) + if (!_cups_strncasecmp(key, "usb_", 4)) { /* * Add USB device ID information... @@ -762,12 +812,12 @@ query_callback( key + 4, value); } - if (!strcasecmp(key, "usb_MFG") || !strcasecmp(key, "usb_MANU") || - !strcasecmp(key, "usb_MANUFACTURER")) + if (!_cups_strcasecmp(key, "usb_MFG") || !_cups_strcasecmp(key, "usb_MANU") || + !_cups_strcasecmp(key, "usb_MANUFACTURER")) strcpy(make_and_model, value); - else if (!strcasecmp(key, "usb_MDL") || !strcasecmp(key, "usb_MODEL")) + else if (!_cups_strcasecmp(key, "usb_MDL") || !_cups_strcasecmp(key, "usb_MODEL")) strcpy(model, value); - else if (!strcasecmp(key, "product") && !strstr(value, "Ghostscript")) + else if (!_cups_strcasecmp(key, "product") && !strstr(value, "Ghostscript")) { if (value[0] == '(') { @@ -783,18 +833,19 @@ query_callback( else strcpy(model, value); } - else if (!strcasecmp(key, "ty")) + else if (!_cups_strcasecmp(key, "ty")) { strcpy(model, value); if ((ptr = strchr(model, ',')) != NULL) *ptr = '\0'; } - else if (!strcasecmp(key, "priority")) + else if (!_cups_strcasecmp(key, "priority")) device->priority = atoi(value); else if ((device->type == CUPS_DEVICE_IPP || + device->type == CUPS_DEVICE_IPPS || device->type == CUPS_DEVICE_PRINTER) && - !strcasecmp(key, "printer-type")) + !_cups_strcasecmp(key, "printer-type")) { /* * This is a CUPS printer! @@ -815,9 +866,9 @@ query_callback( if (make_and_model[0]) snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;", make_and_model, model); - else if (!strncasecmp(model, "designjet ", 10)) + else if (!_cups_strncasecmp(model, "designjet ", 10)) snprintf(device_id, sizeof(device_id), "MFG:HP;MDL:%s", model + 10); - else if (!strncasecmp(model, "stylus ", 7)) + else if (!_cups_strncasecmp(model, "stylus ", 7)) snprintf(device_id, sizeof(device_id), "MFG:EPSON;MDL:%s", model + 7); else if ((ptr = strchr(model, ' ')) != NULL) { @@ -866,6 +917,8 @@ query_callback( static void sigterm_handler(int sig) /* I - Signal number (unused) */ { + (void)sig; + if (job_canceled) exit(CUPS_BACKEND_OK); else @@ -908,5 +961,5 @@ unquote(char *dst, /* I - Destination buffer */ /* - * End of "$Id: dnssd.c 8758 2009-08-07 22:27:12Z mike $". + * End of "$Id: dnssd.c 9815 2011-06-05 16:58:33Z mike $". */ diff --git a/backend/easysw-firewire-design.txt b/backend/easysw-firewire-design.txt deleted file mode 100644 index 194c487e..00000000 --- a/backend/easysw-firewire-design.txt +++ /dev/null @@ -1,71 +0,0 @@ -Preliminary Design for CUPS Firewire Printer Backend - 03/19/2002 ------------------------------------------------------------------ - -OVERVIEW - - Easy Software Products will develop an IEEE-1394, a.k.a. - Firewire, printing interface for its Common UNIX Printing - System ("CUPS") for initial use under the Linux operating - system. A follow-on implementation for MacOS X is - anticipated as well. - - The operating system interfaces for IEEE-1394 ports vary - widely; the CUPS printing interface will abstract the OS - layer to a simpler interface geared towards discovering, - opening, reading from, writing to, and closing IEEE-1394 - printers. - - The initial development of the CUPS backend will be targeted - at the EPSON Stylus Pro 10000 large format printer, which - requires the bandwidth provided by Firewire in order to - print at full speed. This printer supports printing via - Serial Bus Protocol 2 (SBP-2) using the SCSI and PWG command - sets. The CUPS backend will implement the PWG command set on - LUN 0 only. - - -OS ABSTRACTION LAYER - - The OS abstraction layer will be a thin client library that - implements the following functions: - - ieee1394_list - ieee1394_open - ieee1394_close - ieee1394_read - ieee1394_write - ieee1394_error - - The "ieee1394_list" function will list all of the available - printer devices on the bus. The device information will - consist of the device URI (ieee1394:/something) used to - access the device and the make and model information, if - available, for the device ("EPSON Stylus Printer"). - - The "ieee1394_open" and "ieee1394_close" functions will open - and close a connection to the printer, respectively. - - The "ieee1394_read" and "ieee1394_write" functions will read - and write data to and from the printer, respectively. The - read function will be non-blocking, returning data only if - there is data coming back from the printer. - - The "ieee1394_error" function will return a string - describing the last error or NULL if no error occurred. - - The library will be responsible for creating any background - threads that are needed to monitor the connection to the - printer. - - -CUPS BACKEND - - The CUPS backend will use the OS abstraction layer to list - and access the Firewire printers. The "main" function will - read and write printer data, while the "list_devices" - function will be called as necessary to identify the - available devices. - - The CUPS 1.1 backend will record any status information in - the error log file, while the 1.2 backend will supply it to - the printer driver process. diff --git a/backend/easysw-firewire-linux.txt b/backend/easysw-firewire-linux.txt deleted file mode 100644 index a8e46118..00000000 --- a/backend/easysw-firewire-linux.txt +++ /dev/null @@ -1,35 +0,0 @@ -Easy Software Products -44141 Airport View Drive -Suite 204 -Hollywood, Maryland 20636 -+1.301.373.9600 -March 8, 2002 - - -Subject: EPSON Firewire Printer Driver for Linux - -Currently, no Firewire printer support exists for Linux. Since -the latest EPSON printer products depend on the Firewire -interface to print at full speed, a solution is needed to -support customers using Linux as their server platform. - -The Linux Firewire subsystem provides a user-mode driver -interface that allows driver programs to access Firewire -devices. Easy Software Products will utilize this interface to -develop a "backend" program for the Common UNIX Printing System -that will allow users to print to EPSON printers using the -Firewire interface. - -After examining the Linux interface, we estimate that it will -require approximately 30 hours of development time to write, -test, and document the Firewire backend, for a total cost of -$3,000. The new backend will become a standard part of the CUPS -software distribution and will be included with at least the -following Linux distributions: - - - Caldera Linux - - Mandrake Linux - - Red Hat Linux - - SuSE Linux - -ESP will provide EPSON with binaries for Red Hat Linux 7.2. diff --git a/backend/ieee1284.c b/backend/ieee1284.c index d55c75a1..c95fbc7f 100644 --- a/backend/ieee1284.c +++ b/backend/ieee1284.c @@ -1,9 +1,9 @@ /* - * "$Id: ieee1284.c 9098 2010-04-09 22:42:09Z mike $" + * "$Id: ieee1284.c 9828 2011-06-14 06:38:24Z mike $" * - * IEEE-1284 support functions for the Common UNIX Printing System (CUPS). + * IEEE-1284 support functions for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -26,6 +26,7 @@ */ #include "backend-private.h" +#include <cups/cups-private.h> /* @@ -45,6 +46,15 @@ backendGetDeviceID( int uri_size) /* I - Size of buffer */ { #ifdef __APPLE__ /* This function is a no-op */ + (void)fd; + (void)device_id; + (void)device_id_size; + (void)make_model; + (void)make_model_size; + (void)scheme; + (void)uri; + (void)uri_size; + return (-1); #else /* Get the device ID from the specified file descriptor... */ @@ -55,6 +65,7 @@ backendGetDeviceID( # if defined(__sun) && defined(ECPPIOC_GETDEVID) struct ecpp_device_id did; /* Device ID buffer */ # endif /* __sun && ECPPIOC_GETDEVID */ + char *ptr; /* Pointer into device ID */ DEBUG_printf(("backendGetDeviceID(fd=%d, device_id=%p, device_id_size=%d, " @@ -176,7 +187,7 @@ backendGetDeviceID( * and then limit the length to the size of our buffer... */ - if (length > device_id_size) + if (length > device_id_size || length < 14) length = (((unsigned)device_id[1] & 255) << 8) + ((unsigned)device_id[0] & 255); @@ -214,11 +225,12 @@ backendGetDeviceID( device_id[length] = '\0'; } } -# ifdef DEBUG else + { DEBUG_printf(("backendGetDeviceID: ioctl failed - %s\n", strerror(errno))); -# endif /* DEBUG */ + *device_id = '\0'; + } # endif /* __linux */ # if defined(__sun) && defined(ECPPIOC_GETDEVID) @@ -246,6 +258,22 @@ backendGetDeviceID( # endif /* __sun && ECPPIOC_GETDEVID */ } + /* + * Check whether device ID is valid. Turn line breaks and tabs to spaces and + * reject device IDs with non-printable characters. + */ + + for (ptr = device_id; *ptr; ptr ++) + if (_cups_isspace(*ptr)) + *ptr = ' '; + else if ((*ptr & 255) < ' ' || *ptr == 127) + { + DEBUG_printf(("backendGetDeviceID: Bad device_id character %d.", + *ptr & 255)); + *device_id = '\0'; + break; + } + DEBUG_printf(("backendGetDeviceID: device_id=\"%s\"\n", device_id)); if (scheme && uri) @@ -280,7 +308,7 @@ backendGetDeviceID( * Get the make, model, and serial numbers... */ - num_values = _ppdGet1284Values(device_id, &values); + num_values = _cupsGet1284Values(device_id, &values); if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL) if ((sern = cupsGetOption("SERN", num_values, values)) == NULL) @@ -294,9 +322,9 @@ backendGetDeviceID( if (mfg) { - if (!strcasecmp(mfg, "Hewlett-Packard")) + if (!_cups_strcasecmp(mfg, "Hewlett-Packard")) mfg = "HP"; - else if (!strcasecmp(mfg, "Lexmark International")) + else if (!_cups_strcasecmp(mfg, "Lexmark International")) mfg = "Lexmark"; } else @@ -312,7 +340,7 @@ backendGetDeviceID( if (!mdl) mdl = ""; - if (!strncasecmp(mdl, mfg, strlen(mfg))) + if (!_cups_strncasecmp(mdl, mfg, strlen(mfg))) { mdl += strlen(mfg); @@ -373,7 +401,7 @@ backendGetMakeModel( * Look for the description field... */ - num_values = _ppdGet1284Values(device_id, &values); + num_values = _cupsGet1284Values(device_id, &values); if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL) mdl = cupsGetOption("MDL", num_values, values); @@ -387,7 +415,7 @@ backendGetMakeModel( if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL) mfg = cupsGetOption("MFG", num_values, values); - if (!mfg || !strncasecmp(mdl, mfg, strlen(mfg))) + if (!mfg || !_cups_strncasecmp(mdl, mfg, strlen(mfg))) { /* * Just copy the model string, since it has the manufacturer... @@ -403,10 +431,7 @@ backendGetMakeModel( char temp[1024]; /* Temporary make and model */ - if (mfg) - snprintf(temp, sizeof(temp), "%s %s", mfg, mdl); - else - snprintf(temp, sizeof(temp), "%s", mdl); + snprintf(temp, sizeof(temp), "%s %s", mfg, mdl); _ppdNormalizeMakeAndModel(temp, make_model, make_model_size); } @@ -462,5 +487,5 @@ backendGetMakeModel( /* - * End of "$Id: ieee1284.c 9098 2010-04-09 22:42:09Z mike $". + * End of "$Id: ieee1284.c 9828 2011-06-14 06:38:24Z mike $". */ diff --git a/backend/ipp.c b/backend/ipp.c index ef0fe0a9..be5fce37 100644 --- a/backend/ipp.c +++ b/backend/ipp.c @@ -1,9 +1,9 @@ /* - * "$Id: ipp.c 8950 2010-01-14 22:40:19Z mike $" + * "$Id: ipp.c 9808 2011-05-26 12:03:28Z mike $" * - * IPP backend for the Common UNIX Printing System (CUPS). + * IPP backend for CUPS. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -18,14 +18,16 @@ * * main() - Send a file to the printer or server. * cancel_job() - Cancel a print job. - * check_printer_state() - Check the printer state... - * compress_files() - Compress print files... + * check_printer_state() - Check the printer state. + * compress_files() - Compress print files. + * monitor_printer() - Monitor the printer state. + * new_request() - Create a new print creation or validation request. * password_cb() - Disable the password prompt for * cupsDoFileRequest(). * report_attr() - Report an IPP attribute value. * report_printer_state() - Report the printer state. - * run_pictwps_filter() - Convert PICT files to PostScript when printing - * remotely. + * run_as_user() - Run the IPP backend as the printing user. + * timeout_cb() - Handle HTTP timeouts. * sigterm_handler() - Handle 'terminate' signals that stop the backend. */ @@ -33,47 +35,136 @@ * Include necessary headers. */ -#include <cups/http-private.h> #include "backend-private.h" +#include <cups/array-private.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> +#if defined(HAVE_GSSAPI) && defined(HAVE_XPC) +# include <xpc/xpc.h> +# define kPMPrintUIToolAgent "com.apple.printuitool.agent" +# define kPMStartJob 100 +# define kPMWaitForJob 101 +extern void xpc_connection_set_target_uid(xpc_connection_t connection, + uid_t uid); +#endif /* HAVE_GSSAPI && HAVE_XPC */ + + +/* + * Types... + */ + +typedef struct _cups_monitor_s /**** Monitoring data ****/ +{ + const char *uri, /* Printer URI */ + *hostname, /* Hostname */ + *user, /* Username */ + *resource; /* Resource path */ + int port, /* Port number */ + version, /* IPP version */ + job_id; /* Job ID 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 */ +} _cups_monitor_t; + /* * Globals... */ -static char *password = NULL; /* Password for device URI */ -static int password_tries = 0; /* Password tries */ -static const char *auth_info_required = "none"; +static const char *auth_info_required; /* New auth-info-required value */ -#ifdef __APPLE__ -static char pstmpname[1024] = ""; /* Temporary PostScript file name */ -#endif /* __APPLE__ */ -static char tmpfilename[1024] = ""; /* Temporary spool file name */ -static int job_cancelled = 0; /* Job cancelled? */ +#if defined(HAVE_GSSAPI) && defined(HAVE_XPC) +static int child_pid = 0; /* Child process ID */ +#endif /* HAVE_GSSAPI && HAVE_XPC */ +static const char * const jattrs[] = /* Job attributes we want */ +{ + "job-impressions-completed", + "job-media-sheets-completed", + "job-state", + "job-state-reasons" +}; +static int job_canceled = 0; + /* Job cancelled? */ +static char *password = NULL; + /* Password for device URI */ +static int password_tries = 0; + /* Password tries */ +static const char * const pattrs[] = /* Printer attributes we want */ +{ + "copies-supported", + "cups-version", + "document-format-supported", + "marker-colors", + "marker-high-levels", + "marker-levels", + "marker-low-levels", + "marker-message", + "marker-names", + "marker-types", + "media-col-supported", + "multiple-document-handling-supported", + "operations-supported", + "printer-alert", + "printer-alert-description", + "printer-is-accepting-jobs", + "printer-state", + "printer-state-message", + "printer-state-reasons", +}; +static const char * const remote_job_states[] = +{ /* Remote job state keywords */ + "+cups-remote-pending", + "+cups-remote-pending-held", + "+cups-remote-processing", + "+cups-remote-stopped", + "+cups-remote-canceled", + "+cups-remote-aborted", + "+cups-remote-completed" +}; +static _cups_mutex_t report_mutex = _CUPS_MUTEX_INITIALIZER; + /* Mutex to control access */ +static int num_attr_cache = 0; + /* Number of cached attributes */ +static cups_option_t *attr_cache = NULL; + /* Cached attributes */ +static cups_array_t *state_reasons; /* Array of printe-state-reasons keywords */ +static char tmpfilename[1024] = ""; + /* Temporary spool file name */ /* * Local functions... */ -static void cancel_job(http_t *http, const char *uri, int id, - const char *resource, const char *user, int version); -static void check_printer_state(http_t *http, const char *uri, - const char *resource, const char *user, - int version, int job_id); +static void cancel_job(http_t *http, const char *uri, int id, + const char *resource, const char *user, + int version); +static ipp_pstate_t check_printer_state(http_t *http, const char *uri, + const char *resource, + const char *user, int version); #ifdef HAVE_LIBZ -static void compress_files(int num_files, char **files); +static void compress_files(int num_files, char **files); #endif /* HAVE_LIBZ */ -static const char *password_cb(const char *); -static void report_attr(ipp_attribute_t *attr); -static int report_printer_state(ipp_t *ipp, int job_id); - -#ifdef __APPLE__ -static int run_pictwps_filter(char **argv, const char *filename); -#endif /* __APPLE__ */ -static void sigterm_handler(int sig); +static void *monitor_printer(_cups_monitor_t *monitor); +static ipp_t *new_request(ipp_op_t op, int version, const char *uri, + const char *user, const char *title, + int num_options, cups_option_t *options, + const char *compression, int copies, + const char *format, _ppd_cache_t *pc, + ipp_attribute_t *media_col_sup, + ipp_attribute_t *doc_handling_sup); +static const char *password_cb(const char *); +static void report_attr(ipp_attribute_t *attr); +static void report_printer_state(ipp_t *ipp); +#if defined(HAVE_GSSAPI) && defined(HAVE_XPC) +static int run_as_user(int argc, char *argv[], uid_t uid, + const char *device_uri, int fd); +#endif /* HAVE_GSSAPI && HAVE_XPC */ +static void sigterm_handler(int sig); +static int timeout_cb(http_t *http, void *user_data); +static void update_reasons(ipp_attribute_t *attr, const char *s); /* @@ -102,65 +193,60 @@ main(int argc, /* I - Number of command-line args */ *name, /* Name of option */ *value, /* Value of option */ sep; /* Separator character */ + http_addrlist_t *addrlist; /* Address of printer */ int snmp_fd, /* SNMP socket */ start_count, /* Page count via SNMP at start */ page_count, /* Page count via SNMP */ have_supplies; /* Printer supports supply levels? */ int num_files; /* Number of files to print */ char **files, /* Files to print */ - *filename; /* Pointer to single filename */ + *compatfile = NULL; /* Compatibility filename */ + off_t compatsize = 0; /* Size of compatibility file */ int port; /* Port number (not used) */ + char portname[255]; /* Port name */ char uri[HTTP_MAX_URI]; /* Updated URI without user/pass */ + http_status_t http_status; /* Status of HTTP request */ ipp_status_t ipp_status; /* Status of IPP request */ http_t *http; /* HTTP connection */ ipp_t *request, /* IPP request */ *response, /* IPP response */ *supported; /* get-printer-attributes response */ time_t start_time; /* Time of first connect */ - int recoverable; /* Recoverable error shown? */ int contimeout; /* Connection timeout */ - int delay; /* Delay for retries... */ - int compression, /* Do compression of the job data? */ - waitjob, /* Wait for job complete? */ + int delay, /* Delay for retries */ + prev_delay; /* Previous delay */ + const char *compression; /* Compression mode */ + int waitjob, /* Wait for job complete? */ waitprinter; /* Wait for printer ready? */ + _cups_monitor_t monitor; /* Monitoring data */ ipp_attribute_t *job_id_attr; /* job-id attribute */ int job_id; /* job-id value */ ipp_attribute_t *job_sheets; /* job-media-sheets-completed */ ipp_attribute_t *job_state; /* job-state */ ipp_attribute_t *copies_sup; /* copies-supported */ + ipp_attribute_t *cups_version; /* cups-version */ ipp_attribute_t *format_sup; /* document-format-supported */ + ipp_attribute_t *media_col_sup; /* media-col-supported */ + ipp_attribute_t *operations_sup; /* operations-supported */ + 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 copies, /* Number of copies for job */ copies_remaining; /* Number of copies remaining */ const char *content_type, /* CONTENT_TYPE environment variable */ - *final_content_type; /* FINAL_CONTENT_TYPE environment var */ + *final_content_type, /* FINAL_CONTENT_TYPE environment var */ + *document_format; /* document-format value */ + int fd; /* File descriptor */ + off_t bytes = 0; /* Bytes copied */ + char buffer[16384]; /* Copy buffer */ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) struct sigaction action; /* Actions for POSIX signals */ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ int version; /* IPP version */ - static const char * const pattrs[] = - { /* Printer attributes we want */ - "com.apple.print.recoverable-message", - "copies-supported", - "document-format-supported", - "marker-colors", - "marker-high-levels", - "marker-levels", - "marker-low-levels", - "marker-message", - "marker-names", - "marker-types", - "printer-is-accepting-jobs", - "printer-state", - "printer-state-message", - "printer-state-reasons", - }; - static const char * const jattrs[] = - { /* Job attributes we want */ - "job-media-sheets-completed", - "job-state" - }; + ppd_file_t *ppd; /* PPD file */ + _ppd_cache_t *pc; /* PPD cache and mapping data */ + fd_set input; /* Input set for select() */ /* @@ -211,12 +297,75 @@ main(int argc, /* I - Number of command-line args */ else if (argc < 6) { _cupsLangPrintf(stderr, - _("Usage: %s job-id user title copies options [file]\n"), + _("Usage: %s job-id user title copies options [file]"), argv[0]); return (CUPS_BACKEND_STOP); } /* + * Get the device URI... + */ + + while ((device_uri = cupsBackendDeviceURI(argv)) == NULL) + { + _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer.")); + sleep(10); + + if (getenv("CLASS") != NULL) + return (CUPS_BACKEND_FAILED); + } + + if ((auth_info_required = getenv("AUTH_INFO_REQUIRED")) == NULL) + auth_info_required = "none"; + + state_reasons = _cupsArrayNewStrings(getenv("PRINTER_STATE_REASONS")); + +#ifdef HAVE_GSSAPI + /* + * For Kerberos, become the printing user (if we can) to get the credentials + * that way. + */ + + if (!getuid() && (value = getenv("AUTH_UID")) != NULL) + { + uid_t uid = (uid_t)atoi(value); + /* User ID */ + +# ifdef HAVE_XPC + if (uid > 0) + { + if (argc == 6) + return (run_as_user(argc, argv, uid, device_uri, 0)); + else + { + int status = 0; /* Exit status */ + + for (i = 6; i < argc && !status && !job_canceled; i ++) + { + if ((fd = open(argv[i], O_RDONLY)) >= 0) + { + status = run_as_user(argc, argv, uid, device_uri, fd); + close(fd); + } + else + { + _cupsLangPrintError("ERROR", _("Unable to open print file")); + status = CUPS_BACKEND_FAILED; + } + } + + return (status); + } + } + +# else /* No XPC, just try to run as the user ID */ + if (uid > 0) + seteuid(uid); +# endif /* HAVE_XPC */ + } +#endif /* HAVE_GSSAPI */ + + /* * Get the (final) content type... */ @@ -235,9 +384,6 @@ main(int argc, /* I - Number of command-line args */ * Extract the hostname and printer name from the URI... */ - if ((device_uri = cupsBackendDeviceURI(argv)) == NULL) - return (CUPS_BACKEND_FAILED); - httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); @@ -254,8 +400,8 @@ main(int argc, /* I - Number of command-line args */ * See if there are any options... */ - compression = 0; - version = 11; + compression = NULL; + version = 20; waitjob = 1; waitprinter = 1; contimeout = 7 * 24 * 60 * 60; @@ -308,48 +454,48 @@ main(int argc, /* I - Number of command-line args */ * Process the option... */ - if (!strcasecmp(name, "waitjob")) + if (!_cups_strcasecmp(name, "waitjob")) { /* * Wait for job completion? */ - waitjob = !strcasecmp(value, "on") || - !strcasecmp(value, "yes") || - !strcasecmp(value, "true"); + waitjob = !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "yes") || + !_cups_strcasecmp(value, "true"); } - else if (!strcasecmp(name, "waitprinter")) + else if (!_cups_strcasecmp(name, "waitprinter")) { /* * Wait for printer idle? */ - waitprinter = !strcasecmp(value, "on") || - !strcasecmp(value, "yes") || - !strcasecmp(value, "true"); + waitprinter = !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "yes") || + !_cups_strcasecmp(value, "true"); } - else if (!strcasecmp(name, "encryption")) + else if (!_cups_strcasecmp(name, "encryption")) { /* * Enable/disable encryption? */ - if (!strcasecmp(value, "always")) + if (!_cups_strcasecmp(value, "always")) cupsSetEncryption(HTTP_ENCRYPT_ALWAYS); - else if (!strcasecmp(value, "required")) + else if (!_cups_strcasecmp(value, "required")) cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); - else if (!strcasecmp(value, "never")) + else if (!_cups_strcasecmp(value, "never")) cupsSetEncryption(HTTP_ENCRYPT_NEVER); - else if (!strcasecmp(value, "ifrequested")) + else if (!_cups_strcasecmp(value, "ifrequested")) cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED); else { - _cupsLangPrintf(stderr, - _("ERROR: Unknown encryption option value \"%s\"!\n"), - value); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unknown encryption option value: \"%s\"."), + value); } } - else if (!strcasecmp(name, "version")) + else if (!_cups_strcasecmp(name, "version")) { if (!strcmp(value, "1.0")) version = 10; @@ -359,23 +505,24 @@ main(int argc, /* I - Number of command-line args */ version = 20; else if (!strcmp(value, "2.1")) version = 21; + else if (!strcmp(value, "2.2")) + version = 22; else { - _cupsLangPrintf(stderr, - _("ERROR: Unknown version option value \"%s\"!\n"), - value); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unknown version option value: \"%s\"."), + value); } } #ifdef HAVE_LIBZ - else if (!strcasecmp(name, "compression")) + else if (!_cups_strcasecmp(name, "compression")) { - compression = !strcasecmp(value, "true") || - !strcasecmp(value, "yes") || - !strcasecmp(value, "on") || - !strcasecmp(value, "gzip"); + if (!_cups_strcasecmp(value, "true") || !_cups_strcasecmp(value, "yes") || + !_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "gzip")) + compression = "gzip"; } #endif /* HAVE_LIBZ */ - else if (!strcasecmp(name, "contimeout")) + else if (!_cups_strcasecmp(name, "contimeout")) { /* * Set the connection timeout... @@ -390,9 +537,9 @@ main(int argc, /* I - Number of command-line args */ * Unknown option... */ - _cupsLangPrintf(stderr, - _("ERROR: Unknown option \"%s\" with value \"%s\"!\n"), - name, value); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unknown option \"%s\" with value \"%s\"."), + name, value); } } } @@ -405,64 +552,13 @@ main(int argc, /* I - Number of command-line args */ if (argc == 6) { - /* - * Copy stdin to a temporary file... - */ + num_files = 0; + files = NULL; + send_options = !_cups_strcasecmp(final_content_type, "application/pdf") || + !_cups_strcasecmp(final_content_type, "application/vnd.cups-pdf") || + !_cups_strncasecmp(final_content_type, "image/", 6); - int fd; /* File descriptor */ - http_addrlist_t *addrlist; /* Address list */ - off_t tbytes; /* Total bytes copied */ - - - fputs("STATE: +connecting-to-device\n", stderr); - fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname); - - if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, "1")) == NULL) - { - _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"), - hostname); - return (CUPS_BACKEND_STOP); - } - - snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family); - - if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0) - { - _cupsLangPrintError(_("ERROR: Unable to create temporary file")); - return (CUPS_BACKEND_FAILED); - } - - _cupsLangPuts(stderr, _("INFO: Copying print data...\n")); - - tbytes = backendRunLoop(-1, fd, snmp_fd, &(addrlist->addr), 0, 0, - backendNetworkSideCB); - - if (snmp_fd >= 0) - _cupsSNMPClose(snmp_fd); - - httpAddrFreeList(addrlist); - - close(fd); - - /* - * Don't try printing files less than 2 bytes... - */ - - if (tbytes <= 1) - { - _cupsLangPuts(stderr, _("ERROR: Empty print file!\n")); - unlink(tmpfilename); - return (CUPS_BACKEND_FAILED); - } - - /* - * Point to the single file from stdin... - */ - - filename = tmpfilename; - num_files = 1; - files = &filename; - send_options = 0; + fputs("DEBUG: Sending stdin for job...\n", stderr); } else { @@ -478,9 +574,9 @@ main(int argc, /* I - Number of command-line args */ if (compression) compress_files(num_files, files); #endif /* HAVE_LIBZ */ - } - fprintf(stderr, "DEBUG: %d files to send in job...\n", num_files); + fprintf(stderr, "DEBUG: %d files to send in job...\n", num_files); + } /* * Set the authentication info, if any... @@ -499,7 +595,7 @@ main(int argc, /* I - Number of command-line args */ cupsSetUser(username); } - else if (!getuid()) + else { /* * Try loading authentication information from the environment. @@ -514,23 +610,75 @@ main(int argc, /* I - Number of command-line args */ } /* - * Try connecting to the remote server... + * Try finding the remote server... */ - delay = 5; - recoverable = 0; - start_time = time(NULL); + start_time = time(NULL); + + sprintf(portname, "%d", port); + + update_reasons(NULL, "+connecting-to-device"); + fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname); - fputs("STATE: +connecting-to-device\n", stderr); + while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) + { + _cupsLangPrintFilter(stderr, "INFO", + _("Unable to locate printer \"%s\"."), hostname); + sleep(10); + + if (getenv("CLASS") != NULL) + { + update_reasons(NULL, "-connecting-to-device"); + return (CUPS_BACKEND_STOP); + } + } + + http = _httpCreate(hostname, port, addrlist, cupsEncryption(), AF_UNSPEC); + httpSetTimeout(http, 30.0, timeout_cb, NULL); + + /* + * See if the printer supports SNMP... + */ + + if ((snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family)) >= 0) + { + have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr), + &start_count, NULL); + } + else + have_supplies = start_count = 0; + + /* + * Wait for data from the filter... + */ + + if (num_files == 0) + { + if (!backendWaitLoop(snmp_fd, &(addrlist->addr), 0, backendNetworkSideCB)) + return (CUPS_BACKEND_OK); + else if ((bytes = read(0, buffer, sizeof(buffer))) <= 0) + return (CUPS_BACKEND_OK); + } + + /* + * Try connecting to the remote server... + */ + + delay = _cupsNextDelay(0, &prev_delay); do { fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port); - _cupsLangPuts(stderr, _("INFO: Connecting to printer...\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer.")); - if ((http = httpConnectEncrypt(hostname, port, cupsEncryption())) == NULL) + if (httpReconnect(http)) { - if (job_cancelled) + int error = errno; /* Connection error */ + + if (http->status == HTTP_PKI_ERROR) + update_reasons(NULL, "+cups-certificate-error"); + + if (job_canceled) break; if (getenv("CLASS") != NULL) @@ -542,12 +690,9 @@ main(int argc, /* I - Number of command-line args */ * available printer in the class. */ - _cupsLangPuts(stderr, - _("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); - - if (tmpfilename[0]) - unlink(tmpfilename); + _cupsLangPrintFilter(stderr, "INFO", + _("Unable to contact printer, queuing on next " + "printer in class.")); /* * Sleep 5 seconds to keep the job from requeuing too rapidly... @@ -555,85 +700,73 @@ main(int argc, /* I - Number of command-line args */ sleep(5); + update_reasons(NULL, "-connecting-to-device"); + return (CUPS_BACKEND_FAILED); } + fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno)); + if (errno == ECONNREFUSED || errno == EHOSTDOWN || errno == EHOSTUNREACH) { if (contimeout && (time(NULL) - start_time) > contimeout) { - _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("The printer is not responding.")); + update_reasons(NULL, "-connecting-to-device"); return (CUPS_BACKEND_FAILED); } - recoverable = 1; - - _cupsLangPrintf(stderr, - _("WARNING: recoverable: Network host \'%s\' is busy; " - "will retry in %d seconds...\n"), - hostname, delay); + switch (error) + { + case EHOSTDOWN : + _cupsLangPrintFilter(stderr, "WARNING", + _("The printer may not exist or " + "is unavailable at this time.")); + break; + + case EHOSTUNREACH : + _cupsLangPrintFilter(stderr, "WARNING", + _("The printer is unreachable at this " + "time.")); + break; + + case ECONNREFUSED : + default : + _cupsLangPrintFilter(stderr, "WARNING", + _("The printer is busy.")); + break; + } sleep(delay); - if (delay < 30) - delay += 5; - } - else if (h_errno) - { - _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"), - hostname); - return (CUPS_BACKEND_STOP); + delay = _cupsNextDelay(delay, &prev_delay); } else { - recoverable = 1; - - fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno)); - _cupsLangPuts(stderr, - _("ERROR: recoverable: Unable to connect to printer; will " - "retry in 30 seconds...\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("The printer is not responding.")); sleep(30); } - if (job_cancelled) + if (job_canceled) break; } + else + update_reasons(NULL, "-cups-certificate-error"); } - while (http == NULL); - - if (job_cancelled || !http) - { - if (tmpfilename[0]) - unlink(tmpfilename); + while (http->fd < 0); + if (job_canceled || !http) return (CUPS_BACKEND_FAILED); - } - fputs("STATE: -connecting-to-device\n", stderr); - _cupsLangPuts(stderr, _("INFO: Connected to printer...\n")); + update_reasons(NULL, "-connecting-to-device"); + _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer.")); -#ifdef AF_INET6 - if (http->hostaddr->addr.sa_family == AF_INET6) - fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6)...\n", - httpAddrString(http->hostaddr, addrname, sizeof(addrname)), - ntohs(http->hostaddr->ipv6.sin6_port)); - else -#endif /* AF_INET6 */ - if (http->hostaddr->addr.sa_family == AF_INET) - fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4)...\n", - httpAddrString(http->hostaddr, addrname, sizeof(addrname)), - ntohs(http->hostaddr->ipv4.sin_port)); - - /* - * See if the printer supports SNMP... - */ - - if ((snmp_fd = _cupsSNMPOpen(http->hostaddr->addr.sa_family)) >= 0) - have_supplies = !backendSNMPSupplies(snmp_fd, http->hostaddr, &start_count, - NULL); - else - have_supplies = start_count = 0; + fprintf(stderr, "DEBUG: Connected to %s:%d...\n", + httpAddrString(http->hostaddr, addrname, sizeof(addrname)), + _httpAddrPort(http->hostaddr)); /* * Build a URI for the printer and fill the standard IPP attributes for @@ -646,13 +779,17 @@ main(int argc, /* I - Number of command-line args */ /* * First validate the destination and see if the device supports multiple - * copies. We have to do this because some IPP servers (e.g. HP JetDirect) - * don't support the copies attribute... + * copies... */ - copies_sup = NULL; - format_sup = NULL; - supported = NULL; + copies_sup = NULL; + cups_version = NULL; + format_sup = NULL; + media_col_sup = NULL; + supported = NULL; + operations_sup = NULL; + doc_handling_sup = NULL; + validate_job = 0; do { @@ -684,57 +821,73 @@ main(int argc, /* I - Number of command-line args */ fputs("DEBUG: Getting supported attributes...\n", stderr); if (http->version < HTTP_1_1) - httpReconnect(http); + { + fprintf(stderr, "DEBUG: Printer responded with HTTP version %d.%d.\n", + http->version / 100, http->version % 100); + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-wrong-http-version"); + } - if ((supported = cupsDoRequest(http, request, resource)) == NULL) - ipp_status = cupsLastError(); - else - ipp_status = supported->request.status.status_code; + supported = cupsDoRequest(http, request, resource); + ipp_status = cupsLastError(); + + fprintf(stderr, "DEBUG: Get-Printer-Attributes: %s (%s)\n", + ippErrorString(ipp_status), cupsLastErrorString()); if (ipp_status > IPP_OK_CONFLICT) { + fprintf(stderr, "DEBUG: Get-Printer-Attributes returned %s.\n", + ippErrorString(ipp_status)); + if (ipp_status == IPP_PRINTER_BUSY || ipp_status == IPP_SERVICE_UNAVAILABLE) { if (contimeout && (time(NULL) - start_time) > contimeout) { - _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("The printer is not responding.")); return (CUPS_BACKEND_FAILED); } - recoverable = 1; - - _cupsLangPrintf(stderr, - _("WARNING: recoverable: Network host \'%s\' is busy; " - "will retry in %d seconds...\n"), - hostname, delay); + _cupsLangPrintFilter(stderr, "INFO", _("The printer is busy.")); - report_printer_state(supported, 0); + report_printer_state(supported); sleep(delay); - if (delay < 30) - delay += 5; + delay = _cupsNextDelay(delay, &prev_delay); } else if ((ipp_status == IPP_BAD_REQUEST || ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10) { /* - * Switch to IPP/1.0... + * Switch to IPP/1.1 or IPP/1.0... */ - _cupsLangPrintf(stderr, - _("INFO: Printer does not support IPP/%d.%d, trying " - "IPP/1.0...\n"), version / 10, version % 10); - version = 10; + if (version >= 20) + { + _cupsLangPrintFilter(stderr, "INFO", + _("Printer does not support IPP/%d.%d, trying " + "IPP/%s."), version / 10, version % 10, "1.1"); + version = 11; + } + else + { + _cupsLangPrintFilter(stderr, "INFO", + _("Printer does not support IPP/%d.%d, trying " + "IPP/%s."), version / 10, version % 10, "1.0"); + version = 10; + } + httpReconnect(http); } else if (ipp_status == IPP_NOT_FOUND) { - _cupsLangPuts(stderr, _("ERROR: Destination printer does not exist!\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("The printer URI is incorrect or no longer " + "exists.")); - if (supported) - ippDelete(supported); + ippDelete(supported); return (CUPS_BACKEND_STOP); } @@ -749,33 +902,92 @@ main(int argc, /* I - Number of command-line args */ } else { - _cupsLangPrintf(stderr, - _("ERROR: Unable to get printer status (%s)!\n"), - cupsLastErrorString()); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to get printer status.")); sleep(10); } - if (supported) - ippDelete(supported); - + ippDelete(supported); + supported = NULL; continue; } - else if ((copies_sup = ippFindAttribute(supported, "copies-supported", - IPP_TAG_RANGE)) != NULL) + + if (!getenv("CLASS")) + { + /* + * Check printer-is-accepting-jobs = false and printer-state-reasons for the + * "spool-area-full" keyword... + */ + + int busy = 0; + + if ((printer_accepting = ippFindAttribute(supported, + "printer-is-accepting-jobs", + IPP_TAG_BOOLEAN)) != NULL && + !printer_accepting->values[0].boolean) + busy = 1; + else if (!printer_accepting) + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-missing-printer-is-accepting-jobs"); + + if ((printer_state = ippFindAttribute(supported, + "printer-state-reasons", + IPP_TAG_KEYWORD)) != NULL && !busy) + { + for (i = 0; i < printer_state->num_values; i ++) + if (!strcmp(printer_state->values[0].string.text, + "spool-area-full") || + !strncmp(printer_state->values[0].string.text, "spool-area-full-", + 16)) + { + busy = 1; + break; + } + } + else + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-missing-printer-state-reasons"); + + if (busy) + { + _cupsLangPrintFilter(stderr, "INFO", _("The printer is busy.")); + + report_printer_state(supported); + + sleep(delay); + + delay = _cupsNextDelay(delay, &prev_delay); + + ippDelete(supported); + supported = NULL; + continue; + } + } + + /* + * Check for supported attributes... + */ + + if ((copies_sup = ippFindAttribute(supported, "copies-supported", + IPP_TAG_RANGE)) != NULL) { /* * Has the "copies-supported" attribute - does it have an upper * bound > 1? */ + fprintf(stderr, "DEBUG: copies-supported=%d-%d\n", + copies_sup->values[0].range.lower, + copies_sup->values[0].range.upper); + if (copies_sup->values[0].range.upper <= 1) copies_sup = NULL; /* No */ } - format_sup = ippFindAttribute(supported, "document-format-supported", - IPP_TAG_MIMETYPE); + cups_version = ippFindAttribute(supported, "cups-version", IPP_TAG_TEXT); - if (format_sup) + if ((format_sup = ippFindAttribute(supported, "document-format-supported", + IPP_TAG_MIMETYPE)) != NULL) { fprintf(stderr, "DEBUG: document-format-supported (%d values)\n", format_sup->num_values); @@ -784,7 +996,71 @@ main(int argc, /* I - Number of command-line args */ format_sup->values[i].string.text); } - report_printer_state(supported, 0); + if ((media_col_sup = ippFindAttribute(supported, "media-col-supported", + IPP_TAG_KEYWORD)) != NULL) + { + fprintf(stderr, "DEBUG: media-col-supported (%d values)\n", + media_col_sup->num_values); + for (i = 0; i < media_col_sup->num_values; i ++) + fprintf(stderr, "DEBUG: [%d] = \"%s\"\n", i, + media_col_sup->values[i].string.text); + } + + if ((operations_sup = ippFindAttribute(supported, "operations-supported", + IPP_TAG_ENUM)) != NULL) + { + for (i = 0; i < operations_sup->num_values; i ++) + if (operations_sup->values[i].integer == IPP_PRINT_JOB) + break; + + if (i >= operations_sup->num_values) + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-missing-print-job"); + + for (i = 0; i < operations_sup->num_values; i ++) + if (operations_sup->values[i].integer == IPP_CANCEL_JOB) + break; + + if (i >= operations_sup->num_values) + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-missing-cancel-job"); + + for (i = 0; i < operations_sup->num_values; i ++) + if (operations_sup->values[i].integer == IPP_GET_JOB_ATTRIBUTES) + break; + + if (i >= operations_sup->num_values) + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-missing-get-job-attributes"); + + for (i = 0; i < operations_sup->num_values; i ++) + if (operations_sup->values[i].integer == IPP_GET_PRINTER_ATTRIBUTES) + break; + + if (i >= operations_sup->num_values) + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "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; + } + + if (!validate_job) + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-missing-validate-job"); + } + else + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-missing-operations-supported"); + + doc_handling_sup = ippFindAttribute(supported, + "multiple-document-handling-supported", + IPP_TAG_KEYWORD); + + report_printer_state(supported); } while (ipp_status > IPP_OK_CONFLICT); @@ -813,16 +1089,13 @@ main(int argc, /* I - Number of command-line args */ * available printer in the class. */ - _cupsLangPuts(stderr, - _("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Unable to contact printer, queuing on next " + "printer in class.")); ippDelete(supported); httpClose(http); - if (tmpfilename[0]) - unlink(tmpfilename); - /* * Sleep 5 seconds to keep the job from requeuing too rapidly... */ @@ -833,18 +1106,6 @@ main(int argc, /* I - Number of command-line args */ } } - if (recoverable) - { - /* - * If we've shown a recoverable error make sure the printer proxies - * have a chance to see the recovered message. Not pretty but - * necessary for now... - */ - - fputs("INFO: recovered: \n", stderr); - sleep(5); - } - /* * See if the printer supports multiple copies... */ @@ -855,201 +1116,296 @@ main(int argc, /* I - Number of command-line args */ { copies_remaining = 1; - if (argc < 7) + if (argc < 7 && !send_options) copies = 1; } else copies_remaining = copies; /* - * Then issue the print-job request... + * Prepare remaining printing options... */ - job_id = 0; + options = NULL; + pc = NULL; - while (copies_remaining > 0) + if (send_options) { - /* - * Check for side-channel requests... - */ + num_options = cupsParseOptions(argv[5], 0, &options); - backendCheckSideChannel(snmp_fd, http->hostaddr); + if (!cups_version && media_col_sup) + { + /* + * Load the PPD file and generate PWG attribute mapping information... + */ - /* - * Build the IPP request... - */ + ppd = ppdOpenFile(getenv("PPD")); + pc = _ppdCacheCreateWithPPD(ppd); - if (job_cancelled) - break; + ppdClose(ppd); + } + } + else + num_options = 0; - if (num_files > 1) - request = ippNewRequest(IPP_CREATE_JOB); - else - request = ippNewRequest(IPP_PRINT_JOB); + document_format = NULL; - request->request.op.version[0] = version / 10; - request->request.op.version[1] = version % 10; + 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)) + { + document_format = final_content_type; + break; + } - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); + if (!document_format) + { + for (i = 0; i < format_sup->num_values; i ++) + if (!_cups_strcasecmp("application/octet-stream", + format_sup->values[i].string.text)) + { + document_format = "application/octet-stream"; + break; + } + } + } - fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri); + /* + * 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... + * + * (I hate compatibility hacks!) + */ - if (argv[2][0]) - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, - "requesting-user-name", NULL, argv[2]); + if (http->version < HTTP_1_1 && num_files == 0) + { + if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0) + { + perror("DEBUG: Unable to create temporary file"); + return (CUPS_BACKEND_FAILED); + } - fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]); + _cupsLangPrintFilter(stderr, "INFO", _("Copying print data.")); - /* - * Only add a "job-name" attribute if the remote server supports - * copy generation - some IPP implementations like HP's don't seem - * to like UTF-8 job names (STR #1837)... - */ + compatsize = backendRunLoop(-1, fd, snmp_fd, &(addrlist->addr), 0, 0, + backendNetworkSideCB); - if (argv[3][0] && copies_sup) - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, - argv[3]); + close(fd); - fprintf(stderr, "DEBUG: job-name = \"%s\"\n", argv[3]); + compatfile = tmpfilename; + files = &compatfile; + num_files = 1; + } + else if (http->version < HTTP_1_1 && num_files == 1) + { + struct stat fileinfo; /* File information */ -#ifdef HAVE_LIBZ - if (compression) - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "compression", NULL, "gzip"); -#endif /* HAVE_LIBZ */ + if (!stat(files[0], &fileinfo)) + compatsize = fileinfo.st_size; + } - /* - * Handle options on the command-line... - */ + /* + * Start monitoring the printer in the background... + */ - options = NULL; - num_options = cupsParseOptions(argv[5], 0, &options); + monitor.uri = uri; + monitor.hostname = hostname; + monitor.user = argv[2]; + monitor.resource = resource; + monitor.port = port; + monitor.version = version; + monitor.job_id = 0; + monitor.encryption = cupsEncryption(); + monitor.job_state = IPP_JOB_PENDING; + monitor.printer_state = IPP_PRINTER_IDLE; -#ifdef __APPLE__ - if (!strcasecmp(final_content_type, "application/pictwps") && - num_files == 1) - { - if (format_sup != NULL) - { - for (i = 0; i < format_sup->num_values; i ++) - if (!strcasecmp(final_content_type, format_sup->values[i].string.text)) - break; - } + _cupsThreadCreate((_cups_thread_func_t)monitor_printer, &monitor); - if (format_sup == NULL || i >= format_sup->num_values) - { - /* - * Remote doesn't support "application/pictwps" (i.e. it's not MacOS X) - * so convert the document to PostScript... - */ + /* + * Validate access to the printer... + */ - if (run_pictwps_filter(argv, files[0])) - { - if (pstmpname[0]) - unlink(pstmpname); + while (!job_canceled && validate_job) + { + request = new_request(IPP_VALIDATE_JOB, version, uri, argv[2], argv[3], + num_options, options, compression, + copies_sup ? copies : 1, document_format, pc, + media_col_sup, doc_handling_sup); - if (tmpfilename[0]) - unlink(tmpfilename); + ippDelete(cupsDoRequest(http, request, resource)); - return (CUPS_BACKEND_FAILED); - } + ipp_status = cupsLastError(); - files[0] = pstmpname; + fprintf(stderr, "DEBUG: Validate-Job: %s (%s)\n", + ippErrorString(ipp_status), cupsLastErrorString()); - /* - * Change the MIME type to application/postscript and change the - * number of copies to 1... - */ + if (job_canceled) + break; - final_content_type = "application/postscript"; - copies = 1; - copies_remaining = 1; - send_options = 0; - } + if (ipp_status == IPP_SERVICE_UNAVAILABLE || ipp_status == IPP_PRINTER_BUSY) + { + _cupsLangPrintFilter(stderr, "INFO", _("The printer is busy.")); + sleep(10); } -#endif /* __APPLE__ */ - - if (format_sup != NULL) + else if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN || + ipp_status == IPP_AUTHENTICATION_CANCELED) { - for (i = 0; i < format_sup->num_values; i ++) - if (!strcasecmp(final_content_type, format_sup->values[i].string.text)) - break; + /* + * Update auth-info-required as needed... + */ - if (i < format_sup->num_values) - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, - "document-format", NULL, final_content_type); - } + fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n", + httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE)); - if (copies_sup && version > 10 && send_options) - { /* - * Only send options if the destination printer supports the copies - * attribute and IPP/1.1. This is a hack for the HP and Lexmark - * implementations of IPP, which do not accept extension attributes - * and incorrectly report a client-error-bad-request error instead of - * the successful-ok-unsupported-attributes status. In short, at least - * some HP and Lexmark implementations of IPP are non-compliant. + * 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... */ - cupsEncodeOptions(request, num_options, options); + if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE), + "Negotiate", 9)) + auth_info_required = "negotiate"; - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", - copies); + goto cleanup; } + else if (ipp_status == IPP_OPERATION_NOT_SUPPORTED) + { + /* + * This is all too common... + */ + + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-missing-validate-job"); + break; + } + else if (ipp_status < IPP_REDIRECTION_OTHER_SITE) + break; + } - cupsFreeOptions(num_options, options); + /* + * Then issue the print-job request... + */ + job_id = 0; + + while (!job_canceled && copies_remaining > 0) + { /* - * If copies aren't supported, then we are likely dealing with an HP - * JetDirect. The HP IPP implementation seems to close the connection - * after every request - that is, it does *not* implement HTTP Keep- - * Alive, which is REQUIRED by HTTP/1.1... + * Check for side-channel requests... */ - if (!copies_sup) - httpReconnect(http); + backendCheckSideChannel(snmp_fd, http->hostaddr); /* - * Do the request... + * Build the IPP job creation request... */ - if (http->version < HTTP_1_1) - httpReconnect(http); + 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); + + /* + * Do the request... + */ if (num_files > 1) response = cupsDoRequest(http, request, resource); else - response = cupsDoFileRequest(http, request, resource, files[0]); + { + size_t length = 0; /* Length of request */ + + if (compatsize > 0) + { + fputs("DEBUG: Sending file using HTTP/1.0 Content-Length...\n", stderr); + length = ippLength(request) + (size_t)compatsize; + } + else + fputs("DEBUG: Sending file using HTTP/1.1 chunking...\n", stderr); + + http_status = cupsSendRequest(http, request, resource, length); + if (http_status == HTTP_CONTINUE && request->state == IPP_DATA) + { + if (num_files == 1) + fd = open(files[0], O_RDONLY); + else + { + fd = 0; + http_status = cupsWriteRequestData(http, buffer, bytes); + } + + while (http_status == HTTP_CONTINUE) + { + /* + * Check for side-channel requests and more print data... + */ + + FD_ZERO(&input); + FD_SET(fd, &input); + FD_SET(snmp_fd, &input); + + while (select(fd > snmp_fd ? fd + 1 : snmp_fd + 1, &input, NULL, NULL, + NULL) <= 0 && !job_canceled); + + if (FD_ISSET(snmp_fd, &input)) + backendCheckSideChannel(snmp_fd, http->hostaddr); + + if (FD_ISSET(fd, &input)) + { + if ((bytes = read(fd, buffer, sizeof(buffer))) > 0) + { + fprintf(stderr, "DEBUG: Read %d bytes...\n", (int)bytes); + + if (cupsWriteRequestData(http, buffer, bytes) != HTTP_CONTINUE) + break; + } + else if (bytes == 0 || (errno != EINTR && errno != EAGAIN)) + break; + } + } + + if (num_files == 1) + close(fd); + } + + response = cupsGetResponse(http, resource); + ippDelete(request); + } ipp_status = cupsLastError(); + fprintf(stderr, "DEBUG: %s: %s (%s)\n", + num_files > 1 ? "Create-Job" : "Print-Job", + ippErrorString(ipp_status), cupsLastErrorString()); + if (ipp_status > IPP_OK_CONFLICT) { job_id = 0; - if (job_cancelled) + if (job_canceled) break; if (ipp_status == IPP_SERVICE_UNAVAILABLE || ipp_status == IPP_PRINTER_BUSY) { - _cupsLangPuts(stderr, - _("INFO: Printer busy; will retry in 10 seconds...\n")); + _cupsLangPrintFilter(stderr, "INFO", _("The printer is busy.")); sleep(10); - } - else if ((ipp_status == IPP_BAD_REQUEST || - ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10) - { - /* - * Switch to IPP/1.0... - */ - _cupsLangPrintf(stderr, - _("INFO: Printer does not support IPP/%d.%d, trying " - "IPP/1.0...\n"), version / 10, version % 10); - version = 10; - httpReconnect(http); + if (num_files == 0) + { + /* + * We can't re-submit when we have no files to print, so exit + * immediately with the right status code... + */ + + goto cleanup; + } } else { @@ -1057,8 +1413,8 @@ main(int argc, /* I - Number of command-line args */ * Update auth-info-required as needed... */ - _cupsLangPrintf(stderr, _("ERROR: Print file was not accepted (%s)!\n"), - cupsLastErrorString()); + _cupsLangPrintFilter(stderr, "ERROR", + _("Print file was not accepted.")); if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN) { @@ -1076,25 +1432,39 @@ main(int argc, /* I - Number of command-line args */ "Negotiate", 9)) auth_info_required = "negotiate"; } + else + sleep(10); + + if (num_files == 0) + { + /* + * We can't re-submit when we have no files to print, so exit + * immediately with the right status code... + */ + + goto cleanup; + } } } else if ((job_id_attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL) { - _cupsLangPuts(stderr, - _("NOTICE: Print file accepted - job ID unknown.\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Print file accepted - job ID unknown.")); + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-missing-job-id"); job_id = 0; } else { - job_id = job_id_attr->values[0].integer; - _cupsLangPrintf(stderr, _("NOTICE: Print file accepted - job ID %d.\n"), - job_id); + monitor.job_id = job_id = job_id_attr->values[0].integer; + _cupsLangPrintFilter(stderr, "INFO", + _("Print file accepted - job ID %d."), job_id); } ippDelete(response); - if (job_cancelled) + if (job_canceled) break; if (job_id && num_files > 1) @@ -1131,18 +1501,40 @@ main(int argc, /* I - Number of command-line args */ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, content_type); - if (http->version < HTTP_1_1) - httpReconnect(http); + 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) + { + while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) + { + if (cupsWriteRequestData(http, buffer, bytes) != HTTP_CONTINUE) + break; + else + { + /* + * Check for side-channel requests... + */ + + backendCheckSideChannel(snmp_fd, http->hostaddr); + } + } + + close(fd); + } - ippDelete(cupsDoFileRequest(http, request, resource, files[i])); + ippDelete(cupsGetResponse(http, resource)); + ippDelete(request); + + fprintf(stderr, "DEBUG: Send-Document: %s (%s)\n", + ippErrorString(cupsLastError()), cupsLastErrorString()); if (cupsLastError() > IPP_OK_CONFLICT) { ipp_status = cupsLastError(); - _cupsLangPrintf(stderr, - _("ERROR: Unable to add file %d to job: %s\n"), - job_id, cupsLastErrorString()); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to add document to print job.")); break; } } @@ -1166,9 +1558,9 @@ main(int argc, /* I - Number of command-line args */ if (!job_id || !waitjob) continue; - _cupsLangPuts(stderr, _("INFO: Waiting for job to complete...\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Waiting for job to complete.")); - for (delay = 1; !job_cancelled;) + for (delay = _cupsNextDelay(0, &prev_delay); !job_canceled;) { /* * Check for side-channel requests... @@ -1202,9 +1594,7 @@ main(int argc, /* I - Number of command-line args */ * Do the request... */ - if (!copies_sup || http->version < HTTP_1_1) - httpReconnect(http); - + httpReconnect(http); response = cupsDoRequest(http, request, resource); ipp_status = cupsLastError(); @@ -1214,12 +1604,17 @@ main(int argc, /* I - Number of command-line args */ * Job has gone away and/or the server has no job history... */ + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-missing-job-history"); ippDelete(response); ipp_status = IPP_OK; break; } + fprintf(stderr, "DEBUG: Get-Job-Attributes: %s (%s)\n", + ippErrorString(ipp_status), cupsLastErrorString()); + if (ipp_status > IPP_OK_CONFLICT) { if (ipp_status != IPP_SERVICE_UNAVAILABLE && @@ -1227,9 +1622,8 @@ main(int argc, /* I - Number of command-line args */ { ippDelete(response); - _cupsLangPrintf(stderr, - _("ERROR: Unable to get job %d attributes (%s)!\n"), - job_id, cupsLastErrorString()); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to get print job status.")); break; } } @@ -1239,18 +1633,34 @@ main(int argc, /* I - Number of command-line args */ if ((job_state = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL) { + /* + * Reflect the remote job state in the local queue... + */ + + if (cups_version && + job_state->values[0].integer >= IPP_JOB_PENDING && + job_state->values[0].integer <= IPP_JOB_COMPLETED) + update_reasons(NULL, + remote_job_states[job_state->values[0].integer - + IPP_JOB_PENDING]); + + if ((job_sheets = ippFindAttribute(response, + "job-media-sheets-completed", + IPP_TAG_INTEGER)) == NULL) + job_sheets = ippFindAttribute(response, + "job-impressions-completed", + IPP_TAG_INTEGER); + + if (job_sheets) + fprintf(stderr, "PAGE: total %d\n", + job_sheets->values[0].integer); + /* * Stop polling if the job is finished or pending-held... */ if (job_state->values[0].integer > IPP_JOB_STOPPED) { - if ((job_sheets = ippFindAttribute(response, - "job-media-sheets-completed", - IPP_TAG_INTEGER)) != NULL) - fprintf(stderr, "PAGE: total %d\n", - job_sheets->values[0].integer); - ippDelete(response); break; } @@ -1263,8 +1673,8 @@ main(int argc, /* I - Number of command-line args */ * the job... */ - fputs("DEBUG: No job-state available from printer - stopping queue.\n", - stderr); + update_reasons(NULL, "+cups-ipp-conformance-failure-report," + "cups-ipp-missing-job-state"); ipp_status = IPP_INTERNAL_ERROR; break; } @@ -1273,20 +1683,12 @@ main(int argc, /* I - Number of command-line args */ ippDelete(response); /* - * Check the printer state and report it if necessary... - */ - - check_printer_state(http, uri, resource, argv[2], version, job_id); - - /* - * Wait 1-10 seconds before polling again... + * Wait before polling again... */ sleep(delay); - delay ++; - if (delay > 10) - delay = 1; + delay = _cupsNextDelay(delay, &prev_delay); } } @@ -1294,20 +1696,20 @@ main(int argc, /* I - Number of command-line args */ * Cancel the job as needed... */ - if (job_cancelled && job_id) + if (job_canceled && job_id) cancel_job(http, uri, job_id, resource, argv[2], version); /* * Check the printer state and report it if necessary... */ - check_printer_state(http, uri, resource, argv[2], version, job_id); + check_printer_state(http, uri, resource, argv[2], version); /* * Collect the final page count as needed... */ - if (have_supplies && + if (have_supplies && !backendSNMPSupplies(snmp_fd, http->hostaddr, &page_count, NULL) && page_count > start_count) fprintf(stderr, "PAGE: total %d\n", page_count - start_count); @@ -1325,6 +1727,11 @@ main(int argc, /* I - Number of command-line args */ * Free memory... */ + cleanup: + + cupsFreeOptions(num_options, options); + _ppdCacheDestroy(pc); + httpClose(http); ippDelete(supported); @@ -1344,26 +1751,28 @@ main(int argc, /* I - Number of command-line args */ } #endif /* HAVE_LIBZ */ -#ifdef __APPLE__ - if (pstmpname[0]) - unlink(pstmpname); -#endif /* __APPLE__ */ - /* * Return the queue status... */ - fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required); + if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN || + ipp_status == IPP_AUTHENTICATION_CANCELED || + ipp_status <= IPP_OK_CONFLICT) + fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required); - if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN) + if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN || + ipp_status == IPP_AUTHENTICATION_CANCELED) return (CUPS_BACKEND_AUTH_REQUIRED); else if (ipp_status == IPP_INTERNAL_ERROR) return (CUPS_BACKEND_STOP); - else if (ipp_status > IPP_OK_CONFLICT) + else if (ipp_status == IPP_DOCUMENT_FORMAT || + ipp_status == IPP_CONFLICT) return (CUPS_BACKEND_FAILED); + else if (ipp_status > IPP_OK_CONFLICT) + return (CUPS_BACKEND_RETRY_CURRENT); else { - _cupsLangPuts(stderr, _("INFO: Ready to print.\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Ready to print.")); return (CUPS_BACKEND_OK); } } @@ -1384,7 +1793,7 @@ cancel_job(http_t *http, /* I - HTTP connection */ ipp_t *request; /* Cancel-Job request */ - _cupsLangPuts(stderr, _("INFO: Canceling print job...\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Canceling print job.")); request = ippNewRequest(IPP_CANCEL_JOB); request->request.op.version[0] = version / 10; @@ -1402,47 +1811,34 @@ cancel_job(http_t *http, /* I - HTTP connection */ * Do the request... */ - if (http->version < HTTP_1_1) - httpReconnect(http); - ippDelete(cupsDoRequest(http, request, resource)); if (cupsLastError() > IPP_OK_CONFLICT) - _cupsLangPrintf(stderr, _("ERROR: Unable to cancel job %d: %s\n"), id, - cupsLastErrorString()); + _cupsLangPrintFilter(stderr, "ERROR", _("Unable to cancel print job.")); } /* - * 'check_printer_state()' - Check the printer state... + * 'check_printer_state()' - Check the printer state. */ -static void +static ipp_pstate_t /* O - Current printer-state */ check_printer_state( http_t *http, /* I - HTTP connection */ const char *uri, /* I - Printer URI */ const char *resource, /* I - Resource path */ const char *user, /* I - Username, if any */ - int version, /* I - IPP version */ - int job_id) /* I - Current job ID */ -{ - ipp_t *request, /* IPP request */ - *response; /* IPP response */ - static const char * const attrs[] = /* Attributes we want */ - { - "com.apple.print.recoverable-message", - "marker-colors", - "marker-levels", - "marker-message", - "marker-names", - "marker-types", - "printer-state-message", - "printer-state-reasons" - }; + int version) /* I - IPP version */ + { + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* Attribute in response */ + ipp_pstate_t printer_state = IPP_PRINTER_STOPPED; + /* Current printer-state */ /* - * Check on the printer state... + * Send a Get-Printer-Attributes request and log the results... */ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); @@ -1450,34 +1846,41 @@ check_printer_state( request->request.op.version[1] = version % 10; ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); + NULL, uri); if (user && user[0]) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, - "requesting-user-name", NULL, user); + "requesting-user-name", NULL, user); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "requested-attributes", - (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs); - - /* - * Do the request... - */ - - if (http->version < HTTP_1_1) - httpReconnect(http); + "requested-attributes", + (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); if ((response = cupsDoRequest(http, request, resource)) != NULL) { - report_printer_state(response, job_id); + report_printer_state(response); + + if ((attr = ippFindAttribute(response, "printer-state", + IPP_TAG_ENUM)) != NULL) + printer_state = (ipp_pstate_t)attr->values[0].integer; + ippDelete(response); } + + fprintf(stderr, "DEBUG: Get-Printer-Attributes: %s (%s)\n", + ippErrorString(cupsLastError()), cupsLastErrorString()); + + /* + * Return the printer-state value... + */ + + return (printer_state); } #ifdef HAVE_LIBZ /* - * 'compress_files()' - Compress print files... + * 'compress_files()' - Compress print files. */ static void @@ -1500,25 +1903,19 @@ compress_files(int num_files, /* I - Number of files */ { if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) { - _cupsLangPrintf(stderr, - _("ERROR: Unable to create temporary compressed print " - "file: %s\n"), strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to create compressed print file")); exit(CUPS_BACKEND_FAILED); } if ((out = cupsFileOpenFd(fd, "w9")) == NULL) { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open temporary compressed print " - "file: %s\n"), strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to open compressed print file")); exit(CUPS_BACKEND_FAILED); } if ((in = cupsFileOpen(files[i], "r")) == NULL) { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open print file \"%s\": %s\n"), - files[i], strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to open print file")); cupsFileClose(out); exit(CUPS_BACKEND_FAILED); } @@ -1527,9 +1924,8 @@ compress_files(int num_files, /* I - Number of files */ while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0) if (cupsFileWrite(out, buffer, bytes) < bytes) { - _cupsLangPrintf(stderr, - _("ERROR: Unable to write %d bytes to \"%s\": %s\n"), - (int)bytes, filename, strerror(errno)); + _cupsLangPrintError("ERROR", + _("Unable to generate compressed print file")); cupsFileClose(in); cupsFileClose(out); exit(CUPS_BACKEND_FAILED); @@ -1554,6 +1950,365 @@ compress_files(int num_files, /* I - Number of files */ /* + * 'monitor_printer()' - Monitor the printer state. + */ + +static void * /* O - Thread exit code */ +monitor_printer( + _cups_monitor_t *monitor) /* I - Monitoring data */ +{ + http_t *http; /* Connection to printer */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* Attribute in response */ + int delay, /* Current delay */ + prev_delay; /* Previous delay */ + + + /* + * Make a copy of the printer connection... + */ + + http = _httpCreate(monitor->hostname, monitor->port, NULL, monitor->encryption, + AF_UNSPEC); + httpSetTimeout(http, 30.0, timeout_cb, NULL); + cupsSetPasswordCB(password_cb); + + /* + * Loop until the job is canceled, aborted, or completed. + */ + + delay = _cupsNextDelay(0, &prev_delay); + + while (monitor->job_state < IPP_JOB_CANCELED && !job_canceled) + { + /* + * Reconnect to the printer... + */ + + if (!httpReconnect(http)) + { + /* + * Connected, so check on the printer state... + */ + + monitor->printer_state = check_printer_state(http, monitor->uri, + monitor->resource, + monitor->user, + monitor->version); + + if (monitor->job_id > 0) + { + /* + * 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; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, monitor->uri); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "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); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", + (int)(sizeof(jattrs) / sizeof(jattrs[0])), NULL, jattrs); + + /* + * Do the request... + */ + + response = cupsDoRequest(http, request, monitor->resource); + + fprintf(stderr, "DEBUG: Get-Job-Attributes: %s (%s)\n", + ippErrorString(cupsLastError()), cupsLastErrorString()); + + 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; + + ippDelete(response); + } + + /* + * Disconnect from the printer - we'll reconnect on the next poll... + */ + + _httpDisconnect(http); + } + + /* + * Sleep for N seconds... + */ + + sleep(delay); + + delay = _cupsNextDelay(delay, &prev_delay); + } + + /* + * Cleanup and return... + */ + + httpClose(http); + + return (NULL); +} + + +/* + * 'new_request()' - Create a new print creation or validation request. + */ + +static ipp_t * /* O - Request data */ +new_request( + ipp_op_t op, /* I - IPP operation code */ + int version, /* I - IPP version number */ + const char *uri, /* I - printer-uri value */ + const char *user, /* I - requesting-user-name value */ + const char *title, /* I - job-name value */ + int num_options, /* I - Number of options to send */ + 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 */ + _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 */ +{ + int i; /* Looping var */ + ipp_t *request; /* Request data */ + const char *keyword; /* PWG keyword */ + _pwg_size_t *size; /* PWG media size */ + ipp_t *media_col, /* media-col value */ + *media_size; /* media-size value */ + const char *media_source, /* media-source value */ + *media_type, /* media-type value */ + *collate_str; /* multiple-document-handling value */ + + + /* + * Create the IPP request... + */ + + request = ippNewRequest(op); + request->request.op.version[0] = version / 10; + request->request.op.version[1] = version % 10; + + fprintf(stderr, "DEBUG: %s IPP/%d.%d\n", + ippOpString(request->request.op.operation_id), + request->request.op.version[0], + request->request.op.version[1]); + + /* + * Add standard attributes... + */ + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + fprintf(stderr, "DEBUG: printer-uri=\"%s\"\n", uri); + + if (user && *user) + { + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, user); + fprintf(stderr, "DEBUG: requesting-user-name=\"%s\"\n", user); + } + + if (title && *title) + { + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, + title); + fprintf(stderr, "DEBUG: job-name=\"%s\"\n", title); + } + + if (format) + { + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, + "document-format", NULL, format); + fprintf(stderr, "DEBUG: document-format=\"%s\"\n", format); + } + +#ifdef HAVE_LIBZ + if (compression) + { + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "compression", NULL, compression); + fprintf(stderr, "DEBUG: compression=\"%s\"\n", compression); + } +#endif /* HAVE_LIBZ */ + + /* + * Handle options on the command-line... + */ + + if (num_options > 0) + { + if (pc) + { + /* + * Send standard IPP attributes... + */ + + if ((keyword = cupsGetOption("PageSize", num_options, options)) == NULL) + keyword = cupsGetOption("media", num_options, options); + + if ((size = _ppdCacheGetSize(pc, keyword)) != NULL) + { + /* + * Add a media-col value... + */ + + media_size = ippNew(); + ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "x-dimension", size->width); + ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "y-dimension", size->length); + + media_col = ippNew(); + ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size); + + media_source = _ppdCacheGetSource(pc, cupsGetOption("InputSlot", + num_options, + options)); + media_type = _ppdCacheGetType(pc, cupsGetOption("MediaType", + num_options, + options)); + + for (i = 0; i < media_col_sup->num_values; i ++) + { + if (!strcmp(media_col_sup->values[i].string.text, + "media-left-margin")) + ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "media-left-margin", size->left); + else if (!strcmp(media_col_sup->values[i].string.text, + "media-bottom-margin")) + ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "media-bottom-margin", size->left); + else if (!strcmp(media_col_sup->values[i].string.text, + "media-right-margin")) + ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "media-right-margin", size->left); + else if (!strcmp(media_col_sup->values[i].string.text, + "media-top-margin")) + ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "media-top-margin", size->left); + else if (!strcmp(media_col_sup->values[i].string.text, + "media-source") && media_source) + ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, + "media-source", NULL, media_source); + else if (!strcmp(media_col_sup->values[i].string.text, + "media-type") && media_type) + ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, + "media-type", NULL, media_type); + } + + ippAddCollection(request, IPP_TAG_JOB, "media-col", media_col); + } + + if ((keyword = cupsGetOption("output-bin", num_options, + options)) == NULL) + keyword = _ppdCacheGetBin(pc, cupsGetOption("OutputBin", num_options, + options)); + + if (keyword) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-bin", + NULL, keyword); + + if ((keyword = cupsGetOption("output-mode", num_options, + options)) != NULL) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-mode", + NULL, keyword); + else if ((keyword = cupsGetOption("ColorModel", num_options, + options)) != NULL) + { + if (!_cups_strcasecmp(keyword, "Gray")) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-mode", + NULL, "monochrome"); + else + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-mode", + NULL, "color"); + } + + if ((keyword = cupsGetOption("print-quality", num_options, + options)) != NULL) + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", + atoi(keyword)); + else if ((keyword = cupsGetOption("cupsPrintQuality", num_options, + options)) != NULL) + { + if (!_cups_strcasecmp(keyword, "draft")) + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", + IPP_QUALITY_DRAFT); + else if (!_cups_strcasecmp(keyword, "normal")) + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", + IPP_QUALITY_NORMAL); + else if (!_cups_strcasecmp(keyword, "high")) + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", + IPP_QUALITY_HIGH); + } + + if ((keyword = cupsGetOption("sides", num_options, options)) != NULL) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", + NULL, keyword); + else if (pc->sides_option && + (keyword = cupsGetOption(pc->sides_option, num_options, + options)) != NULL) + { + if (!_cups_strcasecmp(keyword, pc->sides_1sided)) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", + NULL, "one-sided"); + else if (!_cups_strcasecmp(keyword, pc->sides_2sided_long)) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", + NULL, "two-sided-long-edge"); + if (!_cups_strcasecmp(keyword, pc->sides_2sided_short)) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", + NULL, "two-sided-short-edge"); + } + + if (doc_handling_sup && + (keyword = cupsGetOption("collate", num_options, options)) != NULL) + { + if (!_cups_strcasecmp(keyword, "true")) + collate_str = "separate-documents-collated-copies"; + else + collate_str = "separate-documents-uncollated-copies"; + + for (i = 0; i < doc_handling_sup->num_values; i ++) + if (!strcmp(doc_handling_sup->values[i].string.text, collate_str)) + { + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, + "multiple-document-handling", NULL, collate_str); + break; + } + } + } + else + { + /* + * When talking to another CUPS server, send all options... + */ + + cupsEncodeOptions(request, num_options, options); + } + + if (copies > 1) + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", copies); + } + + return (request); +} + + +/* * 'password_cb()' - Disable the password prompt for cupsDoFileRequest(). */ @@ -1592,10 +2347,11 @@ password_cb(const char *prompt) /* I - Prompt (not used) */ static void report_attr(ipp_attribute_t *attr) /* I - Attribute */ { - int i; /* Looping var */ - char value[1024], /* Value string */ - *valptr, /* Pointer into value string */ - *attrptr; /* Pointer into attribute value */ + int i; /* Looping var */ + char value[1024], /* Value string */ + *valptr, /* Pointer into value string */ + *attrptr; /* Pointer into attribute value */ + const char *cached; /* Cached attribute */ /* @@ -1645,11 +2401,21 @@ report_attr(ipp_attribute_t *attr) /* I - Attribute */ *valptr = '\0'; - /* - * Tell the scheduler about the new values... - */ + _cupsMutexLock(&report_mutex); + + if ((cached = cupsGetOption(attr->name, num_attr_cache, + attr_cache)) == NULL || strcmp(cached, value)) + { + /* + * Tell the scheduler about the new values... + */ - fprintf(stderr, "ATTR: %s=%s\n", attr->name, value); + num_attr_cache = cupsAddOption(attr->name, value, num_attr_cache, + &attr_cache); + fprintf(stderr, "ATTR: %s=%s\n", attr->name, value); + } + + _cupsMutexUnlock(&report_mutex); } @@ -1657,297 +2423,560 @@ report_attr(ipp_attribute_t *attr) /* I - Attribute */ * 'report_printer_state()' - Report the printer state. */ -static int /* O - Number of reasons shown */ -report_printer_state(ipp_t *ipp, /* I - IPP response */ - int job_id) /* I - Current job ID */ +static void +report_printer_state(ipp_t *ipp) /* I - IPP response */ { - int i; /* Looping var */ - int count; /* Count of reasons shown... */ - ipp_attribute_t *caprm, /* com.apple.print.recoverable-message */ + ipp_attribute_t *pa, /* printer-alert */ + *pam, /* printer-alert-message */ *psm, /* printer-state-message */ *reasons, /* printer-state-reasons */ *marker; /* marker-* attributes */ - const char *reason; /* Current reason */ - const char *prefix; /* Prefix for STATE: line */ - char state[1024]; /* State string */ - int saw_caprw; /* Saw com.apple.print.recoverable-warning state */ + char value[1024], /* State/message string */ + *valptr; /* Pointer into string */ + static int ipp_supplies = -1; + /* Report supply levels? */ - if ((psm = ippFindAttribute(ipp, "printer-state-message", - IPP_TAG_TEXT)) != NULL) - fprintf(stderr, "INFO: %s\n", psm->values[0].string.text); + /* + * Report alerts and messages... + */ - if ((reasons = ippFindAttribute(ipp, "printer-state-reasons", - IPP_TAG_KEYWORD)) == NULL) - return (0); + if ((pa = ippFindAttribute(ipp, "printer-alert", IPP_TAG_TEXT)) != NULL) + report_attr(pa); - saw_caprw = 0; - state[0] = '\0'; - prefix = "STATE: "; + if ((pam = ippFindAttribute(ipp, "printer-alert-message", + IPP_TAG_TEXT)) != NULL) + report_attr(pam); - for (i = 0, count = 0; i < reasons->num_values; i ++) + if ((psm = ippFindAttribute(ipp, "printer-state-message", + IPP_TAG_TEXT)) != NULL) { - reason = reasons->values[i].string.text; + char *ptr; /* Pointer into message */ - if (!strcmp(reason, "com.apple.print.recoverable-warning")) - saw_caprw = 1; - else if (strcmp(reason, "paused")) + + strlcpy(value, "INFO: ", sizeof(value)); + for (ptr = psm->values[0].string.text, valptr = value + 6; + *ptr && valptr < (value + sizeof(value) - 6); + ptr ++) { - strlcat(state, prefix, sizeof(state)); - strlcat(state, reason, sizeof(state)); + if (*ptr < ' ' && *ptr > 0 && *ptr != '\t') + { + /* + * Substitute "<XX>" for the control character; sprintf is safe because + * we always leave 6 chars free at the end... + */ - prefix = ","; + sprintf(valptr, "<%02X>", *ptr); + valptr += 4; + } + else + *valptr++ = *ptr; } - } - if (state[0]) - fprintf(stderr, "%s\n", state); + *valptr++ = '\n'; + *valptr = '\0'; + + fputs(value, stderr); + } /* - * Relay com.apple.print.recoverable-message... + * Now report printer-state-reasons, filtering out some of the reasons we never + * want to set... */ - if ((caprm = ippFindAttribute(ipp, "com.apple.print.recoverable-message", - IPP_TAG_TEXT)) != NULL) - fprintf(stderr, "WARNING: %s: %s\n", - saw_caprw ? "recoverable" : "recovered", - caprm->values[0].string.text); + if ((reasons = ippFindAttribute(ipp, "printer-state-reasons", + IPP_TAG_KEYWORD)) == NULL) + return; + + update_reasons(reasons, NULL); /* * Relay the current marker-* attribute values... */ - if ((marker = ippFindAttribute(ipp, "marker-colors", IPP_TAG_NAME)) != NULL) - report_attr(marker); - if ((marker = ippFindAttribute(ipp, "marker-high-levels", - IPP_TAG_INTEGER)) != NULL) - report_attr(marker); - if ((marker = ippFindAttribute(ipp, "marker-levels", - IPP_TAG_INTEGER)) != NULL) - report_attr(marker); - if ((marker = ippFindAttribute(ipp, "marker-low-levels", - IPP_TAG_INTEGER)) != NULL) - report_attr(marker); - if ((marker = ippFindAttribute(ipp, "marker-message", IPP_TAG_TEXT)) != NULL) - report_attr(marker); - if ((marker = ippFindAttribute(ipp, "marker-names", IPP_TAG_NAME)) != NULL) - report_attr(marker); - if ((marker = ippFindAttribute(ipp, "marker-types", IPP_TAG_KEYWORD)) != NULL) - report_attr(marker); - - return (count); + if (ipp_supplies < 0) + { + ppd_file_t *ppd; /* PPD file */ + ppd_attr_t *ppdattr; /* Attribute in PPD file */ + + if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL && + (ppdattr = ppdFindAttr(ppd, "cupsIPPSupplies", NULL)) != NULL && + ppdattr->value && _cups_strcasecmp(ppdattr->value, "true")) + ipp_supplies = 0; + else + ipp_supplies = 1; + + ppdClose(ppd); + } + + if (ipp_supplies > 0) + { + if ((marker = ippFindAttribute(ipp, "marker-colors", IPP_TAG_NAME)) != NULL) + report_attr(marker); + if ((marker = ippFindAttribute(ipp, "marker-high-levels", + IPP_TAG_INTEGER)) != NULL) + report_attr(marker); + if ((marker = ippFindAttribute(ipp, "marker-levels", + IPP_TAG_INTEGER)) != NULL) + report_attr(marker); + if ((marker = ippFindAttribute(ipp, "marker-low-levels", + IPP_TAG_INTEGER)) != NULL) + report_attr(marker); + if ((marker = ippFindAttribute(ipp, "marker-message", + IPP_TAG_TEXT)) != NULL) + report_attr(marker); + if ((marker = ippFindAttribute(ipp, "marker-names", IPP_TAG_NAME)) != NULL) + report_attr(marker); + if ((marker = ippFindAttribute(ipp, "marker-types", + IPP_TAG_KEYWORD)) != NULL) + report_attr(marker); + } } -#ifdef __APPLE__ +#if defined(HAVE_GSSAPI) && defined(HAVE_XPC) /* - * 'run_pictwps_filter()' - Convert PICT files to PostScript when printing - * remotely. + * 'run_as_user()' - Run the IPP backend as the printing user. * - * This step is required because the PICT format is not documented and - * subject to change, so developing a filter for other OS's is infeasible. - * Also, fonts required by the PICT file need to be embedded on the - * client side (which has the fonts), so we run the filter to get a - * PostScript file for printing... + * This function uses an XPC-based user agent to run the backend as the printing + * user. We need to do this in order to have access to the user's Kerberos + * credentials. */ -static int /* O - Exit status of filter */ -run_pictwps_filter(char **argv, /* I - Command-line arguments */ - const char *filename)/* I - Filename */ +static int /* O - Exit status */ +run_as_user(int argc, /* I - Number of command-line args */ + char *argv[], /* I - Command-line arguments */ + uid_t uid, /* I - User ID */ + const char *device_uri, /* I - Device URI */ + int fd) /* I - File to print */ { - struct stat fileinfo; /* Print file information */ - const char *ppdfile; /* PPD file for destination printer */ - int pid; /* Child process ID */ - int fd; /* Temporary file descriptor */ - int status; /* Exit status of filter */ - const char *printer; /* PRINTER env var */ - static char ppdenv[1024]; /* PPD environment variable */ + const char *auth_negotiate;/* AUTH_NEGOTIATE env var */ + xpc_connection_t conn; /* Connection to XPC service */ + xpc_object_t request; /* Request message dictionary */ + __block xpc_object_t response; /* Response message dictionary */ + dispatch_semaphore_t sem; /* Semaphore for waiting for response */ + int status = CUPS_BACKEND_FAILED; + /* Status of request */ + fprintf(stderr, "DEBUG: Running IPP backend as UID %d.\n", (int)uid); + /* - * First get the PPD file for the printer... + * Connect to the user agent for the specified UID... */ - printer = getenv("PRINTER"); - if (!printer) + conn = xpc_connection_create_mach_service(kPMPrintUIToolAgent, + dispatch_get_global_queue(0, 0), 0); + if (!conn) { - _cupsLangPuts(stderr, - _("ERROR: PRINTER environment variable not defined!\n")); - return (-1); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to start backend process.")); + fputs("DEBUG: Unable to create connection to agent.\n", stderr); + goto cleanup; } - if ((ppdfile = cupsGetPPD(printer)) == NULL) + xpc_connection_set_event_handler(conn, + ^(xpc_object_t event) + { + xpc_type_t messageType = xpc_get_type(event); + + if (messageType == XPC_TYPE_ERROR) + { + if (event == XPC_ERROR_CONNECTION_INTERRUPTED) + fprintf(stderr, "DEBUG: Interrupted connection to service %s.\n", + xpc_connection_get_name(conn)); + else if (event == XPC_ERROR_CONNECTION_INVALID) + fprintf(stderr, "DEBUG: Connection invalid for service %s.\n", + xpc_connection_get_name(conn)); + else + fprintf(stderr, "DEBUG: Unxpected error for service %s: %s\n", + xpc_connection_get_name(conn), + xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION)); + } + }); + xpc_connection_set_target_uid(conn, uid); + xpc_connection_resume(conn); + + /* + * Try starting the backend... + */ + + request = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_int64(request, "command", kPMStartJob); + xpc_dictionary_set_string(request, "device-uri", device_uri); + xpc_dictionary_set_string(request, "job-id", argv[1]); + xpc_dictionary_set_string(request, "user", argv[2]); + xpc_dictionary_set_string(request, "title", argv[3]); + xpc_dictionary_set_string(request, "copies", argv[4]); + xpc_dictionary_set_string(request, "options", argv[5]); + xpc_dictionary_set_string(request, "auth-info-required", + getenv("AUTH_INFO_REQUIRED")); + if ((auth_negotiate = getenv("AUTH_NEGOTIATE")) != NULL) + xpc_dictionary_set_string(request, "auth-negotiate", auth_negotiate); + xpc_dictionary_set_fd(request, "stdin", fd); + xpc_dictionary_set_fd(request, "stderr", 2); + xpc_dictionary_set_fd(request, "side-channel", CUPS_SC_FD); + + sem = dispatch_semaphore_create(0); + response = NULL; + + xpc_connection_send_message_with_reply(conn, request, + dispatch_get_global_queue(0,0), + ^(xpc_object_t reply) + { + /* Save the response and wake up */ + if (xpc_get_type(reply) + == XPC_TYPE_DICTIONARY) + response = xpc_retain(reply); + + dispatch_semaphore_signal(sem); + }); + + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + xpc_release(request); + dispatch_release(sem); + + if (response) { - _cupsLangPrintf(stderr, - _("ERROR: Unable to get PPD file for printer \"%s\" - " - "%s.\n"), printer, cupsLastErrorString()); + child_pid = xpc_dictionary_get_int64(response, "child-pid"); + + xpc_release(response); + + if (child_pid) + fprintf(stderr, "DEBUG: Child PID=%d.\n", child_pid); + else + { + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to start backend process.")); + fputs("DEBUG: No child PID.\n", stderr); + goto cleanup; + } } else { - snprintf(ppdenv, sizeof(ppdenv), "PPD=%s", ppdfile); - putenv(ppdenv); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to start backend process.")); + fputs("DEBUG: No reply from agent.\n", stderr); + goto cleanup; } /* - * Then create a temporary file for printing... + * Then wait for the backend to finish... */ - if ((fd = cupsTempFd(pstmpname, sizeof(pstmpname))) < 0) + request = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_int64(request, "command", kPMWaitForJob); + xpc_dictionary_set_fd(request, "stderr", 2); + + sem = dispatch_semaphore_create(0); + response = NULL; + + xpc_connection_send_message_with_reply(conn, request, + dispatch_get_global_queue(0,0), + ^(xpc_object_t reply) + { + /* Save the response and wake up */ + if (xpc_get_type(reply) + == XPC_TYPE_DICTIONARY) + response = xpc_retain(reply); + + dispatch_semaphore_signal(sem); + }); + + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + xpc_release(request); + dispatch_release(sem); + + if (response) { - _cupsLangPrintError(_("ERROR: Unable to create temporary file")); - if (ppdfile) - unlink(ppdfile); - return (-1); - } + status = xpc_dictionary_get_int64(response, "status"); - /* - * Get the owner of the spool file - it is owned by the user we want to run - * as... - */ + if (status == SIGTERM || status == SIGKILL || status == SIGPIPE) + { + fprintf(stderr, "DEBUG: Child terminated on signal %d.\n", status); + status = CUPS_BACKEND_FAILED; + } + else if (WIFSIGNALED(status)) + { + fprintf(stderr, "DEBUG: Child crashed on signal %d.\n", status); + status = CUPS_BACKEND_STOP; + } + else if (WIFEXITED(status)) + { + status = WEXITSTATUS(status); + fprintf(stderr, "DEBUG: Child exited with status %d.\n", status); + } - if (argv[6]) - stat(argv[6], &fileinfo); + xpc_release(response); + } else - { - /* - * Use the OSX defaults, as an up-stream filter created the PICT - * file... - */ + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to get backend exit status.")); + + cleanup: - fileinfo.st_uid = 1; - fileinfo.st_gid = 80; + if (conn) + { + xpc_connection_suspend(conn); + xpc_connection_cancel(conn); + xpc_release(conn); } - if (ppdfile) - chown(ppdfile, fileinfo.st_uid, fileinfo.st_gid); + return (status); +} +#endif /* HAVE_GSSAPI && HAVE_XPC */ - fchown(fd, fileinfo.st_uid, fileinfo.st_gid); - /* - * Finally, run the filter to convert the file... - */ +/* + * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend. + */ - if ((pid = fork()) == 0) +static void +sigterm_handler(int sig) /* I - Signal */ +{ + (void)sig; /* remove compiler warnings... */ + +#if defined(HAVE_GSSAPI) && defined(HAVE_XPC) + if (child_pid) + { + kill(child_pid, sig); + child_pid = 0; + } +#endif /* HAVE_GSSAPI && HAVE_XPC */ + + if (!job_canceled) { /* - * Child process for pictwpstops... Redirect output of pictwpstops to a - * file... + * Flag that the job should be canceled... */ - dup2(fd, 1); - close(fd); + job_canceled = 1; + return; + } - if (!getuid()) - { - /* - * Change to an unpriviledged user... - */ + /* + * The scheduler already tried to cancel us once, now just terminate + * after removing our temp file! + */ - if (setgid(fileinfo.st_gid)) - return (errno); + if (tmpfilename[0]) + unlink(tmpfilename); - if (setuid(fileinfo.st_uid)) - return (errno); - } + exit(1); +} - execlp("pictwpstops", printer, argv[1], argv[2], argv[3], argv[4], argv[5], - filename, NULL); - _cupsLangPrintf(stderr, _("ERROR: Unable to exec pictwpstops: %s\n"), - strerror(errno)); - return (errno); - } - close(fd); +/* + * 'timeout_cb()' - Handle HTTP timeouts. + */ - if (pid < 0) - { - /* - * Error! - */ +static int /* O - 1 to continue, 0 to cancel */ +timeout_cb(http_t *http, /* I - Connection to server (unused) */ + void *user_data) /* I - User data (unused) */ +{ + (void)http; + (void)user_data; - _cupsLangPrintf(stderr, _("ERROR: Unable to fork pictwpstops: %s\n"), - strerror(errno)); - if (ppdfile) - unlink(ppdfile); - return (-1); - } + return (!job_canceled); +} + + +/* + * 'update_reasons()' - Update the printer-state-reasons values. + */ + +static void +update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */ + const char *s) /* I - STATE: string or NULL */ +{ + char op; /* Add (+), remove (-), replace (\0) */ + cups_array_t *new_reasons; /* New reasons array */ + char *reason, /* Current reason */ + add[2048], /* Reasons added string */ + *addptr, /* Pointer into add string */ + rem[2048], /* Reasons removed string */ + *remptr; /* Pointer into remove string */ + const char *addprefix, /* Current add string prefix */ + *remprefix; /* Current remove string prefix */ + + + fprintf(stderr, "DEBUG: update_reasons(attr=%d(%s%s), s=\"%s\")\n", + attr ? attr->num_values : 0, attr ? attr->values[0].string.text : "", + attr && attr->num_values > 1 ? ",..." : "", s ? s : "(null)"); /* - * Now wait for the filter to complete... + * Create an array of new reason keyword strings... */ - if (wait(&status) < 0) + if (attr) { - _cupsLangPrintf(stderr, _("ERROR: Unable to wait for pictwpstops: %s\n"), - strerror(errno)); - close(fd); - if (ppdfile) - unlink(ppdfile); - return (-1); - } - - if (ppdfile) - unlink(ppdfile); + int i; /* Looping var */ - close(fd); + new_reasons = cupsArrayNew((cups_array_func_t)strcmp, NULL); + op = '\0'; - if (status) + for (i = 0; i < attr->num_values; i ++) + { + reason = attr->values[i].string.text; + + if (strcmp(reason, "none") && + strcmp(reason, "none-report") && + strcmp(reason, "paused") && + strcmp(reason, "com.apple.print.recoverable-warning") && + strncmp(reason, "cups-", 5)) + cupsArrayAdd(new_reasons, reason); + } + } + else if (s) { - if (status >= 256) - _cupsLangPrintf(stderr, _("ERROR: pictwpstops exited with status %d!\n"), - status / 256); + if (*s == '+' || *s == '-') + op = *s++; else - _cupsLangPrintf(stderr, _("ERROR: pictwpstops exited on signal %d!\n"), - status); + op = '\0'; - return (status); + new_reasons = _cupsArrayNewStrings(s); } + else + return; /* - * Return with no errors.. + * Compute the changes... */ - return (0); -} -#endif /* __APPLE__ */ + add[0] = '\0'; + addprefix = "STATE: +"; + addptr = add; + rem[0] = '\0'; + remprefix = "STATE: -"; + remptr = rem; + fprintf(stderr, "DEBUG2: op='%c', new_reasons=%d, state_reasons=%d\n", + op ? op : ' ', cupsArrayCount(new_reasons), + cupsArrayCount(state_reasons)); -/* - * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend. - */ + _cupsMutexLock(&report_mutex); -static void -sigterm_handler(int sig) /* I - Signal */ -{ - (void)sig; /* remove compiler warnings... */ + if (op == '+') + { + /* + * Add reasons... + */ + + for (reason = (char *)cupsArrayFirst(new_reasons); + reason; + reason = (char *)cupsArrayNext(new_reasons)) + { + if (!cupsArrayFind(state_reasons, reason)) + { + if (!strncmp(reason, "cups-remote-", 12)) + { + /* + * If we are setting cups-remote-xxx, remove all other cups-remote-xxx + * keywords... + */ + + char *temp; /* Current reason in state_reasons */ + + cupsArraySave(state_reasons); + + for (temp = (char *)cupsArrayFirst(state_reasons); + temp; + temp = (char *)cupsArrayNext(state_reasons)) + if (!strncmp(temp, "cups-remote-", 12)) + { + snprintf(remptr, sizeof(rem) - (remptr - rem), "%s%s", remprefix, + temp); + remptr += strlen(remptr); + remprefix = ","; + + cupsArrayRemove(state_reasons, temp); + break; + } + + cupsArrayRestore(state_reasons); + } + + cupsArrayAdd(state_reasons, reason); - if (!job_cancelled) + snprintf(addptr, sizeof(add) - (addptr - add), "%s%s", addprefix, + reason); + addptr += strlen(addptr); + addprefix = ","; + } + } + } + else if (op == '-') { /* - * Flag that the job should be cancelled... + * Remove reasons... */ - job_cancelled = 1; - return; + for (reason = (char *)cupsArrayFirst(new_reasons); + reason; + reason = (char *)cupsArrayNext(new_reasons)) + { + if (cupsArrayFind(state_reasons, reason)) + { + snprintf(remptr, sizeof(rem) - (remptr - rem), "%s%s", remprefix, + reason); + remptr += strlen(remptr); + remprefix = ","; + + cupsArrayRemove(state_reasons, reason); + } + } + } + else + { + /* + * Replace reasons... + */ + + for (reason = (char *)cupsArrayFirst(state_reasons); + reason; + reason = (char *)cupsArrayNext(state_reasons)) + { + if (strncmp(reason, "cups-", 5) && !cupsArrayFind(new_reasons, reason)) + { + snprintf(remptr, sizeof(rem) - (remptr - rem), "%s%s", remprefix, + reason); + remptr += strlen(remptr); + remprefix = ","; + + cupsArrayRemove(state_reasons, reason); + } + } + + for (reason = (char *)cupsArrayFirst(new_reasons); + reason; + reason = (char *)cupsArrayNext(new_reasons)) + { + if (!cupsArrayFind(state_reasons, reason)) + { + cupsArrayAdd(state_reasons, reason); + + snprintf(addptr, sizeof(add) - (addptr - add), "%s%s", addprefix, + reason); + addptr += strlen(addptr); + addprefix = ","; + } + } } + _cupsMutexUnlock(&report_mutex); + /* - * The scheduler already tried to cancel us once, now just terminate - * after removing our temp files! + * Report changes and return... */ - if (tmpfilename[0]) - unlink(tmpfilename); - -#ifdef __APPLE__ - if (pstmpname[0]) - unlink(pstmpname); -#endif /* __APPLE__ */ - - exit(1); + if (add[0] && rem[0]) + fprintf(stderr, "%s\n%s\n", add, rem); + else if (add[0]) + fprintf(stderr, "%s\n", add); + else if (rem[0]) + fprintf(stderr, "%s\n", rem); } - /* - * End of "$Id: ipp.c 8950 2010-01-14 22:40:19Z mike $". + * End of "$Id: ipp.c 9808 2011-05-26 12:03:28Z mike $". */ diff --git a/backend/lpd.c b/backend/lpd.c index ab95fb78..cd2edc1f 100644 --- a/backend/lpd.c +++ b/backend/lpd.c @@ -1,9 +1,9 @@ /* - * "$Id: lpd.c 8938 2009-12-18 23:52:01Z mike $" + * "$Id: lpd.c 9793 2011-05-20 03:49:49Z mike $" * - * Line Printer Daemon backend for the Common UNIX Printing System (CUPS). + * Line Printer Daemon backend for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -34,6 +34,7 @@ #include <stdarg.h> #include <sys/types.h> #include <sys/stat.h> +#include <stdio.h> #ifdef WIN32 # include <winsock.h> @@ -87,11 +88,12 @@ static int abort_job = 0; /* Non-zero if we get SIGTERM */ */ static int lpd_command(int lpd_fd, int timeout, char *format, ...); -static int lpd_queue(const char *hostname, int port, const char *printer, - int print_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 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 @@ -124,6 +126,9 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ *filename, /* File to print */ title[256]; /* Title string */ int port; /* Port number */ + char portname[256]; /* Port name (string) */ + http_addrlist_t *addrlist; /* List of addresses for printer */ + int snmp_fd; /* SNMP socket */ int fd; /* Print file */ int status; /* Status of LPD job */ int mode; /* Print mode */ @@ -136,6 +141,8 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ timeout, /* Timeout */ contimeout, /* Connection timeout */ copies; /* Number of copies */ + ssize_t bytes = 0; /* Initial bytes read */ + char buffer[16384]; /* Initial print buffer */ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) struct sigaction action; /* Actions for POSIX signals */ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ @@ -181,7 +188,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ else if (argc < 6 || argc > 7) { _cupsLangPrintf(stderr, - _("Usage: %s job-id user title copies options [file]\n"), + _("Usage: %s job-id user title copies options [file]"), argv[0]); return (CUPS_BACKEND_FAILED); } @@ -190,8 +197,14 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Extract the hostname and printer name from the URI... */ - if ((device_uri = cupsBackendDeviceURI(argv)) == NULL) - return (CUPS_BACKEND_FAILED); + while ((device_uri = cupsBackendDeviceURI(argv)) == NULL) + { + _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer.")); + sleep(10); + + if (getenv("CLASS") != NULL) + return (CUPS_BACKEND_FAILED); + } httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, @@ -224,36 +237,15 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ #ifdef __APPLE__ /* - * We want to pass utf-8 characters, not re-map them (3071945) + * We want to pass UTF-8 characters by default, not re-map them (3071945) */ sanitize_title = 0; - +#else /* - * Get the default timeout from a system preference... + * Otherwise we want to re-map UTF-8 to "safe" characters by default... */ - { - CFPropertyListRef pvalue; /* Preference value */ - SInt32 toval; /* Timeout value */ - - - pvalue = CFPreferencesCopyValue(CFSTR("timeout"), - CFSTR("com.apple.print.backends"), - kCFPreferencesAnyUser, - kCFPreferencesCurrentHost); - if (pvalue) - { - if (CFGetTypeID(pvalue) == CFNumberGetTypeID()) - { - CFNumberGetValue(pvalue, kCFNumberSInt32Type, &toval); - contimeout = (int)toval; - } - - CFRelease(pvalue); - } - } -#else sanitize_title = 1; #endif /* __APPLE__ */ @@ -305,16 +297,16 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Process the option... */ - if (!strcasecmp(name, "banner")) + if (!_cups_strcasecmp(name, "banner")) { /* * Set the banner... */ - banner = !value[0] || !strcasecmp(value, "on") || - !strcasecmp(value, "yes") || !strcasecmp(value, "true"); + banner = !value[0] || !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true"); } - else if (!strcasecmp(name, "format") && value[0]) + else if (!_cups_strcasecmp(name, "format") && value[0]) { /* * Set output format... @@ -323,71 +315,72 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (strchr("cdfglnoprtv", value[0])) format = value[0]; else - _cupsLangPrintf(stderr, _("ERROR: Unknown format character \"%c\"\n"), - value[0]); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unknown format character: \"%c\"."), + value[0]); } - else if (!strcasecmp(name, "mode") && value[0]) + else if (!_cups_strcasecmp(name, "mode") && value[0]) { /* * Set control/data order... */ - if (!strcasecmp(value, "standard")) + if (!_cups_strcasecmp(value, "standard")) mode = MODE_STANDARD; - else if (!strcasecmp(value, "stream")) + else if (!_cups_strcasecmp(value, "stream")) mode = MODE_STREAM; else - _cupsLangPrintf(stderr, _("ERROR: Unknown print mode \"%s\"\n"), - value); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unknown print mode: \"%s\"."), value); } - else if (!strcasecmp(name, "order") && value[0]) + else if (!_cups_strcasecmp(name, "order") && value[0]) { /* * Set control/data order... */ - if (!strcasecmp(value, "control,data")) + if (!_cups_strcasecmp(value, "control,data")) order = ORDER_CONTROL_DATA; - else if (!strcasecmp(value, "data,control")) + else if (!_cups_strcasecmp(value, "data,control")) order = ORDER_DATA_CONTROL; else - _cupsLangPrintf(stderr, _("ERROR: Unknown file order \"%s\"\n"), - value); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unknown file order: \"%s\"."), value); } - else if (!strcasecmp(name, "reserve")) + else if (!_cups_strcasecmp(name, "reserve")) { /* * Set port reservation mode... */ - if (!value[0] || !strcasecmp(value, "on") || - !strcasecmp(value, "yes") || !strcasecmp(value, "true") || - !strcasecmp(value, "rfc1179")) + if (!value[0] || !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true") || + !_cups_strcasecmp(value, "rfc1179")) reserve = RESERVE_RFC1179; - else if (!strcasecmp(value, "any")) + else if (!_cups_strcasecmp(value, "any")) reserve = RESERVE_ANY; else reserve = RESERVE_NONE; } - else if (!strcasecmp(name, "manual_copies")) + else if (!_cups_strcasecmp(name, "manual_copies")) { /* * Set manual copies... */ - manual_copies = !value[0] || !strcasecmp(value, "on") || - !strcasecmp(value, "yes") || !strcasecmp(value, "true"); + manual_copies = !value[0] || !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true"); } - else if (!strcasecmp(name, "sanitize_title")) + else if (!_cups_strcasecmp(name, "sanitize_title")) { /* * Set sanitize title... */ - sanitize_title = !value[0] || !strcasecmp(value, "on") || - !strcasecmp(value, "yes") || !strcasecmp(value, "true"); + sanitize_title = !value[0] || !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true"); } - else if (!strcasecmp(name, "timeout")) + else if (!_cups_strcasecmp(name, "timeout")) { /* * Set the timeout... @@ -396,7 +389,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (atoi(value) > 0) timeout = atoi(value); } - else if (!strcasecmp(name, "contimeout")) + else if (!_cups_strcasecmp(name, "contimeout")) { /* * Set the connection timeout... @@ -412,6 +405,43 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ order = ORDER_CONTROL_DATA; /* + * Find the printer... + */ + + snprintf(portname, sizeof(portname), "%d", port); + + fputs("STATE: +connecting-to-device\n", stderr); + fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname); + + while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) + { + _cupsLangPrintFilter(stderr, "INFO", + _("Unable to locate printer \"%s\"."), hostname); + sleep(10); + + if (getenv("CLASS") != NULL) + { + fputs("STATE: -connecting-to-device\n", stderr); + exit(CUPS_BACKEND_FAILED); + } + } + + snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family); + + /* + * Wait for data from the filter... + */ + + if (argc == 6) + { + if (!backendWaitLoop(snmp_fd, &(addrlist->addr), 0, backendNetworkSideCB)) + return (CUPS_BACKEND_OK); + else if (mode == MODE_STANDARD && + (bytes = read(0, buffer, sizeof(buffer))) <= 0) + return (CUPS_BACKEND_OK); + } + + /* * If we have 7 arguments, print the file named on the command-line. * Otherwise, copy stdin to a temporary file and print the temporary * file. @@ -423,37 +453,19 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Copy stdin to a temporary file... */ - http_addrlist_t *addrlist; /* Address list */ - int snmp_fd; /* SNMP socket */ - - - fputs("STATE: +connecting-to-device\n", stderr); - fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname); - - if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, "1")) == NULL) - { - _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"), - hostname); - return (CUPS_BACKEND_STOP); - } - - snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family); - if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0) { - _cupsLangPrintError(_("ERROR: Unable to create temporary file")); + perror("DEBUG: Unable to create temporary file"); return (CUPS_BACKEND_FAILED); } - _cupsLangPuts(stderr, _("INFO: Copying print data...\n")); - - backendRunLoop(-1, fd, snmp_fd, &(addrlist->addr), 0, 0, - backendNetworkSideCB); + _cupsLangPrintFilter(stderr, "INFO", _("Copying print data.")); - if (snmp_fd >= 0) - _cupsSNMPClose(snmp_fd); + if (bytes > 0) + write(fd, buffer, bytes); - httpAddrFreeList(addrlist); + backendRunLoop(-1, fd, snmp_fd, &(addrlist->addr), 0, 0, + backendNetworkSideCB); } else if (argc == 6) { @@ -471,8 +483,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (fd == -1) { - _cupsLangPrintf(stderr, _("ERROR: Unable to open print file %s: %s\n"), - filename, strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to open print file")); return (CUPS_BACKEND_FAILED); } } @@ -514,18 +525,16 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ copies = atoi(argv[4]); } - status = lpd_queue(hostname, port, resource + 1, fd, mode, - username, title, copies, - banner, format, order, reserve, manual_copies, - timeout, contimeout); + status = lpd_queue(hostname, addrlist, resource + 1, fd, snmp_fd, mode, + username, title, copies, banner, format, order, reserve, + manual_copies, timeout, contimeout); if (!status) fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4])); } else - status = lpd_queue(hostname, port, resource + 1, fd, mode, - username, title, 1, - banner, format, order, reserve, 1, + status = lpd_queue(hostname, addrlist, resource + 1, fd, snmp_fd, mode, + username, title, 1, banner, format, order, reserve, 1, timeout, contimeout); /* @@ -538,6 +547,9 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (fd) close(fd); + if (snmp_fd >= 0) + _cupsSNMPClose(snmp_fd); + /* * Return the queue status... */ @@ -563,7 +575,7 @@ lpd_command(int fd, /* I - Socket connection to LPD host */ /* - * Don't try to send commands if the job has been cancelled... + * Don't try to send commands if the job has been canceled... */ if (abort_job) @@ -587,7 +599,7 @@ lpd_command(int fd, /* I - Socket connection to LPD host */ if (lpd_write(fd, buf, bytes) < bytes) { - _cupsLangPrintError(_("ERROR: Unable to send LPD command")); + perror("DEBUG: Unable to send LPD command"); return (-1); } @@ -601,9 +613,9 @@ lpd_command(int fd, /* I - Socket connection to LPD host */ if (recv(fd, &status, 1, 0) < 1) { - _cupsLangPrintf(stderr, - _("WARNING: Remote host did not respond with command " - "status byte after %d seconds!\n"), timeout); + _cupsLangPrintFilter(stderr, "WARNING", + _("Printer did not respond after %d seconds."), + timeout); status = errno; } @@ -620,21 +632,22 @@ lpd_command(int fd, /* I - Socket connection to LPD host */ */ static int /* O - Zero on success, non-zero on failure */ -lpd_queue(const char *hostname, /* I - Host to connect to */ - int port, /* I - Port to connect on */ - const char *printer, /* I - Printer/queue name */ - int print_fd, /* I - File to print */ - int mode, /* I - Print mode */ - const char *user, /* I - Requesting user */ - const char *title, /* I - Job title */ - int copies, /* I - Number of copies */ - int banner, /* I - Print LPD banner? */ - int format, /* I - Format specifier */ - int order, /* I - Order of data/control files */ - int reserve, /* I - Reserve ports? */ - int manual_copies, /* I - Do copies by hand... */ - int timeout, /* I - Timeout... */ - int contimeout) /* I - Connection timeout */ +lpd_queue(const char *hostname, /* I - Host to connect to */ + http_addrlist_t *addrlist, /* I - List of host addresses */ + const char *printer, /* I - Printer/queue name */ + int print_fd, /* I - File to print */ + int snmp_fd, /* I - SNMP socket */ + int mode, /* I - Print mode */ + const char *user, /* I - Requesting user */ + const char *title, /* I - Job title */ + int copies, /* I - Number of copies */ + int banner, /* I - Print LPD banner? */ + int format, /* I - Format specifier */ + int order, /* I - Order of data/control files */ + int reserve, /* I - Reserve ports? */ + int manual_copies,/* I - Do copies by hand... */ + int timeout, /* I - Timeout... */ + int contimeout) /* I - Connection timeout */ { char localhost[255]; /* Local host name */ int error; /* Error number */ @@ -644,16 +657,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ char control[10240], /* LPD control 'file' */ *cptr; /* Pointer into control file string */ char status; /* Status byte from command */ - char portname[255]; /* Port name */ int delay; /* Delay for retries... */ char addrname[256]; /* Address name */ - http_addrlist_t *addrlist, /* Address list */ - *addr; /* Socket address */ - int snmp_fd, /* SNMP socket */ - have_supplies; /* Printer supports supply levels? */ + http_addrlist_t *addr; /* Socket address */ + int have_supplies; /* Printer supports supply levels? */ int copy; /* Copies written */ time_t start_time; /* Time of first connect */ - int recoverable; /* Recoverable error shown? */ size_t nbytes; /* Number of bytes written */ off_t tbytes; /* Total bytes written */ char buffer[32768]; /* Output buffer */ @@ -679,27 +688,10 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ #endif /* HAVE_SIGSET */ /* - * Find the printer... - */ - - sprintf(portname, "%d", port); - - fputs("STATE: +connecting-to-device\n", stderr); - fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname); - - if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) - { - _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"), - hostname); - return (CUPS_BACKEND_STOP); - } - - /* * Remember when we started trying to connect to the printer... */ - recoverable = 0; - start_time = time(NULL); + start_time = time(NULL); /* * Loop forever trying to print the file... @@ -712,23 +704,19 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ */ fprintf(stderr, "DEBUG: Connecting to %s:%d for printer %s\n", hostname, - port, printer); - _cupsLangPuts(stderr, _("INFO: Connecting to printer...\n")); + _httpAddrPort(&(addrlist->addr)), printer); + _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer.")); for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist, delay = 5;; addr = addr->next) { /* - * Stop if this job has been cancelled... + * Stop if this job has been canceled... */ if (abort_job) - { - httpAddrFreeList(addrlist); - return (CUPS_BACKEND_FAILED); - } /* * Choose the next priviledged port... @@ -756,7 +744,7 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0) { - _cupsLangPrintError(_("ERROR: Unable to create socket")); + perror("DEBUG: Unable to create socket"); sleep(1); continue; @@ -773,7 +761,7 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0) { - _cupsLangPrintError(_("ERROR: Unable to reserve port")); + perror("DEBUG: Unable to reserve port"); sleep(1); continue; @@ -786,8 +774,6 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (abort_job) { - httpAddrFreeList(addrlist); - close(fd); return (CUPS_BACKEND_FAILED); @@ -811,11 +797,9 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ * available printer in the class. */ - _cupsLangPuts(stderr, - _("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); - - httpAddrFreeList(addrlist); + _cupsLangPrintFilter(stderr, "INFO", + _("Unable to contact printer, queuing on next " + "printer in class.")); /* * Sleep 5 seconds to keep the job from requeuing too rapidly... @@ -826,20 +810,38 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ return (CUPS_BACKEND_FAILED); } + fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(error)); + if (error == ECONNREFUSED || error == EHOSTDOWN || error == EHOSTUNREACH) { if (contimeout && (time(NULL) - start_time) > contimeout) { - _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("The printer is not responding.")); return (CUPS_BACKEND_FAILED); } - recoverable = 1; - - _cupsLangPrintf(stderr, - _("WARNING: recoverable: Network host \'%s\' is busy; " - "will retry in %d seconds...\n"), hostname, delay); + switch (error) + { + case EHOSTDOWN : + _cupsLangPrintFilter(stderr, "WARNING", + _("The printer may not exist or " + "is unavailable at this time.")); + break; + + case EHOSTUNREACH : + _cupsLangPrintFilter(stderr, "WARNING", + _("The printer is unreachable at " + "this time.")); + break; + + case ECONNREFUSED : + default : + _cupsLangPrintFilter(stderr, "WARNING", + _("The printer is busy.")); + break; + } sleep(delay); @@ -856,49 +858,26 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ } else { - recoverable = 1; - - fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno)); - _cupsLangPuts(stderr, - _("ERROR: recoverable: Unable to connect to printer; " - "will retry in 30 seconds...\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("The printer is not responding.")); sleep(30); } } - if (recoverable) - { - /* - * If we've shown a recoverable error make sure the printer proxies - * have a chance to see the recovered message. Not pretty but - * necessary for now... - */ - - fputs("INFO: recovered: \n", stderr); - sleep(5); - } - fputs("STATE: -connecting-to-device\n", stderr); - _cupsLangPuts(stderr, _("INFO: Connected to printer...\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer.")); -#ifdef AF_INET6 - if (addr->addr.addr.sa_family == AF_INET6) - fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6) (local port %d)...\n", - httpAddrString(&addr->addr, addrname, sizeof(addrname)), - ntohs(addr->addr.ipv6.sin6_port), lport); - else -#endif /* AF_INET6 */ - if (addr->addr.addr.sa_family == AF_INET) - fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4) (local port %d)...\n", - httpAddrString(&addr->addr, addrname, sizeof(addrname)), - ntohs(addr->addr.ipv4.sin_port), lport); + fprintf(stderr, "DEBUG: Connected to %s:%d (local port %d)...\n", + httpAddrString(&(addr->addr), addrname, sizeof(addrname)), + _httpAddrPort(&(addr->addr)), lport); /* * See if the printer supports SNMP... */ - if ((snmp_fd = _cupsSNMPOpen(addr->addr.addr.sa_family)) >= 0) - have_supplies = !backendSNMPSupplies(snmp_fd, &(addr->addr), NULL, NULL); + if (snmp_fd >= 0) + have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr), NULL, + NULL); else have_supplies = 0; @@ -906,7 +885,7 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ * Check for side-channel requests... */ - backendCheckSideChannel(snmp_fd, &(addr->addr)); + backendCheckSideChannel(snmp_fd, &(addrlist->addr)); /* * Next, open the print file and figure out its size... @@ -920,10 +899,9 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (fstat(print_fd, &filestats)) { - httpAddrFreeList(addrlist); close(fd); - _cupsLangPrintError(_("ERROR: unable to stat print file")); + perror("DEBUG: unable to stat print file"); return (CUPS_BACKEND_FAILED); } @@ -951,7 +929,6 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (lpd_command(fd, timeout, "\002%s\n", printer)) /* Receive print job(s) */ { - httpAddrFreeList(addrlist); close(fd); return (CUPS_BACKEND_FAILED); } @@ -1004,19 +981,19 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control), (int)getpid() % 1000, localhost)) { - httpAddrFreeList(addrlist); close(fd); return (CUPS_BACKEND_FAILED); } - _cupsLangPrintf(stderr, _("INFO: Sending control file (%u bytes)\n"), - (unsigned)strlen(control)); + fprintf(stderr, "DEBUG: Sending control file (%u bytes)\n", + (unsigned)strlen(control)); if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1)) { status = errno; - _cupsLangPrintError(_("ERROR: Unable to write control file")); + perror("DEBUG: Unable to write control file"); + } else { @@ -1024,9 +1001,9 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (read(fd, &status, 1) < 1) { - _cupsLangPrintf(stderr, - _("WARNING: Remote host did not respond with control " - "status byte after %d seconds!\n"), timeout); + _cupsLangPrintFilter(stderr, "WARNING", + _("Printer did not respond after %d seconds."), + timeout); status = errno; } @@ -1034,11 +1011,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ } if (status != 0) - _cupsLangPrintf(stderr, - _("ERROR: Remote host did not accept control file " - "(%d)\n"), status); + _cupsLangPrintFilter(stderr, "ERROR", + _("Remote host did not accept control file (%d)."), + status); else - _cupsLangPuts(stderr, _("INFO: Control file sent successfully\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Control file sent successfully.")); } else status = 0; @@ -1059,19 +1037,13 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ CUPS_LLCAST filestats.st_size, (int)getpid() % 1000, localhost)) { - httpAddrFreeList(addrlist); close(fd); return (CUPS_BACKEND_FAILED); } - _cupsLangPrintf(stderr, -#ifdef HAVE_LONG_LONG - _("INFO: Sending data file (%lld bytes)\n"), -#else - _("INFO: Sending data file (%ld bytes)\n"), -#endif /* HAVE_LONG_LONG */ - CUPS_LLCAST filestats.st_size); + fprintf(stderr, "DEBUG: Sending data file (" CUPS_LLFMT " bytes)\n", + CUPS_LLCAST filestats.st_size); tbytes = 0; for (copy = 0; copy < manual_copies; copy ++) @@ -1080,13 +1052,13 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ while ((nbytes = read(print_fd, buffer, sizeof(buffer))) > 0) { - _cupsLangPrintf(stderr, - _("INFO: Spooling LPR job, %.0f%% complete...\n"), - 100.0 * tbytes / filestats.st_size); + _cupsLangPrintFilter(stderr, "INFO", + _("Spooling job, %.0f%% complete."), + 100.0 * tbytes / filestats.st_size); if (lpd_write(fd, buffer, nbytes) < nbytes) { - _cupsLangPrintError(_("ERROR: Unable to send print file to printer")); + perror("DEBUG: Unable to send print file to printer"); break; } else @@ -1100,7 +1072,7 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ status = errno; else if (lpd_write(fd, "", 1) < 1) { - _cupsLangPrintError(_("ERROR: Unable to send trailing nul to printer")); + perror("DEBUG: Unable to send trailing nul to printer"); status = errno; } else @@ -1116,9 +1088,9 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (recv(fd, &status, 1, 0) < 1) { - _cupsLangPrintf(stderr, - _("WARNING: Remote host did not respond with data " - "status byte after %d seconds!\n"), timeout); + _cupsLangPrintFilter(stderr, "WARNING", + _("Printer did not respond after %d seconds."), + timeout); status = 0; } @@ -1129,11 +1101,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ status = 0; if (status != 0) - _cupsLangPrintf(stderr, - _("ERROR: Remote host did not accept data file (%d)\n"), - status); + _cupsLangPrintFilter(stderr, "ERROR", + _("Remote host did not accept data file (%d)."), + status); else - _cupsLangPuts(stderr, _("INFO: Data file sent successfully\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Data file sent successfully.")); } if (status == 0 && order == ORDER_DATA_CONTROL) @@ -1151,19 +1124,18 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control), (int)getpid() % 1000, localhost)) { - httpAddrFreeList(addrlist); close(fd); return (CUPS_BACKEND_FAILED); } - _cupsLangPrintf(stderr, _("INFO: Sending control file (%lu bytes)\n"), - (unsigned long)strlen(control)); + fprintf(stderr, "DEBUG: Sending control file (%lu bytes)\n", + (unsigned long)strlen(control)); if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1)) { status = errno; - _cupsLangPrintError(_("ERROR: Unable to write control file")); + perror("DEBUG: Unable to write control file"); } else { @@ -1171,9 +1143,9 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (read(fd, &status, 1) < 1) { - _cupsLangPrintf(stderr, - _("WARNING: Remote host did not respond with control " - "status byte after %d seconds!\n"), timeout); + _cupsLangPrintFilter(stderr, "WARNING", + _("Printer did not respond after %d seconds."), + timeout); status = errno; } @@ -1181,11 +1153,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ } if (status != 0) - _cupsLangPrintf(stderr, - _("ERROR: Remote host did not accept control file " - "(%d)\n"), status); + _cupsLangPrintFilter(stderr, "ERROR", + _("Remote host did not accept control file (%d)."), + status); else - _cupsLangPuts(stderr, _("INFO: Control file sent successfully\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Control file sent successfully.")); } /* @@ -1202,11 +1175,7 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ close(fd); if (status == 0) - { - httpAddrFreeList(addrlist); - return (CUPS_BACKEND_OK); - } /* * Waiting for a retry... @@ -1215,10 +1184,8 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ sleep(30); } - httpAddrFreeList(addrlist); - /* - * If we get here, then the job has been cancelled... + * If we get here, then the job has been canceled... */ return (CUPS_BACKEND_FAILED); @@ -1310,12 +1277,7 @@ rresvport_af(int *port, /* IO - Port number to bind to */ * Set the port number... */ -# ifdef AF_INET6 - if (family == AF_INET6) - addr.ipv6.sin6_port = htons(*port); - else -# endif /* AF_INET6 */ - addr.ipv4.sin_port = htons(*port); + _httpAddrSetPort(&addr, *port); /* * Try binding the port to the socket; return if all is OK... @@ -1376,5 +1338,5 @@ sigterm_handler(int sig) /* I - Signal */ /* - * End of "$Id: lpd.c 8938 2009-12-18 23:52:01Z mike $". + * End of "$Id: lpd.c 9793 2011-05-20 03:49:49Z mike $". */ diff --git a/backend/network.c b/backend/network.c index ee5ef5e1..d5827c46 100644 --- a/backend/network.c +++ b/backend/network.c @@ -1,9 +1,9 @@ /* - * "$Id: network.c 8896 2009-11-20 01:27:57Z mike $" + * "$Id: network.c 9578 2011-03-04 18:44:47Z mike $" * - * Common network APIs for the Common UNIX Printing System (CUPS). + * Common backend network APIs for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 2006-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -279,6 +279,12 @@ backendNetworkSideCB( break; } + case CUPS_SC_CMD_GET_CONNECTED : + status = CUPS_SC_STATUS_OK; + data[0] = device_fd != -1; + datalen = 1; + break; + default : status = CUPS_SC_STATUS_NOT_IMPLEMENTED; datalen = 0; @@ -290,5 +296,5 @@ backendNetworkSideCB( /* - * End of "$Id: network.c 8896 2009-11-20 01:27:57Z mike $". + * End of "$Id: network.c 9578 2011-03-04 18:44:47Z mike $". */ diff --git a/backend/pap.c b/backend/pap.c deleted file mode 100644 index c69bbaf5..00000000 --- a/backend/pap.c +++ /dev/null @@ -1,1696 +0,0 @@ -/* -* "$Id: pap.c 8807 2009-08-31 18:45:43Z mike $" -* -* Copyright 2004-2008 Apple 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. -* -* -* 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 file. -* papOpen() - Open a pap session to a printer. -* papClose() - Close a pap session. -* papWrite() - Write bytes to a printer. -* papCloseResp() - Send a pap close response. -* papSendRequest() - Fomrat and send a pap packet. -* papCancelRequest() - Cancel a pending pap request. -* sidechannel_request() - Handle side-channel requests. -* statusUpdate() - Print printer status to stderr. -* parseUri() - Extract the print name and zone from a uri. -* addPercentEscapes() - Encode a string with percent escapes. -* 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. -*/ - -/* - * This backend uses deprecated APIs for AppleTalk; we know this, so - * silence any warnings about it... - */ - -#ifdef MAC_OS_X_VERSION_MIN_REQUIRED -# undef MAC_OS_X_VERSION_MIN_REQUIRED -#endif /* MAX_OS_X_VERSION_MIN_REQUIRED */ -#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_0 - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <termios.h> -#include <unistd.h> -#include <assert.h> -#include <signal.h> - -#include <sys/fcntl.h> -#include <sys/param.h> -#include <sys/time.h> -#include <sys/errno.h> - -#include <cups/cups.h> -#include <cups/backend.h> -#include <cups/sidechannel.h> -#include <cups/i18n.h> - -#include <netat/appletalk.h> -#include <netat/atp.h> -#include <netat/ddp.h> -#include <netat/nbp.h> -#include <netat/pap.h> - -#include <libkern/OSByteOrder.h> - -#ifdef HAVE_APPLETALK_AT_PROTO_H -# include <AppleTalk/at_proto.h> -#else -/* These definitions come from at_proto.h... */ -# define ZIP_DEF_INTERFACE NULL -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_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 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 zip_getmyzone(char *ifName, at_nvestr_t *zone); -#endif /* HAVE_APPLETALK_AT_PROTO_H */ - -#include <CoreFoundation/CFURL.h> -#include <CoreFoundation/CFNumber.h> -#include <CoreFoundation/CFPreferences.h> - -/* Defines */ -#define MAX_PRINTERS 500 /* Max number of printers we can lookup */ -#define PAP_CONNID 0 -#define PAP_TYPE 1 -#define PAP_EOF 2 - -#define CONNID_OF(p) (((u_char *)&p)[0]) -#define TYPE_OF(p) (((u_char *)&p)[1]) -#define SEQUENCE_NUM(p) (((u_char *)&p)[2]) -#define IS_PAP_EOF(p) (((u_char *)&p)[2]) - -#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 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: 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(); -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 sidechannel_request(); -static void statusUpdate(char* status, u_char statusLen); -static int parseUri(const char* argv0, char* name, char* type, char* zone); -static int addPercentEscapes(const char* src, char* dst, int dstMax); -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); - - -/*! - * @function main - * @abstract Send a file to the specified AppleTalk PAP address. - * - * Usage: printer-uri job-id user title copies options [file] - * - * @param argc # of arguments - * @param argv array of arguments - * - * @result A non-zero return value for errors - */ -int main (int argc, const char * argv[]) -{ - int err = 0; - FILE *fp; /* Print file */ - int copies; /* Number of copies to print */ - char name[NBP_NVE_STR_SIZE + 1]; /* +1 for a nul */ - char type[NBP_NVE_STR_SIZE + 1]; /* +1 for a nul */ - char zone[NBP_NVE_STR_SIZE + 1]; /* +1 for a nul */ - - /* Make sure status messages are not buffered... */ - setbuf(stderr, NULL); - - if (argc == 1 || (argc == 2 && strcmp(argv[1], "-discover") == 0)) - { - listDevices(); - - return 0; - } - - if (argc < 6 || argc > 7) - { - _cupsLangPrintf(stderr, - _("Usage: %s job-id user title copies options [file]\n"), - argv[0]); - return (CUPS_BACKEND_FAILED); - } - - /* If we have 7 arguments, print the file named on the command-line. - * Otherwise, send stdin instead... - */ - if (argc == 6) - { - fp = stdin; - copies = 1; - } - else - { - fprintf(stderr, "DEBUG: opening print file \"%s\"\n", argv[6]); - - /* Try to open the print file... */ - if ((fp = fopen(argv[6], "rb")) == NULL) - { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open print file \"%s\": %s\n"), - argv[6], strerror(errno)); - return (CUPS_BACKEND_FAILED); - } - - copies = atoi(argv[4]); - } - - /* Extract the device name and options from the URI... */ - parseUri(cupsBackendDeviceURI((char **)argv), name, type, zone); - - err = printFile(name, type, zone, fileno(fp), STDOUT_FILENO, STDERR_FILENO, copies, argc); - - if (fp != stdin) - fclose(fp); - - /* Only clear the last status if there wasn't an error */ - if (err == noErr && !gErrorlogged) - fprintf(stderr, "INFO:\n"); - - return err; -} - - -/*! - * @function listDevices - * @abstract Print a list of all LaserWriter type devices registered in the default zone. - * - * @result A non-zero return value for errors - */ -static int listDevices(void) -{ - int i; - int numberFound; - - at_nvestr_t at_zone; - at_entity_t entity; - at_nbptuple_t buf[MAX_PRINTERS]; - at_retry_t retry; - char name[NBP_NVE_STR_SIZE+1]; - char encodedName[(3 * NBP_NVE_STR_SIZE) + 1]; - char zone[NBP_NVE_STR_SIZE+1]; - char encodedZone[(3 * NBP_NVE_STR_SIZE) + 1]; - - /* Make sure it's okay to use appletalk */ - if (!okayToUseAppleTalk()) - { - _cupsLangPuts(stderr, _("INFO: AppleTalk disabled in System Preferences\n")); - return -1; /* Network is down */ - } - - if (zip_getmyzone(ZIP_DEF_INTERFACE, &at_zone)) - { - _cupsLangPrintError(_("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'; - - _cupsLangPrintf(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); - retry.retries = 1; - retry.interval = 1; - retry.backoff = 1; - - if ((numberFound = nbp_lookup(&entity, buf, MAX_PRINTERS, &retry)) < 0) - { - _cupsLangPrintError(_("ERROR: Unable to lookup AppleTalk printers")); - return numberFound; - } - - if (numberFound >= MAX_PRINTERS) - _cupsLangPrintf(stderr, - _("WARNING: Adding only the first %d printers found"), - MAX_PRINTERS); - - /* Not required but sort them so they look nice */ - qsort(buf, numberFound, sizeof(at_nbptuple_t), nbptuple_compare); - - for (i = 0; i < numberFound; i++) - { - 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) - { - /* Each line is of the form: "class URI "make model" "info" */ - char make_model[128], /* Make and model */ - *ptr; - - - if ((ptr = strchr(name, ' ')) != NULL) - { - /* - * If the printer name contains spaces, it is probably a make and - * model... - */ - - if (!strncmp(name, "ET00", 4)) - { - /* - * Drop leading ethernet address info... - */ - - strlcpy(make_model, ptr + 1, sizeof(make_model)); - } - else - strlcpy(make_model, name, sizeof(make_model)); - } - else - strcpy(make_model, "Unknown"); - - printf("network pap://%s/%s/LaserWriter \"%s\" \"%s AppleTalk\"\n", - encodedZone, encodedName, make_model, name); - } - } - return numberFound; -} - - -/*! - * @function printFile - * @abstract Open a PAP session and send the data from the input socket to the printer. - * - * @param name NBP name - * @param zone NBP zone - * @param type NBP type - * @param fdin File descriptor to read data from - * @param fdout File descriptor to write printer responses to - * @param fderr File descriptor to write printer status to - * @param copies # of copies to send (in case in the converter couldn't handle this for us). - * @param argc # of command line arguments. - * - * @result A non-zero return value for errors - */ -static int printFile(char* name, char* type, char* zone, int fdin, int fdout, int fderr, int copies, int argc) -{ - int err; - int rc; - int val; - int len, i; - - char fileBuffer[4096]; /* File buffer */ - int fileBufferNbytes; - off_t fileTbytes; - int fileEOFRead; - int fileEOFSent; - - char sockBuffer[4096 + 1]; /* Socket buffer with room for nul */ - char atpReqBuf[AT_PAP_DATA_SIZE]; - fd_set readSet; - int use_sidechannel; /* Use side channel? */ - - at_nbptuple_t tuple; - at_inet_t sendDataAddr; - at_inet_t src; - at_resp_t resp; - int userdata, xo = 0, reqlen; - u_short tid; - u_char bitmap; - int maxfdp1, - nbp_failures = 0; - struct timeval timeout, *timeoutPtr; - u_char flowQuantum = 1; - time_t now, - start_time, - elasped_time, - sleep_time, - connect_timeout = -1, - nextStatusTime = 0; - at_entity_t entity; - at_retry_t retry; - -#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ -#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ - - /* - * Test the side channel descriptor before calling papOpen() since it may open - * an unused fd 4 (a.k.a. CUPS_SC_FD)... - */ - - FD_ZERO(&readSet); - FD_SET(CUPS_SC_FD, &readSet); - - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - if ((select(CUPS_SC_FD+1, &readSet, NULL, NULL, &timeout)) >= 0) - use_sidechannel = 1; - else - use_sidechannel = 0; - - /* try to find our printer */ - if ((err = nbp_make_entity(&entity, name, type, zone)) != noErr) - { - _cupsLangPrintError(_("ERROR: Unable to make AppleTalk address")); - goto Exit; - } - - /* - * Remember when we started looking for the printer. - */ - - 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 (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; - - _cupsLangPrintf(stderr, _("WARNING: Unable to open \"%s:%s\": %s\n"), - name, zone, strerror(err)); - } - else - { - /* 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"); - _cupsLangPuts(stderr, _("WARNING: Printer not responding\n")); - } - } - } - else - { - fprintf(stderr, "STATE: +apple-appletalk-disabled-warning\n"); - _cupsLangPuts(stderr, - _("INFO: AppleTalk disabled in System Preferences.\n")); - } - - elasped_time = time(NULL) - start_time; - - if (connect_timeout == -1) - connect_timeout = connectTimeout(); - - if (connect_timeout && elasped_time > connect_timeout) - { - _cupsLangPuts(stderr, _("ERROR: Printer not responding\n")); - err = ETIMEDOUT; - goto Exit; /* Waiting too long... */ - } - else if (elasped_time < (30 * 60)) - sleep_time = 10; /* Waiting < 30 minutes */ - else if (elasped_time < (24 * 60 * 60)) - sleep_time = 30; /* Waiting < 24 hours */ - else - sleep_time = 60; /* Waiting > 24 hours */ - - fprintf(stderr, "DEBUG: sleeping %d seconds...\n", (int)sleep_time); - 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 - * current page... if we are printing data from a file then catch the - * signal so we can send a PAP Close packet (otherwise you can't cancel - * raw jobs...) - */ - -#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ - sigset(SIGTERM, (argc < 7) ? SIG_IGN : signalHandler); -#elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - - sigemptyset(&action.sa_mask); - action.sa_handler = (argc < 7) ? SIG_IGN : signalHandler; - sigaction(SIGTERM, &action, NULL); -#else - signal(SIGTERM, (argc < 7) ? SIG_IGN : signalHandler); - -#ifdef DEBUG - /* Makes debugging easier; otherwise printer will be busy for several minutes */ - signal(SIGINT, signalHandler); -#endif /* DEBUG */ - -#endif /* HAVE_SIGSET */ - - _cupsLangPuts(stderr, _("INFO: Sending data\n")); - - sendDataAddr = tuple.enu_addr; - - /* Start the tickle packets and set a timeout alarm */ - if ((err = papSendRequest(gSockfd, &gSessionAddr, gConnID, AT_PAP_TYPE_TICKLE, 0, false, false)) < 0) - { - _cupsLangPrintError(_("ERROR: Unable to send PAP tickle request")); - goto Exit; - } - signal(SIGALRM, signalHandler); - alarm(PAP_TIMEOUT); - - /* Prime the pump with an initial send-data packet */ - if ((err = papSendRequest(gSockfd, &gSessionAddr, gConnID, AT_PAP_TYPE_SEND_DATA, 0xFF, true, true)) < 0) - { - _cupsLangPrintError(_("ERROR: Unable to send initial PAP send data request")); - goto Exit; - } - - /* Set non-blocking mode on our data source descriptor */ - val = fcntl(fdin, F_GETFL, 0); - fcntl(fdin, F_SETFL, val | O_NONBLOCK); - - fileBufferNbytes = 0; - fileTbytes = 0; - fileEOFRead = fileEOFSent = false; - - maxfdp1 = MAX(fdin, gSockfd) + 1; - - if (use_sidechannel && CUPS_SC_FD >= maxfdp1) - maxfdp1 = CUPS_SC_FD + 1; - - if (gStatusInterval != 0) - { - timeout.tv_usec = 0; - nextStatusTime = time(NULL) + gStatusInterval; - timeoutPtr = &timeout; - } - else - timeoutPtr = NULL; - - - for (;;) - { - /* Set up our descriptors for the select */ - FD_ZERO(&readSet); - FD_SET(gSockfd, &readSet); - - if (fileBufferNbytes == 0 && fileEOFRead == false) - FD_SET(fdin, &readSet); - - if (use_sidechannel) - FD_SET(CUPS_SC_FD, &readSet); - - /* Set the select timeout value based on the next status interval */ - if (gStatusInterval != 0) - { - now = time(NULL); - timeout.tv_sec = (nextStatusTime > now) ? nextStatusTime - now : 1; - } - - /* Wait here for something interesting to happen */ - if ((err = select(maxfdp1, &readSet, 0, 0, timeoutPtr)) < 0) - { - _cupsLangPrintError(_("ERROR: select() failed")); - break; - } - - if (err == 0 || (gStatusInterval != 0 && time(NULL) >= nextStatusTime)) - { - /* Time to send a status request */ - if ((err = papSendRequest(gSockfd, &tuple.enu_addr, 0, AT_PAP_TYPE_SEND_STATUS, 0x01, false, false)) < 0) - _cupsLangPrintError(_("WARNING: Unable to send PAP status request")); - - if (gStatusInterval) - nextStatusTime = time(NULL) + gStatusInterval; - } - - /* - * Check if we have a side-channel request ready... - */ - - if (use_sidechannel && FD_ISSET(CUPS_SC_FD, &readSet)) - sidechannel_request(); - - /* Was there an event on the input stream? */ - if (FD_ISSET(fdin, &readSet)) - { - FD_CLR(fdin, &readSet); - - assert(fileBufferNbytes == 0); - fileBufferNbytes = read(fdin, fileBuffer, MIN(sizeof(fileBuffer), AT_PAP_DATA_SIZE * flowQuantum)); - if (fileBufferNbytes == 0) - fileEOFRead = true; - - if (fileEOFSent == false && fileBufferNbytes >= 0 && gSendDataID != 0) - { - fprintf(stderr, "DEBUG: -> PAP_DATA %d bytes %s\n", fileBufferNbytes, fileEOFRead ? "with EOF" : ""); - papWrite(gSockfd, &sendDataAddr, gSendDataID, gConnID, flowQuantum, fileBuffer, fileBufferNbytes, fileEOFRead); - - fileTbytes += fileBufferNbytes; - if (argc > 6 && !gErrorlogged) - fprintf(stderr, "DEBUG: Sending print file, %qd bytes\n", (off_t)fileTbytes); - - fileBufferNbytes = 0; - gSendDataID = 0; - if (fileEOFRead) - { - fileEOFSent = true; - if (gWaitEOF == false || fileTbytes == 0) - { - err = 0; - goto Exit; - } - } - } - } - - /* Was there an event on the output stream? */ - if (FD_ISSET(gSockfd, &readSet)) - { - if ((rc = atp_look(gSockfd)) < 0) - { - _cupsLangPrintError(_("ERROR: Unable to look for PAP response")); - break; - } - - if (rc > 0) - { - /* It's an ATP response */ - resp.resp[0].iov_base = sockBuffer; - resp.resp[0].iov_len = sizeof(sockBuffer) - 1; - resp.bitmap = 0x01; - - if ((err = atp_getresp(gSockfd, &tid, &resp)) < 0) - { - _cupsLangPrintError(_("ERROR: Unable to get PAP response")); - break; - } - userdata = resp.userdata[0]; - } - else - { - /* It's an ATP request */ - reqlen = sizeof(atpReqBuf); - if ((err = atp_getreq(gSockfd, &src, atpReqBuf, &reqlen, &userdata, &xo, &tid, &bitmap, 0)) < 0) - { - _cupsLangPrintError(_("ERROR: Unable to get PAP request")); - break; - } - } - - fprintf(stderr, "DEBUG: <- %s\n", packet_name(TYPE_OF(userdata))); - - switch (TYPE_OF(userdata)) - { - case AT_PAP_TYPE_SEND_STS_REPLY: /* Send-Status-Reply packet */ - if (resp.bitmap & 1) - { - char *iov_base = (char *)resp.resp[0].iov_base; - statusUpdate(&iov_base[5], iov_base[4]); - } - break; - - case AT_PAP_TYPE_SEND_DATA: /* Send-Data packet */ - sendDataAddr.socket = src.socket; - gSendDataID = tid; - OSReadBigInt16(&SEQUENCE_NUM(userdata), 0); - - if ((fileBufferNbytes > 0 || fileEOFRead) && fileEOFSent == false) - { - fprintf(stderr, "DEBUG: -> PAP_DATA %d bytes %s\n", fileBufferNbytes, fileEOFRead ? "with EOF" : ""); - papWrite(gSockfd, &sendDataAddr, gSendDataID, gConnID, flowQuantum, fileBuffer, fileBufferNbytes, fileEOFRead); - - fileTbytes += fileBufferNbytes; - if (argc > 6 && !gErrorlogged) - fprintf(stderr, "DEBUG: Sending print file, %qd bytes\n", (off_t)fileTbytes); - - fileBufferNbytes = 0; - gSendDataID = 0; - if (fileEOFRead) - { - fileEOFSent = true; - if (gWaitEOF == false) - { - err = 0; - goto Exit; - } - } - } - break; - - case AT_PAP_TYPE_DATA: /* Data packet */ - for (len=0, i=0; i < ATP_TRESP_MAX; i++) - { - 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" : ""); - - if (len > 0) - { - char *pLineBegin, *pCommentEnd, *pChar; - char *logLevel; - char logstr[512]; - int logstrlen; - - cupsBackChannelWrite(sockBuffer, len, 1.0); - - sockBuffer[len] = '\0'; /* We always reserve room for the nul so we can use strstr() below*/ - pLineBegin = sockBuffer; - - /* If there are PostScript status comments in the buffer log them. - * - * This logic shouldn't be in the backend but until we get backchannel - * data in CUPS 1.2 it has to live here. - */ - while (pLineBegin < sockBuffer + len && - (pLineBegin = strstr(pLineBegin, "%%[")) != NULL && - (pCommentEnd = strstr(pLineBegin, "]%%")) != NULL) - { - pCommentEnd += 3; /* Skip past "]%%" */ - *pCommentEnd = '\0'; /* There's always room for the nul */ - - /* Strip the CRs & LFs before writing it to stderr */ - for (pChar = pLineBegin; pChar < pCommentEnd; pChar++) - if (*pChar == '\r' || *pChar == '\n') - *pChar = ' '; - - if (strncasecmp(pLineBegin, "%%[ Error:", 10) == 0) - { - /* logLevel should be "ERROR" here but this causes PrintCenter - * to pause the queue which in turn clears this error, which - * restarts the job. So the job ends up in an infinite loop with - * the queue being held/un-held. Just make it DEBUG for now until - * we fix notifications later. - */ - logLevel = "DEBUG"; - gErrorlogged = true; - } - else if (strncasecmp(pLineBegin, "%%[ Flushing", 12) == 0) - logLevel = "DEBUG"; - else - logLevel = "INFO"; - - if ((logstrlen = snprintf(logstr, sizeof(logstr), "%s: %s\n", logLevel, pLineBegin)) >= 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(fderr, logstr, logstrlen); - - pLineBegin = pCommentEnd + 1; - } - } - - if (IS_PAP_EOF(userdata) != 0) - { - /* If this is EOF then were we expecting it? */ - if (fileEOFSent == true) - goto Exit; - else - { - _cupsLangPuts(stderr, _("WARNING: Printer sent unexpected EOF\n")); - } - } - - if ((err = papSendRequest(gSockfd, &gSessionAddr, gConnID, AT_PAP_TYPE_SEND_DATA, 0xFF, true, true)) < 0) - { - _cupsLangPrintf(stderr, - _("ERROR: Error %d sending PAPSendData request: %s\n"), - err, strerror(errno)); - goto Exit; - } - break; - - case AT_PAP_TYPE_TICKLE: /* Tickle packet */ - break; - - case AT_PAP_TYPE_CLOSE_CONN: /* Close-Connection packet */ - /* We shouldn't normally see this. */ - papCloseResp(gSockfd, &gSessionAddr, xo, tid, gConnID); - - /* If this is EOF then were we expecting it? */ - if (fileEOFSent == true) - { - _cupsLangPuts(stderr, _("WARNING: Printer sent unexpected EOF\n")); - } - else - { - _cupsLangPuts(stderr, _("ERROR: Printer sent unexpected EOF\n")); - } - goto Exit; - break; - - case AT_PAP_TYPE_OPEN_CONN: /* Open-Connection packet */ - case AT_PAP_TYPE_OPEN_CONN_REPLY: /* Open-Connection-Reply packet */ - case AT_PAP_TYPE_SEND_STATUS: /* Send-Status packet */ - case AT_PAP_TYPE_CLOSE_CONN_REPLY: /* Close-Connection-Reply packet */ - _cupsLangPrintf(stderr, _("WARNING: Unexpected PAP packet of type %d\n"), - TYPE_OF(userdata)); - break; - - default: - _cupsLangPrintf(stderr, _("WARNING: Unknown PAP packet of type %d\n"), - TYPE_OF(userdata)); - break; - } - - if (CONNID_OF(userdata) == gConnID) - { - /* Reset tickle timer */ - alarm(0); - alarm(PAP_TIMEOUT); - } - } - } - -Exit: - /* - * Close the socket and return... - */ - papClose(); - - return err; -} - - -#pragma mark - -/*! - * @function papOpen - * @abstract Open a pap session to a printer. - * - * @param tuple nbp address of printer - * @param connID returned pap connection id - * @param fd returned socket descriptor - * @param sessionAddr returned session address - * @param flowQuantum returned flow quantum (usually 8) - * - * @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) -{ - int result, - open_result, - userdata; - 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; - - result = 0; - socketfd = 0; - puserdata = (u_char *)&userdata; - - _cupsLangPuts(stderr, _("INFO: Opening connection\n")); - - if ((*fd = atp_open(&socketfd)) < 0) - return -1; - - /* - * Build the open connection request packet. - */ - - tm = time(NULL); - srand(tm); - - *connID = (rand()&0xff) | 0x01; - puserdata[0] = *connID; - puserdata[1] = AT_PAP_TYPE_OPEN_CONN; - puserdata[2] = 0; - puserdata[3] = 0; - - retry.interval = 2; - retry.retries = 5; - - resp.bitmap = 0x01; - resp.resp[0].iov_base = rdata; - resp.resp[0].iov_len = sizeof(rdata); - - data[0] = socketfd; - data[1] = 8; - - for (;;) - { - waitTime = time(NULL) - tm; - OSWriteBigInt16(&data[2], 0, (u_short)waitTime); - - fprintf(stderr, "DEBUG: -> %s\n", packet_name(AT_PAP_TYPE_OPEN_CONN)); - - if (atp_sendreq(*fd, &tuple->enu_addr, data, 4, userdata, 1, 0, - 0, &resp, &retry, 0) < 0) - { - statusUpdate("Destination unreachable", 23); - result = EHOSTUNREACH; - break; - } - - puserdata = (u_char *)&resp.userdata[0]; - open_result = OSReadBigInt16(&rdata[2], 0); - - fprintf(stderr, "DEBUG: <- %s, status %d\n", packet_name(puserdata[1]), - open_result); - - /* - * 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); - } - - 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; -} - - -/*! - * @function papClose - * @abstract End a PAP session by canceling outstanding send-data & tickle - * transactions and sending a PAP close request. - * - * @result A non-zero return value for errors - */ -static int papClose() -{ - int fd; - u_short tmpID; - unsigned char rdata[ATP_DATA_SIZE]; - int userdata; - u_char *puserdata = (u_char *)&userdata; - at_resp_t resp; - at_retry_t retry; - - if (gSockfd != 0) - { - fd = gSockfd; - gSockfd = 0; - - alarm(0); - - /* Cancel the pending send-data and tickle trnsactions - */ - if (gSendDataID) - { - tmpID = gSendDataID; - gSendDataID = 0; - papCancelRequest(fd, tmpID); - } - - if (gTickleID) - { - tmpID = gTickleID; - gTickleID = 0; - papCancelRequest(fd, tmpID); - } - - /* This is a workaround for bug #2735145. The problem is papWrite() - * returns before the ATP TRel arrives for it. If we send the pap close packet - * before this release then the printer can drop the last data packets. - * The effect on an Epson printer is the last page doesn't print, on HP it - * doesn't close the pap session. - */ - if (gWaitEOF == false) - sleep(2); - - fprintf(stderr, "DEBUG: -> %s\n", packet_name(AT_PAP_TYPE_CLOSE_CONN)); - - puserdata[0] = gConnID; - puserdata[1] = AT_PAP_TYPE_CLOSE_CONN; - puserdata[2] = 0; - puserdata[3] = 0; - - retry.interval = 2; - retry.retries = 5; - - resp.bitmap = 0x01; - resp.resp[0].iov_base = rdata; - resp.resp[0].iov_len = sizeof(rdata); - - atp_sendreq(fd, &gSessionAddr, 0, 0, userdata, 1, 0, 0, &resp, &retry, 0); - - close(fd); - } - return noErr; -} - - -/*! - * @function papWrite - * @abstract Write bytes to a printer. - * - * @param sockfd socket descriptor - * @param dest destination address - * @param tid transaction id - * @param connID connection id - * @param flowQuantum returned flow quantum (usually 8) - * @param data pointer to the data - * @param len number of bytes to send - * @param eof pap eof flag - * - * @result A non-zero return value for errors - */ -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 i; - u_char* puserdata; - at_resp_t resp; - - /* fprintf(stderr, "DEBUG: papWrite(%d%s) to %d,%d,%d; %d\n", len, eof ? " EOF":"", dest->net, dest->node, dest->socket, connID); */ - - if (len > AT_PAP_DATA_SIZE * flowQuantum) - { - fprintf(stderr, "DEBUG: papWrite() len of %d is too big!\n", len); - errno = E2BIG; - return -1; - } - - /* - * Break up the outgoing data into a set of - * response packets to reply to an incoming - * PAP 'SENDDATA' request - */ - for (i = 0; i < flowQuantum; i++) - { - 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[i].iov_base = (caddr_t)data; - - if (data) - data += AT_PAP_DATA_SIZE; - - 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 << (i + 1)) - 1; - - /* - * Write out the data as a PAP 'DATA' response - */ - errno = 0; - if ((result = atp_sendrsp(sockfd, dest, true, tid, &resp)) < 0) - { - fprintf(stderr, "DEBUG: atp_sendrsp() returns %d, errno %d \"%s\"\n", result, errno, strerror(errno)); - return -1; - } - return(0); -} - - -/*! - * @function papCloseResp - * @abstract Send a pap close response in the rare case we receive a close connection request. - * - * @param sockfd socket descriptor - * @param dest destination address - * @param tid transaction id - * @param connID connection id - * - * @result A non-zero return value for errors - */ -static int papCloseResp(int sockfd, at_inet_t* dest, int xo, u_short tid, u_char connID) -{ - int result; - at_resp_t resp; - - resp.bitmap = 1; - resp.userdata[0] = 0; - - ((u_char*)&resp.userdata[0])[PAP_CONNID] = connID; - ((u_char*)&resp.userdata[0])[PAP_TYPE] = AT_PAP_TYPE_CLOSE_CONN_REPLY; - - resp.resp[0].iov_base = NULL; - resp.resp[0].iov_len = 0; - - if ((result = atp_sendrsp(sockfd, dest, xo, tid, &resp)) < 0) - { - fprintf(stderr, "DEBUG: atp_sendrsp() returns %d, errno %d \"%s\"\n", result, errno, strerror(errno)); - return -1; - } - return 0; -} - - -/*! - * @function papSendRequest - * @abstract Send a pap close response in the rare case we receive a close connection request. - * - * @param sockfd socket descriptor - * @param dest destination address - * @param function pap function - * @param bitmap bitmap - * @param xo exactly once - * @param seqno sequence number - * - * @result A non-zero return value for errors - */ -static int papSendRequest(int sockfd, at_inet_t* dest, u_char connID, int function, u_char bitmap, int xo, int seqno) -{ - u_short tid; - int err; - sigset_t sv, osv; - int userdata; - u_char *puserdata = (u_char *)&userdata; - at_retry_t retry; - at_resp_t resp; - static u_short pap_send_count = 0; - - fprintf(stderr, "DEBUG: -> %s\n", packet_name(function)); - - puserdata[0] = connID; - puserdata[1] = function; - resp.bitmap = bitmap; - retry.interval = 10; - retry.retries = -1; /* was ATP_INFINITE_RETRIES */ - if (seqno) - { - pap_send_count++; - if (pap_send_count == 0) - pap_send_count = 1; - - OSWriteBigInt16(&puserdata[2], 0, pap_send_count); - } - else - OSWriteBigInt16(&puserdata[2], 0, 0); - - sigemptyset(&sv); - sigaddset(&sv, SIGIO); - sigprocmask(SIG_SETMASK, &sv, &osv); - - err = atp_sendreq(sockfd, dest, 0, 0, userdata, xo, 0, &tid, &resp, &retry, 1); - - sigprocmask(SIG_SETMASK, &osv, NULL); - - return err; -} - - -/*! - * @function papCancelRequest - * @abstract Cancel a pending pap request. - * - * @param sockfd socket descriptor - * @param tid transaction ID - * - * @result A non-zero return value for errors - */ -int papCancelRequest(int sockfd, u_short tid) -{ - sigset_t sv, osv; - - sigemptyset(&sv); - sigaddset(&sv, SIGIO); - sigprocmask(SIG_SETMASK, &sv, &osv); - - if (atp_abort(sockfd, NULL, tid) < 0) - { - sigprocmask(SIG_SETMASK, &osv, NULL); - return -1; - } - sigprocmask(SIG_SETMASK, &osv, NULL); - - return 0; -} - - -/* - * 'sidechannel_request()' - Handle side-channel requests. - */ - -static int -sidechannel_request() -{ - 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 */ - - datalen = sizeof(data); - - if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) - return (-1); - - switch (command) - { - case CUPS_SC_CMD_GET_BIDI: /* Is the connection bidirectional? */ - data[0] = 1; - return (cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0)); - break; - - case CUPS_SC_CMD_GET_STATE: /* Return device state */ - data[0] = CUPS_SC_STATE_ONLINE; - return (cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0)); - break; - - case CUPS_SC_CMD_DRAIN_OUTPUT: /* Drain all pending output */ - case CUPS_SC_CMD_SOFT_RESET: /* Do a soft reset */ - case CUPS_SC_CMD_GET_DEVICE_ID: /* Return IEEE-1284 device ID */ - default: - return (cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED, - NULL, 0, 1.0)); - break; - } - return (0); -} - - -#pragma mark - -/*! - * @function statusUpdate - * @abstract Format and print a PAP status response to stderr. - * - * @param status The status response string - * @param statusLen The length of the status response string - */ -void statusUpdate(char* status, u_char statusLen) -{ - static char status_str[255]; - static u_char last_statusLen = 0xFF; - - /* Only send this if the status has changed */ - if (statusLen != last_statusLen || memcmp(status, status_str, statusLen) != 0) - { - if (statusLen > sizeof(status_str)-1) - statusLen = sizeof(status_str)-1; - last_statusLen = statusLen; - memcpy(status_str, status, statusLen); - status_str[(int)statusLen] = '\0'; - - /* - * Make sure the status string is in the form of a PostScript comment. - */ - - if (statusLen > 3 && memcmp(status, "%%[", 3) == 0) - fprintf(stderr, "INFO: %s\n", status_str); - else - fprintf(stderr, "INFO: %%%%[ %s ]%%%%\n", status_str); - } - return; -} - - -/*! - * @function parseUri - * @abstract Parse a PAP URI into it's NBP components. - * - * @param argv0 The PAP URI to parse - * @param name NBP name - * @param zone NBP zone - * @param type NBP type - * - * @result A non-zero return value for errors - */ -static int parseUri(const char* argv0, char* name, char* type, char* zone) -{ - char method[255], /* Method in URI */ - hostname[1024], /* Hostname */ - username[255], /* Username info (not used) */ - resource[1024], /* Resource info (device and options) */ - *resourcePtr, - *typePtr, - *options, /* Pointer to options */ - *optionName, /* Name of option */ - *value, /* Value of option */ - sep; /* Separator character */ - int port; /* Port number (not used) */ - int statusInterval; /* */ - - /* - * 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, method, sizeof(method), - username, sizeof(username), - hostname, sizeof(hostname), &port, - resource, sizeof(resource)); - - /* - * See if there are any options... - */ - if ((options = strchr(resource, '?')) != NULL) - { - /* - * Yup, terminate the device name string and move to the first - * character of the options... - */ - *options++ = '\0'; - - while (*options != '\0') - { - /* - * Get the name... - */ - - optionName = options; - - while (*options && *options != '=' && *options != '+' && *options != '&') - options ++; - - if ((sep = *options) != '\0') - *options++ = '\0'; - - if (sep == '=') - { - /* - * Get the value... - */ - - value = options; - - while (*options && *options != '+' && *options != '&') - options ++; - - if (*options) - *options++ = '\0'; - } - else - value = (char *)""; - - /* - * Process the option... - */ - - if (!strcasecmp(optionName, "waiteof")) - { - /* - * Wait for the end of the print file? - */ - - if (!strcasecmp(value, "on") || - !strcasecmp(value, "yes") || - !strcasecmp(value, "true")) - { - gWaitEOF = true; - } - else if (!strcasecmp(value, "off") || - !strcasecmp(value, "no") || - !strcasecmp(value, "false")) - { - gWaitEOF = false; - } - else - { - _cupsLangPrintf(stderr, - _("WARNING: Boolean expected for waiteof option \"%s\"\n"), - value); - } - } - else if (!strcasecmp(optionName, "status")) - { - /* - * Set status reporting interval... - */ - - statusInterval = atoi(value); - if (value[0] < '0' || value[0] > '9' || statusInterval < 0) - { - _cupsLangPrintf(stderr, - _("WARNING: number expected for status option \"%s\"\n"), - value); - } - else - { - gStatusInterval = statusInterval; - } - } - } - } - - resourcePtr = resource; - - if (*resourcePtr == '/') - resourcePtr++; - - /* If the resource has a slash we assume the slash seperates the AppleTalk object - * name from the AppleTalk type. If the slash is not present we assume the AppleTalk - * type is LaserWriter. - */ - - typePtr = strchr(resourcePtr, '/'); - if (typePtr != NULL) - { - *typePtr++ = '\0'; - } - else - { - typePtr = "LaserWriter"; - } - - removePercentEscapes(hostname, zone, NBP_NVE_STR_SIZE + 1); - removePercentEscapes(resourcePtr, name, NBP_NVE_STR_SIZE + 1); - removePercentEscapes(typePtr, type, NBP_NVE_STR_SIZE + 1); - - return 0; -} - - -/*! - * @function addPercentEscapes - * @abstract Encode a string with percent escapes - * - * @param src The source C string - * @param dst Desination buffer - * @param dstMax Size of desination buffer - * - * @result A non-zero return value for errors - */ -static int addPercentEscapes(const char* src, char* dst, int dstMax) -{ - char c; - char *dstEnd = dst + dstMax - 1; /* -1 to leave room for the NUL */ - - while (*src) - { - c = *src++; - - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || (c == '.' || c == '-' || c == '*' || c == '_')) - { - if (dst >= dstEnd) - return -1; - - *dst++ = c; - } - else - { - if (dst >= dstEnd - 2) - return -1; - - snprintf(dst, dstEnd - dst, "%%%02x", c); - dst += 3; - } - } - - *dst = '\0'; - return 0; -} - - -/*! - * @function removePercentEscapes - * @abstract Returns a string with any percent escape sequences replaced with their equivalent character - * - * @param src Source buffer - * @param srclen Number of bytes in source buffer - * @param dst Desination buffer - * @param dstMax Size of desination buffer - * - * @result A non-zero return value for errors - */ -static int removePercentEscapes(const char* src, char* dst, int dstMax) -{ - int c; - const char *dstEnd = dst + dstMax; - - while (*src && dst < dstEnd) - { - c = *src++; - - if (c == '%') - { - sscanf(src, "%02x", &c); - src += 2; - } - *dst++ = (char)c; - } - - if (dst >= dstEnd) - return -1; - - *dst = '\0'; - return 0; -} - - -/*! - * @function nbptuple_compare - * @abstract An NBP comparator for qsort. - * - * @result p1<p2: -1, p1=p2: 0, p1>p2: 1 - */ -int nbptuple_compare(const void *p1, const void *p2) -{ - int result; - int len = MIN(((at_nbptuple_t*)p1)->enu_entity.object.len, - ((at_nbptuple_t*)p2)->enu_entity.object.len); - - if ((result = memcmp(((at_nbptuple_t*)p1)->enu_entity.object.str, ((at_nbptuple_t*)p2)->enu_entity.object.str, len)) == 0) - { - if (((at_nbptuple_t*)p1)->enu_entity.object.len < ((at_nbptuple_t*)p2)->enu_entity.object.len) - result = -1; - else if (((at_nbptuple_t*)p1)->enu_entity.object.len > ((at_nbptuple_t*)p2)->enu_entity.object.len) - result = 1; - else - result = 0; - } - return result; -} - - -/*! - * @function okayToUseAppleTalk - * @abstract Returns true if AppleTalk is available and enabled. - * - * @result non-zero if AppleTalk is enabled - */ -static int okayToUseAppleTalk() -{ - int atStatus = checkATStack(); - - /* I think the test should be: - * return atStatus == RUNNING || atStatus == LOADED; - * but when I disable AppleTalk from the network control panel and - * reboot, AppleTalk shows up as loaded. The test empirically becomes - * the following: - */ - return atStatus == RUNNING; -} - - -/*! - * @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. - */ -static int connectTimeout() -{ - CFPropertyListRef value; - SInt32 connect_timeout = (7 * 24 * 60 * 60); /* Default timeout is one week... */ - - value = CFPreferencesCopyValue(CFSTR("timeout"), CFSTR("com.apple.print.backends"), - kCFPreferencesAnyUser, kCFPreferencesCurrentHost); - if (value != NULL) - { - if (CFGetTypeID(value) == CFNumberGetTypeID()) - CFNumberGetValue(value, kCFNumberSInt32Type, &connect_timeout); - - CFRelease(value); - } - - return connect_timeout; -} - - -/*! - * @function signalHandler - * @abstract A signal handler so we can clean up the pap session before exiting. - * - * @param sigraised The signal raised - * - * @result Never returns - */ -static void signalHandler(int sigraised) -{ - _cupsLangPuts(stderr, _("ERROR: There was a timeout error while sending data to the printer\n")); - - papClose(); - - _exit(1); -} diff --git a/backend/parallel.c b/backend/parallel.c index 0df2f457..a475f0e9 100644 --- a/backend/parallel.c +++ b/backend/parallel.c @@ -1,9 +1,9 @@ /* - * "$Id: parallel.c 8896 2009-11-20 01:27:57Z mike $" + * "$Id: parallel.c 9774 2011-05-12 06:15:14Z mike $" * - * Parallel port backend for the Common UNIX Printing System (CUPS). + * Parallel port backend for CUPS. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -85,7 +85,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ device_fd, /* Parallel device */ use_bc; /* Read back-channel data? */ int copies; /* Number of copies to print */ - size_t tbytes; /* Total number of bytes written */ + ssize_t tbytes; /* Total number of bytes written */ struct termios opts; /* Parallel port options */ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) struct sigaction action; /* Actions for POSIX signals */ @@ -124,7 +124,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ else if (argc < 6 || argc > 7) { _cupsLangPrintf(stderr, - _("Usage: %s job-id user title copies options [file]\n"), + _("Usage: %s job-id user title copies options [file]"), argv[0]); return (CUPS_BACKEND_FAILED); } @@ -147,9 +147,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if ((print_fd = open(argv[6], O_RDONLY)) < 0) { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open print file \"%s\": %s\n"), - argv[6], strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to open print file")); return (CUPS_BACKEND_FAILED); } @@ -217,9 +215,9 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * available printer in the class. */ - _cupsLangPuts(stderr, - _("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Unable to contact printer, queuing on next " + "printer in class.")); /* * Sleep 5 seconds to keep the job from requeuing too rapidly... @@ -232,22 +230,20 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (errno == EBUSY) { - _cupsLangPuts(stderr, - _("INFO: Printer busy; will retry in 30 seconds...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Printer busy; will retry in 30 seconds.")); sleep(30); } else if (errno == ENXIO || errno == EIO || errno == ENOENT) { - _cupsLangPuts(stderr, - _("INFO: Printer not connected; will retry in 30 " - "seconds...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Printer not connected; will retry in 30 " + "seconds.")); sleep(30); } else { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open device file \"%s\": %s\n"), - resource, strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to open device file")); return (CUPS_BACKEND_FAILED); } } @@ -287,13 +283,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ tbytes = backendRunLoop(print_fd, device_fd, -1, NULL, use_bc, 1, side_cb); if (print_fd != 0 && tbytes >= 0) - _cupsLangPrintf(stderr, -#ifdef HAVE_LONG_LONG - _("INFO: Sent print file, %lld bytes...\n"), -#else - _("INFO: Sent print file, %ld bytes...\n"), -#endif /* HAVE_LONG_LONG */ - CUPS_LLCAST tbytes); + _cupsLangPrintFilter(stderr, "INFO", _("Print file sent.")); } /* @@ -305,7 +295,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (print_fd != 0) close(print_fd); - return (tbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); + return (CUPS_BACKEND_OK); } @@ -682,5 +672,5 @@ side_cb(int print_fd, /* I - Print file */ /* - * End of "$Id: parallel.c 8896 2009-11-20 01:27:57Z mike $". + * End of "$Id: parallel.c 9774 2011-05-12 06:15:14Z mike $". */ diff --git a/backend/pseudo b/backend/pseudo new file mode 100755 index 00000000..3a82a522 --- /dev/null +++ b/backend/pseudo @@ -0,0 +1,30 @@ +#!/bin/sh +# +# "$Id$" +# +# Psuedo-backend for CUPS testing purposes. +# +# Copyright 2011 by Apple Inc. +# +# These coded instructions, statements, and computer programs are the +# property of Apple Inc. and are protected by Federal copyright +# law. Distribution and use rights are outlined in the file "LICENSE.txt" +# which should have been included with this file. If this file is +# file is missing or damaged, see the license at "http://www.cups.org/". +# +# This file is subject to the Apple OS-Developed Software exception. +# + +if test $# = 0; then + echo 'direct pseudo:///deskjet "HP DeskJet" "HP DeskJet (pseudo)" "MFG:HP;MDL:DeskJet;CMD:PCL;" "Nowhere"' + echo 'direct pseudo:///laserjet "HP LaserJet" "HP LaserJet (pseudo)" "MFG:HP;MDL:LaserJet;CMD:PCL;" "Nowhere"' + exit 0 +fi + +cat $6 >/dev/null +sleep 5 +exit 0 + +# +# End of "$Id$". +# diff --git a/backend/runloop.c b/backend/runloop.c index 6cc1b7be..21cf45df 100644 --- a/backend/runloop.c +++ b/backend/runloop.c @@ -1,9 +1,9 @@ /* - * "$Id: runloop.c 9258 2010-08-13 01:34:04Z mike $" + * "$Id: runloop.c 9820 2011-06-10 22:06:26Z mike $" * - * Common run loop APIs for CUPS. + * Common run loop APIs for CUPS backends. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 2006-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -18,6 +18,8 @@ * * backendDrainOutput() - Drain pending print data to the device. * backendRunLoop() - Read and write print and back-channel data. + * backendWaitLoop() - Wait for input from stdin while handling + * side-channel queries. */ /* @@ -90,7 +92,7 @@ backendDrainOutput(int print_fd, /* I - Print file descriptor */ if (errno != EAGAIN || errno != EINTR) { - perror("ERROR: Unable to read print data"); + _cupsLangPrintError("ERROR", _("Unable to read print data")); return (-1); } @@ -119,8 +121,7 @@ backendDrainOutput(int print_fd, /* I - Print file descriptor */ if (errno != ENOSPC && errno != ENXIO && errno != EAGAIN && errno != EINTR && errno != ENOTTY) { - _cupsLangPrintf(stderr, _("ERROR: Unable to write print data: %s\n"), - strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to write print data")); return (-1); } } @@ -142,14 +143,13 @@ backendDrainOutput(int print_fd, /* I - Print file descriptor */ ssize_t /* O - Total bytes on success, -1 on error */ backendRunLoop( - int print_fd, /* I - Print file descriptor */ - int device_fd, /* I - Device file descriptor */ - int snmp_fd, /* I - SNMP socket or -1 if none */ - http_addr_t *addr, /* I - Address of device */ - int use_bc, /* I - Use back-channel? */ - int update_state, /* I - Update printer-state-reasons? */ - int (*side_cb)(int, int, int, http_addr_t *, int)) - /* I - Side-channel callback */ + int print_fd, /* I - Print file descriptor */ + int device_fd, /* I - Device file descriptor */ + int snmp_fd, /* I - SNMP socket or -1 if none */ + http_addr_t *addr, /* I - Address of device */ + int use_bc, /* I - Use back-channel? */ + int update_state, /* I - Update printer-state-reasons? */ + _cups_sccb_t side_cb) /* I - Side-channel callback */ { int nfds; /* Maximum file descriptor value + 1 */ fd_set input, /* Input set for reading */ @@ -249,13 +249,14 @@ backendRunLoop( if (errno == ENXIO && offline != 1 && update_state) { fputs("STATE: +offline-report\n", stderr); - _cupsLangPuts(stderr, _("INFO: Printer is currently offline.\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Printer is not currently connected.")); offline = 1; } else if (errno == EINTR && total_bytes == 0) { fputs("DEBUG: Received an interrupt before any bytes were " - "written, aborting!\n", stderr); + "written, aborting.\n", stderr); return (0); } @@ -289,7 +290,7 @@ backendRunLoop( if ((bc_bytes = read(device_fd, bc_buffer, sizeof(bc_buffer))) > 0) { fprintf(stderr, - "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data!\n", + "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data\n", CUPS_LLCAST bc_bytes); cupsBackChannelWrite(bc_buffer, bc_bytes, 1.0); } @@ -318,7 +319,7 @@ backendRunLoop( if (errno != EAGAIN || errno != EINTR) { - perror("ERROR: Unable to read print data"); + _cupsLangPrintError("ERROR", _("Unable to read print data")); return (-1); } @@ -357,7 +358,7 @@ backendRunLoop( if (paperout != 1 && update_state) { fputs("STATE: +media-empty-warning\n", stderr); - _cupsLangPuts(stderr, _("ERROR: Out of paper!\n")); + fputs("DEBUG: Out of paper\n", stderr); paperout = 1; } } @@ -366,14 +367,14 @@ backendRunLoop( if (offline != 1 && update_state) { fputs("STATE: +offline-report\n", stderr); - _cupsLangPuts(stderr, _("INFO: Printer is currently off-line.\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Printer is not currently connected.")); offline = 1; } } else if (errno != EAGAIN && errno != EINTR && errno != ENOTTY) { - fprintf(stderr, _("ERROR: Unable to write print data: %s\n"), - strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to write print data")); return (-1); } } @@ -388,7 +389,7 @@ backendRunLoop( if (offline && update_state) { fputs("STATE: -offline-report\n", stderr); - _cupsLangPuts(stderr, _("INFO: Printer is now online.\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Printer is now connected.")); offline = 0; } @@ -422,5 +423,101 @@ backendRunLoop( /* - * End of "$Id: runloop.c 9258 2010-08-13 01:34:04Z mike $". + * 'backendWaitLoop()' - Wait for input from stdin while handling side-channel + * queries. + */ + +int /* O - 1 if data is ready, 0 if not */ +backendWaitLoop( + int snmp_fd, /* I - SNMP socket or -1 if none */ + http_addr_t *addr, /* I - Address of device */ + 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 */ + + + fprintf(stderr, "DEBUG: backendWaitLoop(snmp_fd=%d, addr=%p, side_cb=%p)\n", + snmp_fd, addr, side_cb); + + /* + * Now loop until we receive data from stdin... + */ + + for (;;) + { + /* + * Use select() to determine whether we have data to copy around... + */ + + FD_ZERO(&input); + FD_SET(0, &input); + if (side_cb) + FD_SET(CUPS_SC_FD, &input); + + if (select(CUPS_SC_FD + 1, &input, NULL, NULL, NULL) < 0) + { + /* + * Pause printing to clear any pending errors... + */ + + if (errno == EINTR) + { + fputs("DEBUG: Received an interrupt before any bytes were " + "written, aborting.\n", stderr); + return (0); + } + + sleep(1); + continue; + } + + /* + * Check for input on stdin... + */ + + if (FD_ISSET(0, &input)) + break; + + /* + * Check if we have a side-channel request ready... + */ + + if (side_cb && FD_ISSET(CUPS_SC_FD, &input)) + { + /* + * Do the side-channel request, then start back over in the select + * loop since it may have read from print_fd... + */ + + if ((*side_cb)(0, -1, snmp_fd, addr, use_bc)) + side_cb = NULL; + continue; + } + + /* + * Do SNMP updates periodically... + */ + + if (snmp_fd >= 0 && time(&curtime) >= snmp_update) + { + if (backendSNMPSupplies(snmp_fd, addr, NULL, NULL)) + snmp_update = INT_MAX; + else + snmp_update = curtime + 5; + } + } + + /* + * Return with success... + */ + + return (1); +} + + +/* + * End of "$Id: runloop.c 9820 2011-06-10 22:06:26Z mike $". */ diff --git a/backend/scsi-irix.c b/backend/scsi-irix.c deleted file mode 100644 index ed6c99f2..00000000 --- a/backend/scsi-irix.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * "$Id: scsi-irix.c 8173 2008-12-08 21:44:15Z mike $" - * - * IRIX SCSI printer support for the Common UNIX Printing System (CUPS). - * - * Copyright 2007 by Apple Inc. - * Copyright 2003-2005 by Easy Software Products, all rights reserved. - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use - * of this software must display the following - * acknowledgement: - * - * This product includes software developed by Easy - * Software Products. - * - * 4. The name of Easy Software Products may not be used to - * endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * Contents: - * - * list_devices() - List the available SCSI printer devices. - * print_device() - Print a file to a SCSI device. - */ - -/* - * Include necessary headers. - */ - -#include <bstring.h> /* memcpy() and friends */ -#include <sys/dsreq.h> /* SCSI interface stuff */ - - -/* - * 'list_devices()' - List the available SCSI printer devices. - */ - -void -list_devices(void) -{ - printf("direct scsi \"Unknown\" \"%s\"\n", - _cupsLangString(cupsLangDefault(), _("SCSI Printer"))); -} - - -/* - * 'print_device()' - Print a file to a SCSI device. - */ - -int /* O - Print status */ -print_device(const char *resource, /* I - SCSI device */ - int fd, /* I - File to print */ - int copies) /* I - Number of copies to print */ -{ - int scsi_fd; /* SCSI file descriptor */ - char buffer[8192]; /* Data buffer */ - int bytes; /* Number of bytes */ - int try; /* Current try */ - dsreq_t scsi_req; /* SCSI request */ - char scsi_cmd[6]; /* SCSI command data */ -#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ -#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ - - - /* - * Make sure we have a valid resource name... - */ - - if (strncmp(resource, "/dev/scsi/", 10) != 0) - { - _cupsLangPrintf(stderr, _("ERROR: Bad SCSI device file \"%s\"!\n"), - resource); - return (CUPS_BACKEND_STOP); - } - - /* - * Open the SCSI device file... - */ - - fputs("STATE: +connecting-to-device\n", stderr); - - do - { - if ((scsi_fd = open(resource, O_RDWR | O_EXCL)) == -1) - { - if (getenv("CLASS") != NULL) - { - /* - * If the CLASS environment variable is set, the job was submitted - * to a class and not to a specific queue. In this case, we want - * to abort immediately so that the job can be requeued on the next - * available printer in the class. - */ - - _cupsLangPuts(stderr, - _("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); - - /* - * Sleep 5 seconds to keep the job from requeuing too rapidly... - */ - - sleep(5); - - return (1); - } - - if (errno != EAGAIN && errno != EBUSY) - { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open device file \"%s\": %s\n"), - resource, strerror(errno)); - return (CUPS_BACKEND_FAILED); - } - else - { - _cupsLangPuts(stderr, - _("INFO: Printer busy; will retry in 30 seconds...\n")); - sleep(30); - } - } - } - while (scsi_fd == -1); - - 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 != 0) - { -#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ - sigset(SIGTERM, SIG_IGN); -#elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - - sigemptyset(&action.sa_mask); - action.sa_handler = SIG_IGN; - sigaction(SIGTERM, &action, NULL); -#else - signal(SIGTERM, SIG_IGN); -#endif /* HAVE_SIGSET */ - } - - /* - * Copy the print file to the device... - */ - - while (copies > 0) - { - if (fd != 0) - lseek(fd, 0, SEEK_SET); - - while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) - { - memset(&scsi_req, 0, sizeof(scsi_req)); - - scsi_req.ds_flags = DSRQ_WRITE; - scsi_req.ds_time = 60 * 1000; - scsi_req.ds_cmdbuf = scsi_cmd; - scsi_req.ds_cmdlen = 6; - scsi_req.ds_databuf = buffer; - scsi_req.ds_datalen = bytes; - - scsi_cmd[0] = 0x0a; /* Group 0 print command */ - scsi_cmd[1] = 0x00; - scsi_cmd[2] = bytes / 65536; - scsi_cmd[3] = bytes / 256; - scsi_cmd[4] = bytes; - scsi_cmd[5] = 0x00; - - for (try = 0; try < 10; try ++) - if (ioctl(scsi_fd, DS_ENTER, &scsi_req) < 0 || - scsi_req.ds_status != 0) - { - _cupsLangPrintf(stderr, - _("WARNING: SCSI command timed out (%d); " - "retrying...\n"), scsi_req.ds_status); - sleep(try + 1); - } - else - break; - - if (try >= 10) - { - _cupsLangPrintf(stderr, _("ERROR: Unable to send print data (%d)\n"), - scsi_req.ds_status); - close(scsi_fd); - return (CUPS_BACKEND_FAILED); - } - } - - copies --; - } - - /* - * Close the device and return... - */ - - close(fd); - - return (CUPS_BACKEND_OK); -} - - -/* - * End of "$Id: scsi-irix.c 8173 2008-12-08 21:44:15Z mike $". - */ diff --git a/backend/scsi-linux.c b/backend/scsi-linux.c deleted file mode 100644 index 93861e92..00000000 --- a/backend/scsi-linux.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * "$Id: scsi-linux.c 8173 2008-12-08 21:44:15Z mike $" - * - * Linux SCSI printer support for the Common UNIX Printing System (CUPS). - * - * Copyright 2007 by Apple Inc. - * Copyright 2003-2005 by Easy Software Products, all rights reserved. - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use - * of this software must display the following - * acknowledgement: - * - * This product includes software developed by Easy - * Software Products. - * - * 4. The name of Easy Software Products may not be used to - * endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * Contents: - * - * list_devices() - List the available SCSI printer devices. - * print_device() - Print a file to a SCSI device. - */ - -/* - * Include necessary headers. - */ - -#include <scsi/sg.h> -#include <cups/i18n.h> - - -/* - * We currently only support the Linux 2.4 generic SCSI interface. - */ - -#ifndef SG_DXFER_TO_DEV -/* - * Dummy functions that do nothing on unsupported platforms... - */ -void list_devices(void) {} -int print_device(const char *resource, int fd, int copies) { return (1); } -#else - - -/* - * 'list_devices()' - List the available SCSI printer devices. - */ - -void -list_devices(void) -{ - printf("direct scsi \"Unknown\" \"%s\"\n", - _cupsLangString(cupsLangDefault(), _("SCSI Printer"))); -} - - -/* - * 'print_device()' - Print a file to a SCSI device. - */ - -int /* O - Print status */ -print_device(const char *resource, /* I - SCSI device */ - int fd, /* I - File to print */ - int copies) /* I - Number of copies to print */ -{ - int scsi_fd; /* SCSI file descriptor */ - char buffer[8192]; /* Data buffer */ - int bytes; /* Number of bytes */ - int try; /* Current try */ - sg_io_hdr_t scsi_req; /* SCSI request */ - unsigned char scsi_cmd[6], /* SCSI command data */ - scsi_sense[32]; /* SCSI sense data */ -# if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ -# endif /* HAVE_SIGACTION && !HAVE_SIGSET */ - - - /* - * Make sure we have a valid resource name... - */ - - if (strncmp(resource, "/dev/sg", 7) != 0) - { - _cupsLangPrintf(stderr, _("ERROR: Bad SCSI device file \"%s\"!\n"), - resource); - return (CUPS_BACKEND_STOP); - } - - /* - * Open the SCSI device file... - */ - - fputs("STATE: +connecting-to-device\n", stderr); - - do - { - if ((scsi_fd = open(resource, O_RDWR | O_EXCL)) == -1) - { - if (getenv("CLASS") != NULL) - { - /* - * If the CLASS environment variable is set, the job was submitted - * to a class and not to a specific queue. In this case, we want - * to abort immediately so that the job can be requeued on the next - * available printer in the class. - */ - - _cupsLangPuts(stderr, - _("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); - - /* - * Sleep 5 seconds to keep the job from requeuing too rapidly... - */ - - sleep(5); - - return (CUPS_BACKEND_FAILED); - } - - if (errno != EAGAIN && errno != EBUSY) - { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open device file \"%s\": %s\n"), - resource, strerror(errno)); - return (CUPS_BACKEND_FAILED); - } - else - { - _cupsLangPuts(stderr, - _("INFO: Printer busy; will retry in 30 seconds...\n")); - sleep(30); - } - } - } - while (scsi_fd == -1); - - 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 != 0) - { -# ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ - sigset(SIGTERM, SIG_IGN); -# elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - - sigemptyset(&action.sa_mask); - action.sa_handler = SIG_IGN; - sigaction(SIGTERM, &action, NULL); -# else - signal(SIGTERM, SIG_IGN); -# endif /* HAVE_SIGSET */ - } - - /* - * Copy the print file to the device... - */ - - while (copies > 0) - { - if (fd != 0) - lseek(fd, 0, SEEK_SET); - - while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) - { - memset(&scsi_req, 0, sizeof(scsi_req)); - - scsi_req.interface_id = 'S'; - scsi_req.dxfer_direction = SG_DXFER_TO_DEV; - scsi_req.cmd_len = 6; - scsi_req.mx_sb_len = sizeof(scsi_sense); - scsi_req.iovec_count = 0; - scsi_req.dxfer_len = bytes; - scsi_req.dxferp = buffer; - scsi_req.cmdp = scsi_cmd; - scsi_req.sbp = scsi_sense; - scsi_req.timeout = 60 * 1000; - - scsi_cmd[0] = 0x0a; /* Group 0 print command */ - scsi_cmd[1] = 0x00; - scsi_cmd[2] = bytes / 65536; - scsi_cmd[3] = bytes / 256; - scsi_cmd[4] = bytes; - scsi_cmd[5] = 0x00; - - for (try = 0; try < 10; try ++) - if (ioctl(scsi_fd, SG_IO, &scsi_req) < 0 || - scsi_req.status != 0) - { - _cupsLangPrintf(stderr, - _("WARNING: SCSI command timed out (%d); " - "retrying...\n"), scsi_req.status); - sleep(try + 1); - } - else - break; - - if (try >= 10) - { - _cupsLangPrintf(stderr, _("ERROR: Unable to send print data (%d)\n"), - scsi_req.status); - close(scsi_fd); - return (CUPS_BACKEND_FAILED); - } - } - - copies --; - } - - /* - * Close the device and return... - */ - - close(fd); - - return (CUPS_BACKEND_OK); -} -#endif /* !SG_DXFER_TO_DEV */ - - -/* - * End of "$Id: scsi-linux.c 8173 2008-12-08 21:44:15Z mike $". - */ diff --git a/backend/scsi.c b/backend/scsi.c deleted file mode 100644 index 7040d4bd..00000000 --- a/backend/scsi.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * "$Id: scsi.c 7193 2008-01-07 23:01:40Z mike $" - * - * SCSI printer backend for the Common UNIX Printing System (CUPS). - * - * Copyright 2007 by Apple Inc. - * Copyright 2003-2006 by Easy Software Products, all rights reserved. - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use - * of this software must display the following - * acknowledgement: - * - * This product includes software developed by Easy - * Software Products. - * - * 4. The name of Easy Software Products may not be used to - * endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * Contents: - * - * main() - Send a file to the specified SCSI printer. - */ - -/* - * Include necessary headers. - */ - -#include <cups/backend.h> -#include <cups/cups.h> -#include <cups/i18n.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <cups/string.h> -#include <cups/i18n.h> -#include <signal.h> - -#ifdef WIN32 -# include <io.h> -#else -# include <unistd.h> -# include <fcntl.h> -# ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -# endif /* HAVE_SYS_IOCTL_H */ -#endif /* WIN32 */ - - -/* - * Local functions... - */ - -void list_devices(void); -int print_device(const char *resource, int fd, int copies); - - -#if defined(__linux__) && defined(HAVE_SCSI_SG_H) -# include "scsi-linux.c" -#elif defined(__sgi) -# include "scsi-irix.c" -#else -/* - * Dummy functions that do nothing on unsupported platforms... - */ -void list_devices(void) {} -int print_device(const char *resource, int fd, int copies) { return (CUPS_BACKEND_FAILED); } -#endif /* __linux && HAVE_SCSI_SG_H */ - - -/* - * 'main()' - Send a file to the specified SCSI printer. - * - * Usage: - * - * printer-uri job-id user title copies options [file] - */ - -int /* O - Exit status */ -main(int argc, /* I - Number of command-line arguments (6 or 7) */ - char *argv[]) /* I - Command-line arguments */ -{ - char method[255], /* Method in URI */ - hostname[1024], /* Hostname */ - username[255], /* Username info (not used) */ - resource[1024], /* Resource info (device and options) */ - *options; /* Pointer to options */ - int port; /* Port number (not used) */ - int fp; /* Print file */ - int copies; /* Number of copies to print */ - int status; /* Exit status */ -#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ -#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ - - - /* - * Make sure status messages are not buffered... - */ - - setbuf(stderr, NULL); - - /* - * Ignore SIGPIPE signals... - */ - -#ifdef HAVE_SIGSET - sigset(SIGPIPE, SIG_IGN); -#elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - action.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &action, NULL); -#else - signal(SIGPIPE, SIG_IGN); -#endif /* HAVE_SIGSET */ - - /* - * Check command-line... - */ - - if (argc == 1) - { - list_devices(); - return (CUPS_BACKEND_OK); - } - else if (argc < 6 || argc > 7) - { - _cupsLangPrintf(stderr, - _("Usage: %s job-id user title copies options [file]\n"), - argv[0]); - return (CUPS_BACKEND_FAILED); - } - - /* - * If we have 7 arguments, print the file named on the command-line. - * Otherwise, send stdin instead... - */ - - if (argc == 6) - { - fp = 0; - copies = 1; - } - else - { - /* - * Try to open the print file... - */ - - if ((fp = open(argv[6], O_RDONLY)) < 0) - { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open print file \"%s\": %s\n"), - argv[6], strerror(errno)); - return (CUPS_BACKEND_FAILED); - } - - copies = atoi(argv[4]); - } - - /* - * Extract the device name and options from the URI... - */ - - httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv), - method, sizeof(method), username, sizeof(username), - hostname, sizeof(hostname), &port, - resource, sizeof(resource)); - - /* - * See if there are any options... - */ - - if ((options = strchr(resource, '?')) != NULL) - { - /* - * Yup, terminate the device name string and move to the first - * character of the options... - */ - - *options++ = '\0'; - } - - /* - * Finally, send the print file... - */ - - status = print_device(resource, fp, copies); - - /* - * Close input file and return... - */ - - if (fp != 0) - close(fp); - - return (status); -} - - -/* - * End of "$Id: scsi.c 7193 2008-01-07 23:01:40Z mike $". - */ diff --git a/backend/serial.c b/backend/serial.c index 73ad9a0b..4f350a1f 100644 --- a/backend/serial.c +++ b/backend/serial.c @@ -1,9 +1,9 @@ /* - * "$Id: serial.c 9282 2010-08-31 15:56:40Z mike $" + * "$Id: serial.c 9793 2011-05-20 03:49:49Z mike $" * - * Serial port backend for the Common UNIX Printing System (CUPS). + * Serial port backend for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -26,6 +26,7 @@ */ #include "backend-private.h" +#include <stdio.h> #ifdef __hpux # include <sys/modem.h> @@ -163,7 +164,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ else if (argc < 6 || argc > 7) { _cupsLangPrintf(stderr, - _("Usage: %s job-id user title copies options [file]\n"), + _("Usage: %s job-id user title copies options [file]"), argv[0]); return (CUPS_BACKEND_FAILED); } @@ -186,9 +187,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if ((print_fd = open(argv[6], O_RDONLY)) < 0) { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open print file \"%s\": %s\n"), - argv[6], strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to open print file")); return (CUPS_BACKEND_FAILED); } @@ -238,9 +237,9 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * available printer in the class. */ - _cupsLangPuts(stderr, - _("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Unable to contact printer, queuing on next " + "printer in class.")); /* * Sleep 5 seconds to keep the job from requeuing too rapidly... @@ -253,15 +252,13 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (errno == EBUSY) { - _cupsLangPuts(stderr, - _("INFO: Printer busy; will retry in 30 seconds...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Printer busy; will retry in 30 seconds.")); sleep(30); } else { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open device file \"%s\": %s\n"), - resource, strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to open device file")); return (CUPS_BACKEND_FAILED); } } @@ -321,7 +318,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Process the option... */ - if (!strcasecmp(name, "baud")) + if (!_cups_strcasecmp(name, "baud")) { /* * Set the baud rate... @@ -378,13 +375,13 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ break; # endif /* B230400 */ default : - _cupsLangPrintf(stderr, _("WARNING: Unsupported baud rate %s!\n"), - value); + _cupsLangPrintFilter(stderr, "WARNING", + _("Unsupported baud rate: %s"), value); break; } #endif /* B19200 == 19200 */ } - else if (!strcasecmp(name, "bits")) + else if (!_cups_strcasecmp(name, "bits")) { /* * Set number of data bits... @@ -405,25 +402,25 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ break; } } - else if (!strcasecmp(name, "parity")) + else if (!_cups_strcasecmp(name, "parity")) { /* * Set parity checking... */ - if (!strcasecmp(value, "even")) + if (!_cups_strcasecmp(value, "even")) { opts.c_cflag |= PARENB; opts.c_cflag &= ~PARODD; } - else if (!strcasecmp(value, "odd")) + else if (!_cups_strcasecmp(value, "odd")) { opts.c_cflag |= PARENB; opts.c_cflag |= PARODD; } - else if (!strcasecmp(value, "none")) + else if (!_cups_strcasecmp(value, "none")) opts.c_cflag &= ~PARENB; - else if (!strcasecmp(value, "space")) + else if (!_cups_strcasecmp(value, "space")) { /* * Note: we only support space parity with 7 bits per character... @@ -433,7 +430,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ opts.c_cflag |= CS8; opts.c_cflag &= ~PARENB; } - else if (!strcasecmp(value, "mark")) + else if (!_cups_strcasecmp(value, "mark")) { /* * Note: we only support mark parity with 7 bits per character @@ -446,29 +443,29 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ opts.c_cflag |= CSTOPB; } } - else if (!strcasecmp(name, "flow")) + else if (!_cups_strcasecmp(name, "flow")) { /* * Set flow control... */ - if (!strcasecmp(value, "none")) + if (!_cups_strcasecmp(value, "none")) { opts.c_iflag &= ~(IXON | IXOFF); opts.c_cflag &= ~CRTSCTS; } - else if (!strcasecmp(value, "soft")) + else if (!_cups_strcasecmp(value, "soft")) { opts.c_iflag |= IXON | IXOFF; opts.c_cflag &= ~CRTSCTS; } - else if (!strcasecmp(value, "hard") || - !strcasecmp(value, "rtscts")) + else if (!_cups_strcasecmp(value, "hard") || + !_cups_strcasecmp(value, "rtscts")) { opts.c_iflag &= ~(IXON | IXOFF); opts.c_cflag |= CRTSCTS; } - else if (!strcasecmp(value, "dtrdsr")) + else if (!_cups_strcasecmp(value, "dtrdsr")) { opts.c_iflag &= ~(IXON | IXOFF); opts.c_cflag &= ~CRTSCTS; @@ -476,7 +473,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ dtrdsr = 1; } } - else if (!strcasecmp(name, "stop")) + else if (!_cups_strcasecmp(name, "stop")) { switch (atoi(value)) { @@ -594,7 +591,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if ((bc_bytes = read(device_fd, bc_buffer, sizeof(bc_buffer))) > 0) { fprintf(stderr, - "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data!\n", + "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data\n", CUPS_LLCAST bc_bytes); cupsBackChannelWrite(bc_buffer, bc_bytes, 1.0); } @@ -614,7 +611,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (errno != EAGAIN || errno != EINTR) { - _cupsLangPrintError(_("ERROR: Unable to read print data")); + perror("DEBUG: Unable to read print data"); tcsetattr(device_fd, TCSADRAIN, &origopts); @@ -690,7 +687,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (errno != EAGAIN && errno != EINTR && errno != ENOTTY) { - _cupsLangPrintError(_("ERROR: Unable to write print data")); + perror("DEBUG: Unable to write print data"); tcsetattr(device_fd, TCSADRAIN, &origopts); @@ -725,7 +722,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (print_fd != 0) close(print_fd); - return (total_bytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); + return (CUPS_BACKEND_OK); } @@ -1220,11 +1217,11 @@ list_devices(void) /* Check if hidden... */ - hiddenVal = IORegistryEntrySearchCFProperty(serialService, + hiddenVal = IORegistryEntrySearchCFProperty(serialService, kIOServicePlane, CFSTR("HiddenPort"), kCFAllocatorDefault, - kIORegistryIterateRecursively | + kIORegistryIterateRecursively | kIORegistryIterateParents); if (hiddenVal) CFRelease(hiddenVal); /* This interface should not be used */ @@ -1240,7 +1237,7 @@ list_devices(void) sizeof(serialName), kCFStringEncodingASCII); CFRelease(serialNameAsCFString); - + if (result) { bsdPathAsCFString = @@ -1253,7 +1250,7 @@ list_devices(void) sizeof(bsdPath), kCFStringEncodingASCII); CFRelease(bsdPathAsCFString); - + if (result) printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", bsdPath, serialName); @@ -1326,5 +1323,5 @@ side_cb(int print_fd, /* I - Print file */ /* - * End of "$Id: serial.c 9282 2010-08-31 15:56:40Z mike $". + * End of "$Id: serial.c 9793 2011-05-20 03:49:49Z mike $". */ diff --git a/backend/snmp-supplies.c b/backend/snmp-supplies.c index 8d0dcd76..4d8e52e6 100644 --- a/backend/snmp-supplies.c +++ b/backend/snmp-supplies.c @@ -1,5 +1,5 @@ /* - * "$Id: snmp-supplies.c 9853 2011-07-06 20:27:31Z mike $" + * "$Id: snmp-supplies.c 9793 2011-05-20 03:49:49Z mike $" * * SNMP supplies functions for CUPS. * @@ -40,12 +40,10 @@ #define CUPS_DEVELOPER_EMPTY 2 #define CUPS_MARKER_SUPPLY_LOW 4 #define CUPS_MARKER_SUPPLY_EMPTY 8 -#define CUPS_MARKER_WASTE_ALMOST_FULL 16 -#define CUPS_MARKER_WASTE_FULL 32 -#define CUPS_OPC_NEAR_EOL 64 -#define CUPS_OPC_LIFE_OVER 128 -#define CUPS_TONER_LOW 256 -#define CUPS_TONER_EMPTY 512 +#define CUPS_OPC_NEAR_EOL 16 +#define CUPS_OPC_LIFE_OVER 32 +#define CUPS_TONER_LOW 64 +#define CUPS_TONER_EMPTY 128 /* @@ -172,8 +170,6 @@ static const backend_state_t const supply_states[] = { CUPS_DEVELOPER_EMPTY, "developer-empty-warning" }, { CUPS_MARKER_SUPPLY_LOW, "marker-supply-low-report" }, { CUPS_MARKER_SUPPLY_EMPTY, "marker-supply-empty-warning" }, - { CUPS_MARKER_WASTE_ALMOST_FULL, "marker-waste-almost-full-report" }, - { CUPS_MARKER_WASTE_FULL, "marker-waste-full-warning" }, { CUPS_OPC_NEAR_EOL, "opc-near-eol-report" }, { CUPS_OPC_LIFE_OVER, "opc-life-over-warning" }, { CUPS_TONER_LOW, "toner-low-report" }, @@ -251,10 +247,6 @@ backendSNMPSupplies( break; case CUPS_TC_wasteToner : case CUPS_TC_wasteInk : - if (percent <= 1) - new_supply_state |= CUPS_MARKER_WASTE_FULL; - else - new_supply_state |= CUPS_MARKER_WASTE_ALMOST_FULL; break; case CUPS_TC_ink : case CUPS_TC_inkCartridge : @@ -479,7 +471,7 @@ backend_init_supplies( if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL || ((ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL && - ppdattr->value && strcasecmp(ppdattr->value, "true"))) + ppdattr->value && _cups_strcasecmp(ppdattr->value, "true"))) { ppdClose(ppd); return; @@ -989,5 +981,5 @@ utf16_to_utf8( /* - * End of "$Id: snmp-supplies.c 9853 2011-07-06 20:27:31Z mike $". + * End of "$Id: snmp-supplies.c 9793 2011-05-20 03:49:49Z mike $". */ diff --git a/backend/snmp.c b/backend/snmp.c index 692a0414..de967c8b 100644 --- a/backend/snmp.c +++ b/backend/snmp.c @@ -1,9 +1,9 @@ /* - * "$Id: snmp.c 8912 2009-12-08 02:13:42Z mike $" + * "$Id: snmp.c 9838 2011-06-19 04:28:25Z mike $" * - * SNMP discovery backend for the Common UNIX Printing System (CUPS). + * SNMP discovery backend for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 2006-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -141,13 +141,6 @@ typedef struct snmp_cache_s /**** SNMP scan cache ****/ /* - * Private CUPS API to set the last error... - */ - -extern void _cupsSetError(ipp_status_t status, const char *message); - - -/* * Local functions... */ @@ -171,7 +164,7 @@ static void probe_device(snmp_cache_t *device); static void read_snmp_conf(const char *address); static void read_snmp_response(int fd); static double run_time(void); -static void scan_devices(int fd); +static void scan_devices(int ipv4, int ipv6); static int try_connect(http_addr_t *addr, const char *addrname, int port); static void update_cache(snmp_cache_t *device, const char *uri, @@ -209,7 +202,8 @@ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments (6 or 7) */ char *argv[]) /* I - Command-line arguments */ { - int fd; /* SNMP socket */ + int ipv4, /* SNMP IPv4 socket */ + ipv6; /* SNMP IPv6 socket */ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) struct sigaction action; /* Actions for POSIX signals */ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ @@ -221,7 +215,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (argc > 2) { - fputs(_("Usage: snmp [host-or-ip-address]\n"), stderr); + _cupsLangPuts(stderr, _("Usage: snmp [host-or-ip-address]")); return (1); } @@ -252,9 +246,16 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Open the SNMP socket... */ - if ((fd = _cupsSNMPOpen(AF_INET)) < 0) + if ((ipv4 = _cupsSNMPOpen(AF_INET)) < 0) return (1); +#ifdef AF_INET6 + if ((ipv6 = _cupsSNMPOpen(AF_INET6)) < 0) + return (1); +#else + ipv6 = -1; +#endif /* AF_INET6 */ + /* * Read the configuration file and any cache data... */ @@ -269,13 +270,15 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Scan for devices... */ - scan_devices(fd); + scan_devices(ipv4, ipv6); /* * Close, free, and return with no errors... */ - _cupsSNMPClose(fd); + _cupsSNMPClose(ipv4); + if (ipv6 >= 0) + _cupsSNMPClose(ipv6); free_array(Addresses); free_array(Communities); @@ -464,7 +467,7 @@ static int /* O - Result of comparison */ compare_cache(snmp_cache_t *a, /* I - First cache entry */ snmp_cache_t *b) /* I - Second cache entry */ { - return (strcasecmp(a->addrname, b->addrname)); + return (_cups_strcasecmp(a->addrname, b->addrname)); } @@ -506,7 +509,7 @@ fix_make_model( * that printer driver detection works better... */ - if (!strncasecmp(old_make_model, "Hewlett-Packard", 15)) + if (!_cups_strncasecmp(old_make_model, "Hewlett-Packard", 15)) { /* * Strip leading Hewlett-Packard and hp prefixes and replace @@ -518,7 +521,7 @@ fix_make_model( while (isspace(*mmptr & 255)) mmptr ++; - if (!strncasecmp(mmptr, "hp", 2)) + if (!_cups_strncasecmp(mmptr, "hp", 2)) { mmptr += 2; @@ -531,11 +534,11 @@ fix_make_model( make_model[2] = ' '; strlcpy(make_model + 3, mmptr, make_model_size - 3); } - else if (!strncasecmp(old_make_model, "deskjet", 7)) + else if (!_cups_strncasecmp(old_make_model, "deskjet", 7)) snprintf(make_model, make_model_size, "HP DeskJet%s", old_make_model + 7); - else if (!strncasecmp(old_make_model, "officejet", 9)) + else if (!_cups_strncasecmp(old_make_model, "officejet", 9)) snprintf(make_model, make_model_size, "HP OfficeJet%s", old_make_model + 9); - else if (!strncasecmp(old_make_model, "stylus_pro_", 11)) + else if (!_cups_strncasecmp(old_make_model, "stylus_pro_", 11)) snprintf(make_model, make_model_size, "EPSON Stylus Pro %s", old_make_model + 11); else @@ -715,7 +718,7 @@ probe_device(snmp_cache_t *device) /* I - Device */ #ifdef __APPLE__ /* - * TODO: Try an mDNS query first, and then fallback on direct probes... + * If the printer supports Bonjour/mDNS, don't report it from the SNMP backend. */ if (!try_connect(&(device->address), device->addrname, 5353)) @@ -841,16 +844,16 @@ read_snmp_conf(const char *address) /* I - Single address to probe */ if (!value) fprintf(stderr, "ERROR: Missing value on line %d of %s!\n", linenum, filename); - else if (!strcasecmp(line, "Address")) + else if (!_cups_strcasecmp(line, "Address")) { if (!address) add_array(Addresses, value); } - else if (!strcasecmp(line, "Community")) + else if (!_cups_strcasecmp(line, "Community")) add_array(Communities, value); - else if (!strcasecmp(line, "DebugLevel")) + else if (!_cups_strcasecmp(line, "DebugLevel")) DebugLevel = atoi(value); - else if (!strcasecmp(line, "DeviceURI")) + else if (!_cups_strcasecmp(line, "DeviceURI")) { if (*value != '\"') fprintf(stderr, @@ -859,12 +862,12 @@ read_snmp_conf(const char *address) /* I - Single address to probe */ else add_device_uri(value); } - else if (!strcasecmp(line, "HostNameLookups")) - HostNameLookups = !strcasecmp(value, "on") || - !strcasecmp(value, "yes") || - !strcasecmp(value, "true") || - !strcasecmp(value, "double"); - else if (!strcasecmp(line, "MaxRunTime")) + else if (!_cups_strcasecmp(line, "HostNameLookups")) + HostNameLookups = !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "yes") || + !_cups_strcasecmp(value, "true") || + !_cups_strcasecmp(value, "double"); + else if (!_cups_strcasecmp(line, "MaxRunTime")) MaxRunTime = atoi(value); else fprintf(stderr, "ERROR: Unknown directive %s on line %d of %s!\n", @@ -945,7 +948,7 @@ read_snmp_response(int fd) /* I - SNMP socket file descriptor */ debug_printf("DEBUG: request-id=%d\n", packet.request_id); debug_printf("DEBUG: error-status=%d\n", packet.error_status); - if (packet.error_status) + if (packet.error_status && packet.request_id != DEVICE_TYPE) return; /* @@ -1153,8 +1156,11 @@ run_time(void) */ static void -scan_devices(int fd) /* I - SNMP socket */ +scan_devices(int ipv4, /* I - SNMP IPv4 socket */ + int ipv6) /* I - SNMP IPv6 socket */ { + int fd, /* File descriptor for this address */ + busy; /* Are we busy processing something? */ char *address, /* Current address */ *community; /* Current community */ fd_set input; /* Input set for select() */ @@ -1163,6 +1169,7 @@ scan_devices(int fd) /* I - SNMP socket */ http_addrlist_t *addrs, /* List of addresses */ *addr; /* Current address */ snmp_cache_t *device; /* Current device */ + char temp[1024]; /* Temporary address string */ gettimeofday(&StartTime, NULL); @@ -1181,7 +1188,6 @@ scan_devices(int fd) /* I - SNMP socket */ { char ifname[255]; /* Interface name */ - strlcpy(ifname, address + 4, sizeof(ifname)); if (ifname[0]) ifname[strlen(ifname) - 1] = '\0'; @@ -1189,7 +1195,7 @@ scan_devices(int fd) /* I - SNMP socket */ addrs = get_interface_addresses(ifname); } else - addrs = httpAddrGetList(address, AF_INET, NULL); + addrs = httpAddrGetList(address, AF_UNSPEC, NULL); if (!addrs) { @@ -1205,8 +1211,20 @@ scan_devices(int fd) /* I - SNMP socket */ community, address); for (addr = addrs; addr; addr = addr->next) + { +#ifdef AF_INET6 + if (_httpAddrFamily(&(addr->addr)) == AF_INET6) + fd = ipv6; + else +#endif /* AF_INET6 */ + fd = ipv4; + + debug_printf("DEBUG: Sending get request to %s...\n", + httpAddrString(&(addr->addr), temp, sizeof(temp))); + _cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community, CUPS_ASN1_GET_REQUEST, DEVICE_TYPE, DeviceTypeOID); + } } httpAddrFreeList(addrs); @@ -1225,17 +1243,33 @@ scan_devices(int fd) /* I - SNMP socket */ timeout.tv_sec = 2; timeout.tv_usec = 0; - FD_SET(fd, &input); + FD_SET(ipv4, &input); + if (ipv6 >= 0) + FD_SET(ipv6, &input); + + fd = ipv4 > ipv6 ? ipv4 : ipv6; if (select(fd + 1, &input, NULL, NULL, &timeout) < 0) { - fprintf(stderr, "ERROR: %.3f select() for %d failed: %s\n", run_time(), - fd, strerror(errno)); + fprintf(stderr, "ERROR: %.3f select() for %d/%d failed: %s\n", run_time(), + ipv4, ipv6, strerror(errno)); break; } - if (FD_ISSET(fd, &input)) - read_snmp_response(fd); - else + busy = 0; + + if (FD_ISSET(ipv4, &input)) + { + read_snmp_response(ipv4); + busy = 1; + } + + if (ipv6 >= 0 && FD_ISSET(ipv6, &input)) + { + read_snmp_response(ipv6); + busy = 1; + } + + if (!busy) { /* * List devices with complete information... @@ -1281,14 +1315,14 @@ try_connect(http_addr_t *addr, /* I - Socket address */ debug_printf("DEBUG: %.3f Trying %s://%s:%d...\n", run_time(), port == 515 ? "lpd" : "socket", addrname, port); - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + if ((fd = socket(_httpAddrFamily(addr), SOCK_STREAM, 0)) < 0) { fprintf(stderr, "ERROR: Unable to create socket: %s\n", strerror(errno)); return (-1); } - addr->ipv4.sin_port = htons(port); + _httpAddrSetPort(addr, port); alarm(1); @@ -1337,5 +1371,5 @@ update_cache(snmp_cache_t *device, /* I - Device */ /* - * End of "$Id: snmp.c 8912 2009-12-08 02:13:42Z mike $". + * End of "$Id: snmp.c 9838 2011-06-19 04:28:25Z mike $". */ diff --git a/backend/socket.c b/backend/socket.c index b7fec786..5e28fc89 100644 --- a/backend/socket.c +++ b/backend/socket.c @@ -1,9 +1,9 @@ /* - * "$Id: socket.c 9454 2011-01-10 08:02:55Z mike $" + * "$Id: socket.c 9793 2011-05-20 03:49:49Z mike $" * - * AppSocket backend for the Common UNIX Printing System (CUPS). + * AppSocket backend for CUPS. * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -77,7 +77,6 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ time_t current_time, /* Current time */ wait_time; /* Time to wait before shutting down socket */ #endif /* __APPLE__ */ - int recoverable; /* Recoverable error shown? */ int contimeout; /* Connection timeout */ int waiteof; /* Wait for end-of-file? */ int port; /* Port number */ @@ -92,7 +91,9 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ start_count, /* Page count via SNMP at start */ page_count, /* Page count via SNMP */ have_supplies; /* Printer supports supply levels? */ - ssize_t tbytes; /* Total number of bytes written */ + ssize_t bytes = 0, /* Initial bytes read */ + tbytes; /* Total number of bytes written */ + char buffer[1024]; /* Initial print buffer */ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) struct sigaction action; /* Actions for POSIX signals */ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ @@ -131,7 +132,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ else if (argc < 6 || argc > 7) { _cupsLangPrintf(stderr, - _("Usage: %s job-id user title copies options [file]\n"), + _("Usage: %s job-id user title copies options [file]"), argv[0]); return (CUPS_BACKEND_FAILED); } @@ -154,9 +155,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if ((print_fd = open(argv[6], O_RDONLY)) < 0) { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open print file \"%s\": %s\n"), - argv[6], strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to open print file")); return (CUPS_BACKEND_FAILED); } @@ -167,8 +166,14 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Extract the hostname and port number from the URI... */ - if ((device_uri = cupsBackendDeviceURI(argv)) == NULL) - return (CUPS_BACKEND_FAILED); + while ((device_uri = cupsBackendDeviceURI(argv)) == NULL) + { + _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer.")); + sleep(10); + + if (getenv("CLASS") != NULL) + return (CUPS_BACKEND_FAILED); + } httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, @@ -232,16 +237,16 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Process the option... */ - if (!strcasecmp(name, "waiteof")) + if (!_cups_strcasecmp(name, "waiteof")) { /* * Set the wait-for-eof value... */ - waiteof = !value[0] || !strcasecmp(value, "on") || - !strcasecmp(value, "yes") || !strcasecmp(value, "true"); + waiteof = !value[0] || !_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true"); } - else if (!strcasecmp(name, "contimeout")) + else if (!_cups_strcasecmp(name, "contimeout")) { /* * Set the connection timeout... @@ -254,26 +259,59 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ } /* - * Then try to connect to the remote host... + * Then try finding the remote host... */ - recoverable = 0; - start_time = time(NULL); + start_time = time(NULL); sprintf(portname, "%d", port); fputs("STATE: +connecting-to-device\n", stderr); fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname); - if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) + while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) + { + _cupsLangPrintFilter(stderr, "INFO", + _("Unable to locate printer \"%s\"."), hostname); + sleep(10); + + if (getenv("CLASS") != NULL) + { + fputs("STATE: -connecting-to-device\n", stderr); + return (CUPS_BACKEND_STOP); + } + } + + /* + * See if the printer supports SNMP... + */ + + if ((snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family)) >= 0) + { + have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr), + &start_count, NULL); + } + else + have_supplies = start_count = 0; + + /* + * Wait for data from the filter... + */ + + if (print_fd == 0) { - _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"), - hostname); - return (CUPS_BACKEND_STOP); + if (!backendWaitLoop(snmp_fd, &(addrlist->addr), 1, backendNetworkSideCB)) + return (CUPS_BACKEND_OK); + else if ((bytes = read(0, buffer, sizeof(buffer))) <= 0) + return (CUPS_BACKEND_OK); } + /* + * Connect to the printer... + */ + fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port); - _cupsLangPuts(stderr, _("INFO: Connecting to printer...\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer.")); for (delay = 5;;) { @@ -291,9 +329,9 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * available printer in the class. */ - _cupsLangPuts(stderr, - _("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Unable to contact printer, queuing on next " + "printer in class.")); /* * Sleep 5 seconds to keep the job from requeuing too rapidly... @@ -304,21 +342,38 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ return (CUPS_BACKEND_FAILED); } + fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(error)); + if (error == ECONNREFUSED || error == EHOSTDOWN || error == EHOSTUNREACH) { if (contimeout && (time(NULL) - start_time) > contimeout) { - _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("The printer is not responding.")); return (CUPS_BACKEND_FAILED); } - recoverable = 1; - - _cupsLangPrintf(stderr, - _("WARNING: recoverable: Network host \'%s\' is busy; " - "will retry in %d seconds...\n"), - hostname, delay); + switch (error) + { + case EHOSTDOWN : + _cupsLangPrintFilter(stderr, "WARNING", + _("The printer may not exist or " + "is unavailable at this time.")); + break; + + case EHOSTUNREACH : + _cupsLangPrintFilter(stderr, "WARNING", + _("The printer is unreachable at this " + "time.")); + break; + + case ECONNREFUSED : + default : + _cupsLangPrintFilter(stderr, "WARNING", + _("The printer is busy.")); + break; + } sleep(delay); @@ -327,13 +382,8 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ } else { - recoverable = 1; - - _cupsLangPrintf(stderr, "DEBUG: Connection error: %s\n", - strerror(errno)); - _cupsLangPuts(stderr, - _("ERROR: recoverable: Unable to connect to printer; " - "will retry in 30 seconds...\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("The printer is not responding.")); sleep(30); } } @@ -341,43 +391,12 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ break; } - if (recoverable) - { - /* - * If we've shown a recoverable error make sure the printer proxies have a - * chance to see the recovered message. Not pretty but necessary for now... - */ - - fputs("INFO: recovered: \n", stderr); - sleep(5); - } - fputs("STATE: -connecting-to-device\n", stderr); - _cupsLangPuts(stderr, _("INFO: Connected to printer...\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer.")); -#ifdef AF_INET6 - if (addr->addr.addr.sa_family == AF_INET6) - fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6)...\n", - httpAddrString(&addr->addr, addrname, sizeof(addrname)), - ntohs(addr->addr.ipv6.sin6_port)); - else -#endif /* AF_INET6 */ - if (addr->addr.addr.sa_family == AF_INET) - fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4)...\n", - httpAddrString(&addr->addr, addrname, sizeof(addrname)), - ntohs(addr->addr.ipv4.sin_port)); - - /* - * See if the printer supports SNMP... - */ - - if ((snmp_fd = _cupsSNMPOpen(addr->addr.addr.sa_family)) >= 0) - { - have_supplies = !backendSNMPSupplies(snmp_fd, &(addr->addr), &start_count, - NULL); - } - else - have_supplies = start_count = 0; + fprintf(stderr, "DEBUG: Connected to %s:%d...\n", + httpAddrString(&(addr->addr), addrname, sizeof(addrname)), + _httpAddrPort(&(addr->addr))); /* * Print everything... @@ -385,6 +404,9 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ tbytes = 0; + if (bytes > 0) + tbytes += write(device_fd, buffer, bytes); + while (copies > 0 && tbytes >= 0) { copies --; @@ -395,17 +417,11 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ lseek(print_fd, 0, SEEK_SET); } - tbytes = backendRunLoop(print_fd, device_fd, snmp_fd, &(addr->addr), 1, 0, - backendNetworkSideCB); + tbytes = backendRunLoop(print_fd, device_fd, snmp_fd, &(addrlist->addr), 1, + 0, backendNetworkSideCB); if (print_fd != 0 && tbytes >= 0) - _cupsLangPrintf(stderr, -#ifdef HAVE_LONG_LONG - _("INFO: Sent print file, %lld bytes...\n"), -#else - _("INFO: Sent print file, %ld bytes...\n"), -#endif /* HAVE_LONG_LONG */ - CUPS_LLCAST tbytes); + _cupsLangPrintFilter(stderr, "INFO", _("Print file sent.")); } #ifdef __APPLE__ @@ -425,8 +441,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Shutdown the socket and wait for the other end to finish... */ - _cupsLangPuts(stderr, - _("INFO: Print file sent, waiting for printer to finish...\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Waiting for printer to finish.")); shutdown(device_fd, 1); @@ -437,8 +452,8 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Collect the final page count as needed... */ - if (have_supplies && - !backendSNMPSupplies(snmp_fd, &(addr->addr), &page_count, NULL) && + if (have_supplies && + !backendSNMPSupplies(snmp_fd, &(addrlist->addr), &page_count, NULL) && page_count > start_count) fprintf(stderr, "PAGE: total %d\n", page_count - start_count); @@ -457,10 +472,9 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if (print_fd != 0) close(print_fd); - if (tbytes >= 0) - _cupsLangPuts(stderr, _("INFO: Ready to print.\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Ready to print.")); - return (tbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); + return (CUPS_BACKEND_OK); } @@ -496,7 +510,7 @@ wait_bc(int device_fd, /* I - Socket */ if ((bytes = read(device_fd, buffer, sizeof(buffer))) > 0) { - fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n", + fprintf(stderr, "DEBUG: Received %d bytes of back-channel data\n", (int)bytes); cupsBackChannelWrite(buffer, bytes, 1.0); } @@ -509,5 +523,5 @@ wait_bc(int device_fd, /* I - Socket */ /* - * End of "$Id: socket.c 9454 2011-01-10 08:02:55Z mike $". + * End of "$Id: socket.c 9793 2011-05-20 03:49:49Z mike $". */ diff --git a/backend/test1284.c b/backend/test1284.c index 5c9b9996..1080c195 100644 --- a/backend/test1284.c +++ b/backend/test1284.c @@ -1,10 +1,9 @@ /* - * "$Id: test1284.c 7465 2008-04-18 16:20:11Z mike $" + * "$Id: test1284.c 9042 2010-03-24 00:45:34Z mike $" * - * IEEE-1284 support functions test program for the Common UNIX Printing - * System (CUPS). + * IEEE-1284 support functions test program for CUPS. * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -24,9 +23,7 @@ * Include necessary headers. */ -#include <cups/string.h> -#include <stdlib.h> -#include <errno.h> +#include <cups/string-private.h> #ifdef WIN32 # include <io.h> #else @@ -83,5 +80,5 @@ main(int argc, /* I - Number of command-line args */ /* - * End of "$Id: test1284.c 7465 2008-04-18 16:20:11Z mike $". + * End of "$Id: test1284.c 9042 2010-03-24 00:45:34Z mike $". */ diff --git a/backend/testbackend.c b/backend/testbackend.c index 42d060e0..682b8aa2 100644 --- a/backend/testbackend.c +++ b/backend/testbackend.c @@ -1,9 +1,9 @@ /* - * "$Id: testbackend.c 8689 2009-05-27 18:32:43Z mike $" + * "$Id: testbackend.c 9042 2010-03-24 00:45:34Z mike $" * - * Backend test program for the Common UNIX Printing System (CUPS). + * Backend test program for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2005 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -26,14 +26,11 @@ * Include necessary headers. */ -#include <stdio.h> -#include <stdlib.h> -#include <cups/string.h> +#include <cups/string-private.h> #include <cups/cups.h> #include <cups/sidechannel.h> #include <unistd.h> #include <fcntl.h> -#include <errno.h> #include <sys/wait.h> #include <signal.h> @@ -650,5 +647,5 @@ walk_cb(const char *oid, /* I - OID */ /* - * End of "$Id: testbackend.c 8689 2009-05-27 18:32:43Z mike $". + * End of "$Id: testbackend.c 9042 2010-03-24 00:45:34Z mike $". */ diff --git a/backend/testsupplies.c b/backend/testsupplies.c index ef42ed6a..827cdf6f 100644 --- a/backend/testsupplies.c +++ b/backend/testsupplies.c @@ -1,9 +1,9 @@ /* - * "$Id: testsupplies.c 7502 2008-04-28 21:30:12Z mike $" + * "$Id: testsupplies.c 9771 2011-05-12 05:21:56Z mike $" * - * SNMP supplies test program for the Common UNIX Printing System (CUPS). + * SNMP supplies test program for CUPS. * - * Copyright 2008 by Apple Inc. + * Copyright 2008-2011 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -79,5 +79,5 @@ main(int argc, /* I - Number of command-line args */ /* - * End of "$Id: testsupplies.c 7502 2008-04-28 21:30:12Z mike $". + * End of "$Id: testsupplies.c 9771 2011-05-12 05:21:56Z mike $". */ diff --git a/backend/usb-darwin.c b/backend/usb-darwin.c index a9484c76..f2cb3d36 100644 --- a/backend/usb-darwin.c +++ b/backend/usb-darwin.c @@ -1,7 +1,7 @@ /* -* "$Id: usb-darwin.c 9319 2010-09-28 19:10:26Z mike $" +* "$Id: usb-darwin.c 9793 2011-05-20 03:49:49Z mike $" * -* Copyright 2005-2010 Apple Inc. All rights reserved. +* Copyright 2005-2011 Apple 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 @@ -43,33 +43,32 @@ * * Contents: * -* list_devices() - List all USB devices. -* print_device() - Print a file to a USB device. -* sidechannel_thread() - Thread to handle side-channel requests. -* read_thread() - Thread to read the backchannel data on. -* list_device_cb() - list_device iterator callback. -* find_device_cb() - print_device iterator callback. -* status_timer_cb() - Status timer callback. -* iterate_printers() - Iterate over all the printers. -* device_added() - Device added notifier. -* copy_deviceinfo() - Copy strings from the 1284 device ID. -* release_deviceinfo() - Release deviceinfo strings. -* load_classdriver() - Load a classdriver. -* unload_classdriver() - Unload a classdriver. -* load_printerdriver() - Load vendor's classdriver. -* registry_open() - Open a connection to the printer. -* registry_close() - Close the connection to the printer. -* copy_deviceid() - Copy the 1284 device id string. -* copy_devicestring() - Copy the 1284 device id string. -* copy_value_for_key() - Copy value string associated with a key. -* cfstr_create_trim() - Create CFString and trim whitespace characters. -* parse_options() - Parse uri options. -* setup_cfLanguage() - Create AppleLanguages array from LANG environment var. -* run_legacy_backend() - Re-exec backend as ppc or i386. -* sigterm_handler() - SIGTERM handler. -* next_line() - Find the next line in a buffer. -* parse_pserror() - Scan the backchannel data for postscript errors. -* get_device_id() - Return IEEE-1284 device ID. + * list_devices() - List all USB devices. + * print_device() - Print a file to a USB device. + * read_thread() - Thread to read the backchannel data on. + * sidechannel_thread() - Handle side-channel requests. + * iterate_printers() - Iterate over all the printers. + * device_added() - Device added notifier. + * list_device_cb() - list_device iterator callback. + * find_device_cb() - print_device iterator callback. + * status_timer_cb() - Status timer callback. + * copy_deviceinfo() - Copy strings from the 1284 device ID. + * release_deviceinfo() - Release deviceinfo strings. + * load_classdriver() - Load a classdriver. + * unload_classdriver() - Unload a classdriver. + * load_printerdriver() - Load vendor's classdriver. + * registry_open() - Open a connection to the printer. + * registry_close() - Close the connection to the printer. + * copy_deviceid() - Copy the 1284 device id string. + * copy_devicestring() - Copy the 1284 device id string. + * copy_value_for_key() - Copy value string associated with a key. + * cfstr_create_trim() - Create CFString and trim whitespace characters. + * parse_options() - Parse URI options. + * sigterm_handler() - SIGTERM handler. + * next_line() - Find the next line in a buffer. + * parse_pserror() - Scan the backchannel data for postscript errors. + * soft_reset() - Send a soft reset to the device. + * get_device_id() - Return IEEE-1284 device ID. */ /* @@ -89,11 +88,11 @@ #include <mach/mach.h> #include <mach/mach_error.h> #include <mach/mach_time.h> -#include <cups/debug.h> +#include <cups/debug-private.h> +#include <cups/file-private.h> #include <cups/sidechannel.h> -#include <cups/i18n.h> +#include <cups/language-private.h> #include "backend-private.h" - #include <CoreFoundation/CoreFoundation.h> #include <IOKit/usb/IOUSBLib.h> #include <IOKit/IOCFPlugIn.h> @@ -132,7 +131,7 @@ extern char **environ; #define kUSBClassDriverProperty CFSTR("USB Printing Class") -#define kUSBGenericTOPrinterClassDriver CFSTR("/System/Library/Printers/Libraries/USBGenericTOPrintingClass.plugin") +#define kUSBGenericTOPrinterClassDriver CFSTR("/System/Library/Printers/Libraries/USBGenericPrintingClass.plugin") #define kUSBPrinterClassDeviceNotOpen -9664 /*kPMInvalidIOMContext*/ @@ -270,11 +269,11 @@ static Boolean find_device_cb(void *refcon, io_service_t obj); static Boolean list_device_cb(void *refcon, io_service_t obj); static CFStringRef cfstr_create_trim(const char *cstr); static CFStringRef copy_value_for_key(CFStringRef deviceID, CFStringRef *keys); -static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t intf, classdriver_t ***printerDriver); +static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t interface, classdriver_t ***printerDriver); static kern_return_t load_printerdriver(CFStringRef *driverBundlePath); -static kern_return_t registry_close(); +static kern_return_t registry_close(void); static kern_return_t registry_open(CFStringRef *driverBundlePath); -static kern_return_t unload_classdriver(); +static kern_return_t unload_classdriver(classdriver_t ***classdriver); static OSStatus copy_deviceid(classdriver_t **printer, CFStringRef *deviceID); static void *read_thread(void *reference); static void *sidechannel_thread(void *reference); @@ -286,7 +285,7 @@ static void iterate_printers(iterator_callback_t callBack, void *userdata); static void parse_options(char *options, char *serial, int serial_size, UInt32 *location, Boolean *wait_eof); static void release_deviceinfo(CFStringRef *make, CFStringRef *model, CFStringRef *serial); static void setup_cfLanguage(void); -static void soft_reset(); +static void soft_reset(void); static void status_timer_cb(CFRunLoopTimerRef timer, void *info); #if defined(__i386__) || defined(__x86_64__) @@ -343,10 +342,12 @@ print_device(const char *uri, /* I - Device URI */ ssize_t total_bytes; /* Total bytes written */ UInt32 bytes; /* Bytes written */ struct timeval *timeout, /* Timeout pointer */ - stimeout; /* Timeout for select() */ + tv; /* Time value */ struct timespec cond_timeout; /* pthread condition timeout */ + (void)uri; + /* * See if the side-channel descriptor is valid... */ @@ -373,7 +374,9 @@ print_device(const char *uri, /* I - Device URI */ if (!g.make || !g.model) { - _cupsLangPuts(stderr, _("ERROR: Fatal USB error\n")); + fprintf(stderr, "DEBUG: Fatal USB error.\n"); + _cupsLangPrintFilter(stderr, "ERROR", + _("There was an unrecoverable USB error.")); if (!g.make) fputs("DEBUG: USB make string is NULL\n", stderr); @@ -431,7 +434,8 @@ print_device(const char *uri, /* I - Device URI */ strlcpy(print_buffer, "USB class driver", sizeof(print_buffer)); fputs("STATE: +apple-missing-usbclassdriver-error\n", stderr); - _cupsLangPuts(stderr, _("ERROR: Fatal USB error\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("There was an unrecoverable USB error.")); fprintf(stderr, "DEBUG: Could not load %s\n", print_buffer); if (driverBundlePath) @@ -449,8 +453,8 @@ print_device(const char *uri, /* I - Device URI */ countdown -= PRINTER_POLLING_INTERVAL; if (countdown <= 0) { - _cupsLangPuts(stderr, - _("INFO: Waiting for printer to become available...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Waiting for printer to become available.")); fprintf(stderr, "DEBUG: USB printer status: 0x%08x\n", (int)status); countdown = SUBSEQUENT_LOG_INTERVAL; /* subsequent log entries, every 15 seconds */ } @@ -496,7 +500,9 @@ print_device(const char *uri, /* I - Device URI */ if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL)) { - _cupsLangPuts(stderr, _("ERROR: Fatal USB error\n")); + 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); registry_close(); return (CUPS_BACKEND_STOP); @@ -515,7 +521,9 @@ print_device(const char *uri, /* I - Device URI */ if (pthread_create(&read_thread_id, NULL, read_thread, NULL)) { - _cupsLangPuts(stderr, _("ERROR: Fatal USB error\n")); + 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); registry_close(); return (CUPS_BACKEND_STOP); @@ -532,7 +540,7 @@ print_device(const char *uri, /* I - Device URI */ while (status == noErr && copies-- > 0) { - _cupsLangPuts(stderr, _("INFO: Sending print data...\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Sending data to printer.")); if (print_fd != STDIN_FILENO) { @@ -556,15 +564,15 @@ print_device(const char *uri, /* I - Device URI */ if (g.print_bytes) { - stimeout.tv_sec = 0; - stimeout.tv_usec = 100000; /* 100ms */ - timeout = &stimeout; + tv.tv_sec = 0; + tv.tv_usec = 100000; /* 100ms */ + timeout = &tv; } else if (g.drain_output) { - stimeout.tv_sec = 0; - stimeout.tv_usec = 0; - timeout = &stimeout; + tv.tv_sec = 0; + tv.tv_usec = 0; + timeout = &tv; } else timeout = NULL; @@ -601,7 +609,8 @@ print_device(const char *uri, /* I - Device URI */ } else if (errno != EAGAIN && errno != EINTR) { - _cupsLangPuts(stderr, _("ERROR: Unable to read print data\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to read print data.")); perror("DEBUG: select"); registry_close(); return (CUPS_BACKEND_FAILED); @@ -644,7 +653,8 @@ print_device(const char *uri, /* I - Device URI */ if (errno != EAGAIN && errno != EINTR) { - _cupsLangPuts(stderr, _("ERROR: Unable to read print data\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to read print data.")); perror("DEBUG: read"); registry_close(); return (CUPS_BACKEND_FAILED); @@ -715,13 +725,14 @@ print_device(const char *uri, /* I - Device URI */ iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0); } - if (iostatus || bytes < 0) + if (iostatus) { /* * Write error - bail if we don't see an error we can retry... */ - _cupsLangPuts(stderr, _("ERROR: Unable to send print data\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to send data to printer.")); fprintf(stderr, "DEBUG: USB class driver WritePipe returned %x\n", iostatus); @@ -755,7 +766,7 @@ print_device(const char *uri, /* I - Device URI */ /* * Re-enable the SIGTERM handler so pthread_kill() will work... */ - + struct sigaction action; /* POSIX signal action */ memset(&action, 0, sizeof(action)); @@ -780,17 +791,22 @@ print_device(const char *uri, /* I - Device URI */ g.sidechannel_thread_stop = 1; pthread_mutex_lock(&g.sidechannel_thread_mutex); + if (!g.sidechannel_thread_done) { - /* - * Wait for the side-channel thread to exit... - */ + gettimeofday(&tv, NULL); + cond_timeout.tv_sec = tv.tv_sec + WAIT_SIDE_DELAY; + cond_timeout.tv_nsec = tv.tv_usec * 1000; - cond_timeout.tv_sec = time(NULL) + WAIT_SIDE_DELAY; - cond_timeout.tv_nsec = 0; - if (pthread_cond_timedwait(&g.sidechannel_thread_cond, - &g.sidechannel_thread_mutex, - &cond_timeout) != 0) + while (!g.sidechannel_thread_done) + { + if (pthread_cond_timedwait(&g.sidechannel_thread_cond, + &g.sidechannel_thread_mutex, + &cond_timeout) != 0) + break; + } + + if (!g.sidechannel_thread_done) { /* * Force the side-channel thread to exit... @@ -800,6 +816,7 @@ print_device(const char *uri, /* I - Device URI */ pthread_kill(sidechannel_thread_id, SIGTERM); } } + pthread_mutex_unlock(&g.sidechannel_thread_mutex); pthread_join(sidechannel_thread_id, NULL); @@ -826,11 +843,18 @@ print_device(const char *uri, /* I - Device URI */ if (!g.read_thread_done) { - cond_timeout.tv_sec = time(NULL) + WAIT_EOF_DELAY; - cond_timeout.tv_nsec = 0; + 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 (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex, - &cond_timeout) != 0) + if (!g.read_thread_done) { /* * Force the read thread to exit... @@ -841,6 +865,7 @@ print_device(const char *uri, /* I - Device URI */ pthread_kill(read_thread_id, SIGTERM); } } + pthread_mutex_unlock(&g.read_thread_mutex); pthread_join(read_thread_id, NULL); /* wait for the read thread to return */ @@ -886,6 +911,9 @@ static void *read_thread(void *reference) uint64_t start, delay; + + (void)reference; + /* Calculate what 250 milliSeconds are in mach absolute time... */ mach_timebase_info(&timeBaseInfo); @@ -961,6 +989,8 @@ sidechannel_thread(void *reference) int datalen; /* Request/response data size */ + (void)reference; + do { datalen = sizeof(data); @@ -1152,6 +1182,9 @@ static Boolean list_device_cb(void *refcon, { Boolean keepRunning = (obj != 0x0); + + (void)refcon; + if (keepRunning) { CFStringRef deviceIDString = NULL; @@ -1278,7 +1311,7 @@ static Boolean find_device_cb(void *refcon, if (!keepLooking && g.status_timer != NULL) { fputs("STATE: -offline-report\n", stderr); - _cupsLangPuts(stderr, _("INFO: Printer is now online.\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Printer is now online.")); CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), g.status_timer, kCFRunLoopDefaultMode); CFRelease(g.status_timer); g.status_timer = NULL; @@ -1295,8 +1328,11 @@ static Boolean find_device_cb(void *refcon, static void status_timer_cb(CFRunLoopTimerRef timer, void *info) { + (void)timer; + (void)info; + fputs("STATE: +offline-report\n", stderr); - _cupsLangPuts(stderr, _("INFO: Printer is offline.\n")); + _cupsLangPrintFilter(stderr, "INFO", _("Printer is offline.")); if (getenv("CLASS") != NULL) { @@ -1375,14 +1411,13 @@ static void release_deviceinfo(CFStringRef *make, */ static kern_return_t load_classdriver(CFStringRef driverPath, - printer_interface_t intf, + printer_interface_t interface, classdriver_t ***printerDriver) { kern_return_t kr = kUSBPrinterClassDeviceNotOpen; classdriver_t **driver = NULL; CFStringRef bundle = driverPath ? driverPath : kUSBGenericTOPrinterClassDriver; char bundlestr[1024]; /* Bundle path */ - struct stat bundleinfo; /* File information for bundle */ CFURLRef url; /* URL for driver */ CFPlugInRef plugin = NULL; /* Plug-in address */ @@ -1393,21 +1428,14 @@ static kern_return_t load_classdriver(CFStringRef driverPath, * Validate permissions for the class driver... */ - if (stat(bundlestr, &bundleinfo)) - { - fprintf(stderr, "DEBUG: Unable to load class driver \"%s\": %s\n", - bundlestr, strerror(errno)); - if (errno == ENOENT) - return (load_classdriver(NULL, intf, printerDriver)); - else - return (kr); - } - else if (bundleinfo.st_mode & S_IWOTH) - { - fprintf(stderr, "DEBUG: Unable to load class driver \"%s\": insecure file " - "permissions (0%o)\n", bundlestr, bundleinfo.st_mode); + _cups_fc_result_t result = _cupsFileCheck(bundlestr, + _CUPS_FILE_CHECK_DIRECTORY, 1, + _cupsFileCheckFilter, NULL); + + if (result && driverPath) + return (load_classdriver(NULL, interface, printerDriver)); + else if (result) return (kr); - } /* * Try loading the class driver... @@ -1437,15 +1465,15 @@ static kern_return_t load_classdriver(CFStringRef driverPath, { classdriver_t **genericDriver = NULL; if (driverPath != NULL && CFStringCompare(driverPath, kUSBGenericTOPrinterClassDriver, 0) != kCFCompareEqualTo) - kr = load_classdriver(NULL, intf, &genericDriver); + kr = load_classdriver(NULL, interface, &genericDriver); if (kr == kIOReturnSuccess) { - (*driver)->interface = intf; + (*driver)->interface = interface; (*driver)->Initialize(driver, genericDriver); (*driver)->plugin = plugin; - (*driver)->interface = intf; + (*driver)->interface = interface; *printerDriver = driver; } } @@ -1488,20 +1516,20 @@ static kern_return_t load_printerdriver(CFStringRef *driverBundlePath) IOCFPlugInInterface **iodev = NULL; SInt32 score; kern_return_t kr; - printer_interface_t intf; + printer_interface_t interface; HRESULT res; kr = IOCreatePlugInInterfaceForService(g.printer_obj, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score); if (kr == kIOReturnSuccess) { - if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &intf)) == noErr) + if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &interface)) == noErr) { *driverBundlePath = IORegistryEntryCreateCFProperty(g.printer_obj, kUSBClassDriverProperty, NULL, kNilOptions); - kr = load_classdriver(*driverBundlePath, intf, &g.classdriver); + kr = load_classdriver(*driverBundlePath, interface, &g.classdriver); if (kr != kIOReturnSuccess) - (*intf)->Release(intf); + (*interface)->Release(interface); } IODestroyPlugInInterface(iodev); } @@ -1552,7 +1580,7 @@ static kern_return_t registry_open(CFStringRef *driverBundlePath) * 'registry_close()' - Close the connection to the printer. */ -static kern_return_t registry_close() +static kern_return_t registry_close(void) { if (g.classdriver != NULL) (*g.classdriver)->Close(g.classdriver); @@ -1659,7 +1687,7 @@ static void copy_devicestring(io_service_t usbInterface, IOCFPlugInInterface **iodev = NULL; SInt32 score; kern_return_t kr; - printer_interface_t intf; + printer_interface_t interface; HRESULT res; classdriver_t **klassDriver = NULL; CFStringRef driverBundlePath; @@ -1670,19 +1698,19 @@ static void copy_devicestring(io_service_t usbInterface, &iodev, &score)) == kIOReturnSuccess) { if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) - &intf)) == noErr) + &interface)) == noErr) { - (*intf)->GetLocationID(intf, deviceLocation); - (*intf)->GetInterfaceNumber(intf, interfaceNumber); + (*interface)->GetLocationID(interface, deviceLocation); + (*interface)->GetInterfaceNumber(interface, interfaceNumber); driverBundlePath = IORegistryEntryCreateCFProperty(usbInterface, kUSBClassDriverProperty, NULL, kNilOptions); - kr = load_classdriver(driverBundlePath, intf, &klassDriver); + kr = load_classdriver(driverBundlePath, interface, &klassDriver); if (kr != kIOReturnSuccess && driverBundlePath != NULL) - kr = load_classdriver(NULL, intf, &klassDriver); + kr = load_classdriver(NULL, interface, &klassDriver); if (kr == kIOReturnSuccess && klassDriver != NULL) kr = copy_deviceid(klassDriver, deviceID); @@ -1692,7 +1720,7 @@ static void copy_devicestring(io_service_t usbInterface, if (driverBundlePath != NULL) CFRelease(driverBundlePath); - /* (*intf)->Release(intf); */ + /* (*interface)->Release(interface); */ } IODestroyPlugInInterface(iodev); } @@ -1831,24 +1859,24 @@ static void parse_options(char *options, * Process the option... */ - if (!strcasecmp(name, "waiteof")) + if (!_cups_strcasecmp(name, "waiteof")) { - if (!strcasecmp(value, "on") || - !strcasecmp(value, "yes") || - !strcasecmp(value, "true")) + if (!_cups_strcasecmp(value, "on") || + !_cups_strcasecmp(value, "yes") || + !_cups_strcasecmp(value, "true")) *wait_eof = true; - else if (!strcasecmp(value, "off") || - !strcasecmp(value, "no") || - !strcasecmp(value, "false")) + else if (!_cups_strcasecmp(value, "off") || + !_cups_strcasecmp(value, "no") || + !_cups_strcasecmp(value, "false")) *wait_eof = false; else - _cupsLangPrintf(stderr, - _("WARNING: Boolean expected for waiteof option " - "\"%s\"\n"), value); + _cupsLangPrintFilter(stderr, "WARNING", + _("Boolean expected for waiteof option \"%s\"."), + value); } - else if (!strcasecmp(name, "serial")) + else if (!_cups_strcasecmp(name, "serial")) strlcpy(serial, value, serial_size); - else if (!strcasecmp(name, "location") && location) + else if (!_cups_strcasecmp(name, "location") && location) *location = strtol(value, NULL, 16); } } @@ -1981,7 +2009,8 @@ static void run_legacy_backend(int argc, # else perror("DEBUG: Unable to set binary preference to ppc"); # endif /* __x86_64__ */ - _cupsLangPrintf(stderr, _("Unable to use legacy USB class driver\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to use legacy USB class driver.")); exit(CUPS_BACKEND_STOP); } } @@ -2004,7 +2033,8 @@ static void run_legacy_backend(int argc, { fprintf(stderr, "DEBUG: Unable to exec %s: %s\n", usbpath, strerror(err)); - _cupsLangPrintf(stderr, _("Unable to use legacy USB class driver\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to use legacy USB class driver.")); exit(CUPS_BACKEND_STOP); } @@ -2145,9 +2175,9 @@ static void parse_pserror(char *sockBuffer, pCommentEnd += 3; /* Skip past "]%%" */ *pCommentEnd = '\0'; /* There's always room for the nul */ - if (strncasecmp(pCommentBegin, "%%[ Error:", 10) == 0) + if (_cups_strncasecmp(pCommentBegin, "%%[ Error:", 10) == 0) logLevel = "DEBUG"; - else if (strncasecmp(pCommentBegin, "%%[ Flushing", 12) == 0) + else if (_cups_strncasecmp(pCommentBegin, "%%[ Flushing", 12) == 0) logLevel = "DEBUG"; else logLevel = "INFO"; @@ -2174,10 +2204,10 @@ static void parse_pserror(char *sockBuffer, * 'soft_reset()' - Send a soft reset to the device. */ -static void soft_reset() +static void soft_reset(void) { fd_set input_set; /* Input set for select() */ - struct timeval stimeout; /* Timeout for select() */ + struct timeval tv; /* Time value */ char buffer[2048]; /* Buffer */ struct timespec cond_timeout; /* pthread condition timeout */ @@ -2190,10 +2220,17 @@ static void soft_reset() { (*g.classdriver)->Abort(g.classdriver); - cond_timeout.tv_sec = time(NULL) + 1; - cond_timeout.tv_nsec = 0; + gettimeofday(&tv, NULL); + cond_timeout.tv_sec = tv.tv_sec + 1; + cond_timeout.tv_nsec = tv.tv_usec * 1000; - pthread_cond_timedwait(&g.readwrite_lock_cond, &g.readwrite_lock_mutex, &cond_timeout); + while (g.readwrite_lock) + { + if (pthread_cond_timedwait(&g.readwrite_lock_cond, + &g.readwrite_lock_mutex, + &cond_timeout) != 0) + break; + } } g.readwrite_lock = 1; @@ -2208,10 +2245,10 @@ static void soft_reset() FD_ZERO(&input_set); FD_SET(g.print_fd, &input_set); - stimeout.tv_sec = 0; - stimeout.tv_usec = 0; + tv.tv_sec = 0; + tv.tv_usec = 0; - while (select(g.print_fd+1, &input_set, NULL, NULL, &stimeout) > 0) + while (select(g.print_fd+1, &input_set, NULL, NULL, &tv) > 0) if (read(g.print_fd, buffer, sizeof(buffer)) <= 0) break; @@ -2256,5 +2293,5 @@ static void get_device_id(cups_sc_status_t *status, /* - * End of "$Id: usb-darwin.c 9319 2010-09-28 19:10:26Z mike $". + * End of "$Id: usb-darwin.c 9793 2011-05-20 03:49:49Z mike $". */ diff --git a/backend/usb-libusb.c b/backend/usb-libusb.c index c3f0534e..f4341521 100644 --- a/backend/usb-libusb.c +++ b/backend/usb-libusb.c @@ -1,5 +1,5 @@ /* - * "$Id: usb-libusb.c 9582 2011-03-04 19:28:38Z mike $" + * "$Id: usb-libusb.c 9831 2011-06-14 23:03:29Z mike $" * * Libusb interface code for CUPS. * @@ -31,6 +31,7 @@ #include <usb.h> #include <poll.h> +#include <cups/cups-private.h> /* @@ -113,8 +114,8 @@ print_device(const char *uri, /* I - Device URI */ while ((printer = find_device(print_cb, uri)) == NULL) { - _cupsLangPuts(stderr, - _("INFO: Waiting for printer to become available...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Waiting for printer to become available.")); sleep(5); } @@ -174,9 +175,8 @@ print_device(const char *uri, /* I - Device URI */ if (usb_bulk_write(printer->handle, printer->write_endp, buffer, bytes, 3600000) < 0) { - _cupsLangPrintf(stderr, - _("ERROR: Unable to write %d bytes to printer!\n"), - (int)bytes); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to send data to printer.")); tbytes = -1; break; } @@ -505,6 +505,7 @@ make_device_uri( *mdl, /* Model */ *des, /* Description */ *sern; /* Serial number */ + size_t mfglen; /* Length of manufacturer string */ char tempmfg[256], /* Temporary manufacturer string */ tempsern[256], /* Temporary serial number string */ *tempptr; /* Pointer into temp string */ @@ -514,7 +515,7 @@ make_device_uri( * Get the make, model, and serial numbers... */ - num_values = _ppdGet1284Values(device_id, &values); + num_values = _cupsGet1284Values(device_id, &values); if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL) if ((sern = cupsGetOption("SERN", num_values, values)) == NULL) @@ -558,9 +559,9 @@ make_device_uri( if (mfg) { - if (!strcasecmp(mfg, "Hewlett-Packard")) + if (!_cups_strcasecmp(mfg, "Hewlett-Packard")) mfg = "HP"; - else if (!strcasecmp(mfg, "Lexmark International")) + else if (!_cups_strcasecmp(mfg, "Lexmark International")) mfg = "Lexmark"; } else @@ -584,6 +585,16 @@ make_device_uri( mfg = tempmfg; } + mfglen = strlen(mfg); + + if (!strncasecmp(mdl, mfg, mfglen) && _cups_isspace(mdl[mfglen])) + { + mdl += mfglen + 1; + + while (_cups_isspace(*mdl)) + mdl ++; + } + /* * Generate the device URI from the manufacturer, model, serial number, * and interface number... @@ -736,7 +747,87 @@ print_cb(usb_printer_t *printer, /* I - Printer */ const char *device_id, /* I - IEEE-1284 device ID */ const void *data) /* I - User data (make, model, S/N) */ { - return (!strcmp((char *)data, device_uri)); + char requested_uri[1024], /* Requested URI */ + *requested_ptr, /* Pointer into requested URI */ + detected_uri[1024], /* Detected URI */ + *detected_ptr; /* Pointer into detected URI */ + + + /* + * If we have an exact match, stop now... + */ + + if (!strcmp((char *)data, device_uri)) + return (1); + + /* + * Work on copies of the URIs... + */ + + strlcpy(requested_uri, (char *)data, sizeof(requested_uri)); + strlcpy(detected_uri, device_uri, sizeof(detected_uri)); + + /* + * libusb-discovered URIs can have an "interface" specification and this + * never happens for usblp-discovered URIs, so remove the "interface" + * specification from the URI which we are checking currently. This way a + * queue for a usblp-discovered printer can now be accessed via libusb. + * + * Similarly, strip "?serial=NNN...NNN" as needed. + */ + + if ((requested_ptr = strstr(requested_uri, "?interface=")) == NULL) + requested_ptr = strstr(requested_uri, "&interface="); + if ((detected_ptr = strstr(detected_uri, "?interface=")) == NULL) + detected_ptr = strstr(detected_uri, "&interface="); + + if (!requested_ptr && detected_ptr) + { + /* + * Strip "[?&]interface=nnn" from the detected printer. + */ + + *detected_ptr = '\0'; + } + else if (requested_ptr && !detected_ptr) + { + /* + * Strip "[?&]interface=nnn" from the requested printer. + */ + + *requested_ptr = '\0'; + } + + if ((requested_ptr = strstr(requested_uri, "?serial=?")) != NULL) + { + /* + * Strip "?serial=?" from the requested printer. This is a special + * case, as "?serial=?" means no serial number and not the serial + * number '?'. This is not covered by the checks below... + */ + + *requested_ptr = '\0'; + } + + if ((requested_ptr = strstr(requested_uri, "?serial=")) == NULL && + (detected_ptr = strstr(detected_uri, "?serial=")) != NULL) + { + /* + * Strip "?serial=nnn" from the detected printer. + */ + + *detected_ptr = '\0'; + } + else if (requested_ptr && !detected_ptr) + { + /* + * Strip "?serial=nnn" from the requested printer. + */ + + *requested_ptr = '\0'; + } + + return (!strcmp(requested_uri, detected_uri)); } @@ -777,9 +868,8 @@ side_cb(usb_printer_t *printer, /* I - Printer */ while (usb_bulk_write(printer->handle, printer->write_endp, buffer, bytes, 5000) < 0) { - _cupsLangPrintf(stderr, - _("ERROR: Unable to write %d bytes to printer!\n"), - (int)bytes); + _cupsLangPrintFilter(stderr, "ERROR", + _("Unable to send data to printer.")); tbytes = -1; break; } @@ -830,6 +920,6 @@ side_cb(usb_printer_t *printer, /* I - Printer */ /* - * End of "$Id: usb-libusb.c 9582 2011-03-04 19:28:38Z mike $". + * End of "$Id: usb-libusb.c 9831 2011-06-14 23:03:29Z mike $". */ diff --git a/backend/usb-unix.c b/backend/usb-unix.c index 4e36d77b..1c280332 100644 --- a/backend/usb-unix.c +++ b/backend/usb-unix.c @@ -1,11 +1,11 @@ /* - * "$Id: usb-unix.c 8912 2009-12-08 02:13:42Z mike $" + * "$Id: usb-unix.c 9793 2011-05-20 03:49:49Z mike $" * - * USB port backend for the Common UNIX Printing System (CUPS). + * USB port backend for CUPS. * * This file is included from "usb.c" when compiled on UNIX/Linux. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -56,7 +56,7 @@ print_device(const char *uri, /* I - Device URI */ { int use_bc; /* Use backchannel path? */ int device_fd; /* USB device */ - size_t tbytes; /* Total number of bytes written */ + ssize_t tbytes; /* Total number of bytes written */ struct termios opts; /* Parallel port options */ @@ -96,10 +96,10 @@ print_device(const char *uri, /* I - Device URI */ * a read request... */ - use_bc = strcasecmp(hostname, "Brother") && - strcasecmp(hostname, "Canon") && - strncasecmp(hostname, "Konica", 6) && - strncasecmp(hostname, "Minolta", 7); + use_bc = _cups_strcasecmp(hostname, "Brother") && + _cups_strcasecmp(hostname, "Canon") && + _cups_strncasecmp(hostname, "Konica", 6) && + _cups_strncasecmp(hostname, "Minolta", 7); #endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__ */ if ((device_fd = open_device(uri, &use_bc)) == -1) @@ -113,9 +113,9 @@ print_device(const char *uri, /* I - Device URI */ * available printer in the class. */ - _cupsLangPuts(stderr, - _("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Unable to contact printer, queuing on next " + "printer in class.")); /* * Sleep 5 seconds to keep the job from requeuing too rapidly... @@ -128,23 +128,21 @@ print_device(const char *uri, /* I - Device URI */ if (errno == EBUSY) { - _cupsLangPuts(stderr, - _("INFO: Printer busy; will retry in 10 seconds...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Printer busy, will retry in 10 seconds.")); sleep(10); } else if (errno == ENXIO || errno == EIO || errno == ENOENT || errno == ENODEV) { - _cupsLangPuts(stderr, - _("INFO: Printer not connected; will retry in 30 " - "seconds...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Printer not connected, will retry in 30 " + "seconds.")); sleep(30); } else { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open device file \"%s\": %s\n"), - resource, strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to open device file")); return (CUPS_BACKEND_FAILED); } } @@ -194,13 +192,7 @@ print_device(const char *uri, /* I - Device URI */ #endif /* __sun */ if (print_fd != 0 && tbytes >= 0) - _cupsLangPrintf(stderr, -#ifdef HAVE_LONG_LONG - _("INFO: Sent print file, %lld bytes...\n"), -#else - _("INFO: Sent print file, %ld bytes...\n"), -#endif /* HAVE_LONG_LONG */ - CUPS_LLCAST tbytes); + _cupsLangPrintFilter(stderr, "INFO", _("Print file sent.")); } /* @@ -209,7 +201,7 @@ print_device(const char *uri, /* I - Device URI */ close(device_fd); - return (tbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); + return (CUPS_BACKEND_OK); } @@ -433,8 +425,8 @@ open_device(const char *uri, /* I - Device URI */ */ if (busy) - _cupsLangPuts(stderr, - _("INFO: Printer busy; will retry in 5 seconds...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Printer is busy, will retry in 5 seconds.")); sleep(5); } @@ -517,8 +509,8 @@ open_device(const char *uri, /* I - Device URI */ if (busy) { - _cupsLangPuts(stderr, - _("INFO: Printer is busy; will retry in 5 seconds...\n")); + _cupsLangPrintFilter(stderr, "INFO", + _("Printer is busy, will retry in 5 seconds.")); sleep(5); } } @@ -627,5 +619,5 @@ side_cb(int print_fd, /* I - Print file */ /* - * End of "$Id: usb-unix.c 8912 2009-12-08 02:13:42Z mike $". + * End of "$Id: usb-unix.c 9793 2011-05-20 03:49:49Z mike $". */ diff --git a/backend/usb.c b/backend/usb.c index fddd21d2..81736a1f 100644 --- a/backend/usb.c +++ b/backend/usb.c @@ -1,9 +1,9 @@ /* - * "$Id: usb.c 7687 2008-06-24 01:28:36Z mike $" + * "$Id: usb.c 9771 2011-05-12 05:21:56Z mike $" * - * USB port backend for the Common UNIX Printing System (CUPS). + * USB port backend for CUPS. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -180,7 +180,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ else if (argc < 6 || argc > 7) { _cupsLangPrintf(stderr, - _("Usage: %s job-id user title copies options [file]\n"), + _("Usage: %s job-id user title copies options [file]"), argv[0]); return (CUPS_BACKEND_FAILED); } @@ -196,9 +196,9 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_OK) { - _cupsLangPuts(stderr, - _("ERROR: No device URI found in argv[0] or in DEVICE_URI " - "environment variable!\n")); + _cupsLangPrintFilter(stderr, "ERROR", + _("No device URI found in argv[0] or in DEVICE_URI " + "environment variable.")); return (1); } @@ -234,8 +234,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ if ((print_fd = open(argv[6], O_RDONLY)) < 0) { - _cupsLangPrintf(stderr, _("ERROR: Unable to open print file %s - %s\n"), - argv[6], strerror(errno)); + _cupsLangPrintError("ERROR", _("Unable to open print file")); return (CUPS_BACKEND_FAILED); } @@ -261,5 +260,5 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ /* - * End of "$Id: usb.c 7687 2008-06-24 01:28:36Z mike $". + * End of "$Id: usb.c 9771 2011-05-12 05:21:56Z mike $". */ |