From 7a14d7682bc444c9c97dd5bfd18a3da07efd7eb3 Mon Sep 17 00:00:00 2001 From: msweet Date: Thu, 1 May 2008 21:18:10 +0000 Subject: [PATCH] Merge CUPS 1.4svn-r7524. git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@733 a1ca3aef-8c08-0410-bb20-df032aa958be --- CHANGES.txt | 10 +- Makedefs.in | 2 + backend/Dependencies | 44 +- backend/Makefile | 25 +- backend/backend-private.h | 77 +- backend/ipp.c | 67 +- backend/lpd.c | 128 +- backend/mdns.c | 1408 +++++++++++++++++++++ backend/network.c | 664 ++++++++++ backend/runloop.c | 65 - backend/snmp-supplies.c | 48 +- backend/snmp.c | 137 ++- backend/socket.c | 6 +- backend/testsupplies.c | 2 +- config-scripts/cups-compiler.m4 | 4 + config-scripts/cups-dnssd.m4 | 5 +- cups/Dependencies | 36 +- cups/Makefile | 6 +- cups/api-filter.shtml | 4 + cups/libcups.exp | 20 +- cups/libcups_s.exp | 10 + cups/snmp-private.h | 292 +++++ cups/snmp.c | 144 +-- cups/snmp.h | 143 --- cups/testfile.c | 2 + cups/testsnmp.c | 26 +- doc/cups.css | 34 +- doc/help/api-filedir.html | 14 +- doc/help/api-filter.html | 376 +----- filter/Makefile | 13 +- filter/commandtops.c | 329 +++++ packaging/cups.list.in | 5 + packaging/cups.spec.in | 68 -- scheduler/dirsvc.c | 2017 ++++++++++++++++--------------- scheduler/dirsvc.h | 18 +- scheduler/main.c | 11 +- scheduler/printers.c | 9 +- scheduler/printers.h | 10 +- scheduler/sysman.c | 6 + scripting/php/Makefile | 2 +- systemv/cupstestppd.c | 17 +- test/5.1-lpadmin.sh | 4 +- test/run-stp-tests.sh | 23 +- 43 files changed, 4435 insertions(+), 1896 deletions(-) create mode 100644 backend/mdns.c create mode 100644 backend/network.c create mode 100644 cups/snmp-private.h delete mode 100644 cups/snmp.h create mode 100644 filter/commandtops.c diff --git a/CHANGES.txt b/CHANGES.txt index 6f6e3ed92..bb2c8d68e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,8 +1,16 @@ -CHANGES.txt - 2008-04-23 +CHANGES.txt - 2008-04-30 ------------------------ CHANGES IN CUPS V1.4b1 + - Added a mdns backend for discovery and printing to printers + that advertise themselves via DNS-SD (Bonjour) + - The ipp, lpd, and socket backends now support DNS-SD service + name resolution. + - The scheduler now uses a single shared file descriptor for + all DNS-SD registrations (STR #2674) + - The ipp, lpd, and socket backends now support SNMP-based + page accounting and supply level monitoring (STR #1655) - Added support for cupsPJLDisplay attribute to control what PJL commands are used to display the job information. - Driver information files can now be installed in diff --git a/Makedefs.in b/Makedefs.in index d4a8929d6..27fc8351e 100644 --- a/Makedefs.in +++ b/Makedefs.in @@ -140,12 +140,14 @@ LIBCUPSIMAGEORDER = @LIBCUPSIMAGEORDER@ LINKCUPS = @LINKCUPS@ $(SSLLIBS) LINKCUPSIMAGE = @LINKCUPSIMAGE@ LIBS = $(LINKCUPS) $(COMMONLIBS) +MDNS = @MDNS@ OPTIM = @OPTIM@ OPTIONS = PAMLIBS = @PAMLIBS@ PAP = @PAP@ PDFTOPS = @PDFTOPS@ PHPDIR = @PHPDIR@ +PHPOPTIONS = @PHPOPTIONS@ -I../.. `$(PHPCONFIG) --includes` SSLFLAGS = @SSLFLAGS@ SSLLIBS = @SSLLIBS@ diff --git a/backend/Dependencies b/backend/Dependencies index 26652c844..3925daacd 100644 --- a/backend/Dependencies +++ b/backend/Dependencies @@ -1,15 +1,22 @@ # 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 ../cups/backend.h -ipp.o: ../cups/cups.h ../cups/ppd.h ../cups/array.h ../cups/file.h -ipp.o: ../cups/language.h ../cups/language.h ../cups/i18n.h -ipp.o: ../cups/transcode.h ../cups/string.h -lpd.o: ../cups/backend.h ../cups/versioning.h ../cups/http-private.h -lpd.o: ../config.h ../cups/http.h ../cups/md5.h ../cups/ipp-private.h -lpd.o: ../cups/ipp.h ../cups/cups.h ../cups/ppd.h ../cups/array.h -lpd.o: ../cups/file.h ../cups/language.h ../cups/i18n.h ../cups/transcode.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/cups.h ../cups/ppd.h +ipp.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/debug.h +ipp.o: ../cups/i18n.h ../cups/transcode.h ../cups/snmp-private.h +ipp.o: ../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/cups.h ../cups/ppd.h +lpd.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/debug.h +lpd.o: ../cups/i18n.h ../cups/transcode.h ../cups/snmp-private.h lpd.o: ../cups/string.h +mdns.o: backend-private.h ../cups/backend.h ../cups/versioning.h +mdns.o: ../cups/sidechannel.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +mdns.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h +mdns.o: ../cups/debug.h ../cups/i18n.h ../cups/transcode.h +mdns.o: ../cups/snmp-private.h ../cups/string.h ../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 @@ -17,8 +24,8 @@ 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/cups.h ../cups/ipp.h ../cups/http.h parallel.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h -parallel.o: ../cups/debug.h ../cups/i18n.h ../cups/transcode.h ../cups/snmp.h -parallel.o: ../cups/string.h ../config.h +parallel.o: ../cups/debug.h ../cups/i18n.h ../cups/transcode.h +parallel.o: ../cups/snmp-private.h ../cups/string.h ../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 @@ -26,25 +33,26 @@ scsi.o: ../cups/string.h ../config.h serial.o: backend-private.h ../cups/backend.h ../cups/versioning.h serial.o: ../cups/sidechannel.h ../cups/cups.h ../cups/ipp.h ../cups/http.h serial.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h -serial.o: ../cups/debug.h ../cups/i18n.h ../cups/transcode.h ../cups/snmp.h -serial.o: ../cups/string.h ../config.h +serial.o: ../cups/debug.h ../cups/i18n.h ../cups/transcode.h +serial.o: ../cups/snmp-private.h ../cups/string.h ../config.h snmp.o: backend-private.h ../cups/backend.h ../cups/versioning.h snmp.o: ../cups/sidechannel.h ../cups/cups.h ../cups/ipp.h ../cups/http.h snmp.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h -snmp.o: ../cups/debug.h ../cups/i18n.h ../cups/transcode.h ../cups/snmp.h -snmp.o: ../cups/string.h ../config.h ../cups/array.h ../cups/file.h -snmp.o: ../cups/http-private.h ../cups/md5.h ../cups/ipp-private.h +snmp.o: ../cups/debug.h ../cups/i18n.h ../cups/transcode.h +snmp.o: ../cups/snmp-private.h ../cups/string.h ../config.h ../cups/array.h +snmp.o: ../cups/file.h ../cups/http-private.h ../cups/md5.h +snmp.o: ../cups/ipp-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/cups.h ../cups/ppd.h ../cups/array.h socket.o: ../cups/file.h ../cups/language.h ../cups/debug.h ../cups/i18n.h -socket.o: ../cups/transcode.h ../cups/snmp.h ../cups/string.h +socket.o: ../cups/transcode.h ../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/cups.h ../cups/ipp.h ../cups/http.h ../cups/ppd.h test1284.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/debug.h -test1284.o: ../cups/i18n.h ../cups/transcode.h ../cups/snmp.h +test1284.o: ../cups/i18n.h ../cups/transcode.h ../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 @@ -53,7 +61,7 @@ testsupplies.o: backend-private.h ../cups/backend.h ../cups/versioning.h testsupplies.o: ../cups/sidechannel.h ../cups/cups.h ../cups/ipp.h testsupplies.o: ../cups/http.h ../cups/ppd.h ../cups/array.h ../cups/file.h testsupplies.o: ../cups/language.h ../cups/debug.h ../cups/i18n.h -testsupplies.o: ../cups/transcode.h ../cups/snmp.h ../cups/string.h +testsupplies.o: ../cups/transcode.h ../cups/snmp-private.h ../cups/string.h testsupplies.o: ../config.h usb.o: ../cups/backend.h ../cups/versioning.h ../cups/cups.h ../cups/ipp.h usb.o: ../cups/http.h ../cups/ppd.h ../cups/array.h ../cups/file.h diff --git a/backend/Makefile b/backend/Makefile index c8af61b38..45bf74c25 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -17,13 +17,13 @@ include ../Makedefs -RBACKENDS = ipp lpd +RBACKENDS = ipp lpd $(MDNS) UBACKENDS = $(PAP) $(LEGACY_BACKENDS) serial snmp socket usb TARGETS = test1284 testbackend testsupplies \ libbackend.a $(RBACKENDS) $(UBACKENDS) -LIBOBJS = ieee1284.o runloop.o snmp-supplies.o -OBJS = ipp.o lpd.o pap.o parallel.o scsi.o serial.o snmp.o socket.o \ - test1284.o testbackend.o testsupplies.o usb.o +LIBOBJS = ieee1284.o network.o runloop.o snmp-supplies.o +OBJS = ipp.o lpd.o mdns.o pap.o parallel.o scsi.o serial.o snmp.o \ + socket.o test1284.o testbackend.o testsupplies.o usb.o # @@ -157,9 +157,9 @@ libbackend.a: $(LIBOBJS) # ipp # -ipp: ipp.o ../cups/$(LIBCUPS) +ipp: ipp.o ../cups/$(LIBCUPS) libbackend.a echo Linking $@... - $(CC) $(LDFLAGS) -o ipp ipp.o $(LIBS) + $(CC) $(LDFLAGS) -o ipp ipp.o libbackend.a $(LIBS) $(RM) http $(LN) ipp http @@ -168,9 +168,18 @@ ipp: ipp.o ../cups/$(LIBCUPS) # lpd # -lpd: lpd.o ../cups/$(LIBCUPS) +lpd: lpd.o ../cups/$(LIBCUPS) libbackend.a echo Linking $@... - $(CC) $(LDFLAGS) -o lpd lpd.o $(LIBS) + $(CC) $(LDFLAGS) -o lpd lpd.o libbackend.a $(LIBS) + + +# +# mdns +# + +mdns: mdns.o ../cups/$(LIBCUPS) libbackend.a + echo Linking $@... + $(CC) $(LDFLAGS) -o mdns mdns.o libbackend.a $(LIBS) # diff --git a/backend/backend-private.h b/backend/backend-private.h index 9bbfa1e50..1a295b9a5 100644 --- a/backend/backend-private.h +++ b/backend/backend-private.h @@ -28,7 +28,7 @@ # include # include # include -# include +# include # include # include # include @@ -48,6 +48,7 @@ extern "C" { * OID constants... */ +/* Host MIB */ #define CUPS_OID_mib2 1,3,6,1,2,1 #define CUPS_OID_host CUPS_OID_mib2,25 @@ -68,6 +69,7 @@ extern "C" { #define CUPS_OID_hrPrinterStatus CUPS_OID_hrPrinterEntry,1 #define CUPS_OID_hrPrinterDetectedErrorState CUPS_OID_hrPrinterEntry,2 +/* Printer MIB */ #define CUPS_OID_printmib CUPS_OID_mib2,43 #define CUPS_OID_prtGeneral CUPS_OID_printmib,5 @@ -115,6 +117,39 @@ extern "C" { #define CUPS_OID_prtInterpreterLangFamily CUPS_OID_prtInterpreterEntry,2 #define CUPS_OID_prtInterpreterLangLevel CUPS_OID_prtInterpreterEntry,3 +/* Printer Port Monitor MIB */ +#define CUPS_OID_enterprises 1,3,6,1,4,1 +#define CUPS_OID_pwg CUPS_OID_enterprises,2699,1 +#define CUPS_OID_ppmMIB CUPS_OID_pwg,2 +#define CUPS_OID_ppmMIBObjects CUPS_OID_ppmMIB,1 + +#define CUPS_OID_ppmGeneral CUPS_OID_ppmMIBObjects,1 + +#define CUPS_OID_ppmPrinter CUPS_OID_ppmMIBObjects,2 +#define CUPS_OID_ppmPrinterTable CUPS_OID_ppmPrinter,1 +#define CUPS_OID_ppmPrinterEntry CUPS_OID_ppmPrinterTable,1 +#define CUPS_OID_ppmPrinterIndex CUPS_OID_ppmPrinterEntry,1 +#define CUPS_OID_ppmPrinterName CUPS_OID_ppmPrinterEntry,2 +#define CUPS_OID_ppmPrinterIEEE1284DeviceId CUPS_OID_ppmPrinterEntry,3 +#define CUPS_OID_ppmPrinterNumberOfPorts CUPS_OID_ppmPrinterEntry,4 +#define CUPS_OID_ppmPrinterPreferredPortIndex CUPS_OID_ppmPrinterEntry,5 +#define CUPS_OID_ppmPrinterHrDeviceIndex CUPS_OID_ppmPrinterEntry,6 +#define CUPS_OID_ppmPrinterSnmpCommunityName CUPS_OID_ppmPrinterEntry,7 +#define CUPS_OID_ppmPrinterSnmpQueryEnabled CUPS_OID_ppmPrinterEntry,8 + +#define CUPS_OID_ppmPort CUPS_OID_ppmMIBObjects,3 +#define CUPS_OID_ppmPortTable CUPS_OID_ppmPort,1 +#define CUPS_OID_ppmPortEntry CUPS_OID_ppmPortTable,1 +#define CUPS_OID_ppmPortIndex CUPS_OID_ppmPortEntry,1 +#define CUPS_OID_ppmPortEnabled CUPS_OID_ppmPortEntry,2 +#define CUPS_OID_ppmPortName CUPS_OID_ppmPortEntry,3 +#define CUPS_OID_ppmPortServiceNameOrURI CUPS_OID_ppmPortEntry,4 +#define CUPS_OID_ppmPortProtocolType CUPS_OID_ppmPortEntry,5 +#define CUPS_OID_ppmPortProtocolTargetPort CUPS_OID_ppmPortEntry,6 +#define CUPS_OID_ppmPortProtocolAltSourceEnabled CUPS_OID_ppmPortEntry,7 +#define CUPS_OID_ppmPortPrtChannelIndex CUPS_OID_ppmPortEntry,8 +#define CUPS_OID_ppmPortLprByteCountEnabled CUPS_OID_ppmPortEntry,9 + /* * State constants... @@ -205,21 +240,31 @@ extern "C" { * Prototypes... */ -extern int backendDrainOutput(int print_fd, int device_fd); -extern int backendGetDeviceID(int fd, char *device_id, int device_id_size, - char *make_model, int make_model_size, - const char *scheme, char *uri, int uri_size); -extern int backendGetMakeModel(const char *device_id, char *make_model, - int make_model_size); -extern void 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, - void (*side_cb)(int print_fd, int device_fd, - int snmp_fd, http_addr_t *addr, - int use_bc)); -extern int backendSNMPSupplies(int snmp_fd, http_addr_t *addr, - int *page_count, int *printer_state); +extern void backendCheckSideChannel(int snmp_fd, http_addr_t *addr); +extern int backendDrainOutput(int print_fd, int device_fd); +extern int backendGetDeviceID(int fd, char *device_id, + int device_id_size, + char *make_model, + int make_model_size, + const char *scheme, char *uri, + int uri_size); +extern int backendGetMakeModel(const char *device_id, + char *make_model, + int make_model_size); +extern void backendNetworkSideCB(int print_fd, int device_fd, + int snmp_fd, http_addr_t *addr, + int use_bc); +extern const char *backendResolveURI(char **argv); +extern ssize_t backendRunLoop(int print_fd, int device_fd, int snmp_fd, + http_addr_t *addr, int use_bc, + void (*side_cb)(int print_fd, + int device_fd, + int snmp_fd, + http_addr_t *addr, + int use_bc)); +extern int backendSNMPSupplies(int snmp_fd, http_addr_t *addr, + int *page_count, + int *printer_state); # ifdef __cplusplus } diff --git a/backend/ipp.c b/backend/ipp.c index 1feb6fdb1..4704741de 100644 --- a/backend/ipp.c +++ b/backend/ipp.c @@ -33,17 +33,9 @@ */ #include -#include -#include -#include +#include "backend-private.h" #include #include -#include -#include -#include -#include -#include -#include #include /* @@ -105,6 +97,9 @@ main(int argc, /* I - Number of command-line args */ *name, /* Name of option */ *value, /* Value of option */ sep; /* Separator character */ + int snmp_fd, /* SNMP socket */ + start_count, /* Page count via SNMP at start */ + page_count; /* Page count via SNMP */ int num_files; /* Number of files to print */ char **files, /* Files to print */ *filename; /* Pointer to single filename */ @@ -225,7 +220,7 @@ main(int argc, /* I - Number of command-line args */ * Extract the hostname and printer name from the URI... */ - if (httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv), + if (httpSeparateURI(HTTP_URI_CODING_ALL, backendResolveURI(argv), method, sizeof(method), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_OK) @@ -600,6 +595,21 @@ main(int argc, /* I - Number of command-line args */ 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) + if (backendSNMPSupplies(snmp_fd, http->hostaddr, &start_count, NULL)) + { + /* + * No, close it... + */ + + _cupsSNMPClose(snmp_fd); + snmp_fd = -1; + } + /* * Build a URI for the printer and fill the standard IPP attributes for * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it @@ -620,6 +630,12 @@ main(int argc, /* I - Number of command-line args */ do { + /* + * Check for side-channel requests... + */ + + backendCheckSideChannel(snmp_fd, http->hostaddr); + /* * Build the IPP request... */ @@ -814,6 +830,12 @@ main(int argc, /* I - Number of command-line args */ while (copies_remaining > 0) { + /* + * Check for side-channel requests... + */ + + backendCheckSideChannel(snmp_fd, http->hostaddr); + /* * Build the IPP request... */ @@ -1013,6 +1035,16 @@ main(int argc, /* I - Number of command-line args */ { for (i = 0; i < num_files; i ++) { + /* + * Check for side-channel requests... + */ + + backendCheckSideChannel(snmp_fd, http->hostaddr); + + /* + * Send the next file in the job... + */ + request = ippNewRequest(IPP_SEND_DOCUMENT); request->request.op.version[1] = version; @@ -1069,6 +1101,12 @@ main(int argc, /* I - Number of command-line args */ for (delay = 1; !job_cancelled;) { + /* + * Check for side-channel requests... + */ + + backendCheckSideChannel(snmp_fd, http->hostaddr); + /* * Build an IPP_GET_JOB_ATTRIBUTES request... */ @@ -1182,6 +1220,15 @@ main(int argc, /* I - Number of command-line args */ check_printer_state(http, uri, resource, argv[2], version, job_id); + /* + * Collect the final page count as needed... + */ + + if (snmp_fd >= 0 && + !backendSNMPSupplies(snmp_fd, http->hostaddr, &page_count, NULL) && + page_count > start_count) + fprintf(stderr, "PAGE: total %d\n", page_count - start_count); + /* * Free memory... */ diff --git a/backend/lpd.c b/backend/lpd.c index 100868f98..8f173d27b 100644 --- a/backend/lpd.c +++ b/backend/lpd.c @@ -29,19 +29,11 @@ * Include necessary headers. */ -#include #include -#include -#include -#include -#include +#include "backend-private.h" #include -#include -#include -#include #include #include -#include #ifdef WIN32 # include @@ -120,31 +112,31 @@ 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 */ - resource[1024], /* Resource info (printer name) */ - *options, /* Pointer to options */ - *name, /* Name of option */ - *value, /* Value of option */ - sep, /* Separator character */ - *filename, /* File to print */ - title[256]; /* Title string */ - int port; /* Port number */ - int fd; /* Print file */ - int status; /* Status of LPD job */ - int mode; /* Print mode */ - int banner; /* Print banner page? */ - int format; /* Print format */ - int order; /* Order of control/data files */ - int reserve; /* Reserve priviledged port? */ - int sanitize_title; /* Sanitize title string? */ - int manual_copies, /* Do manual copies? */ - timeout, /* Timeout */ - contimeout, /* Connection timeout */ - copies; /* Number of copies */ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info */ + resource[1024], /* Resource info (printer name) */ + *options, /* Pointer to options */ + *name, /* Name of option */ + *value, /* Value of option */ + sep, /* Separator character */ + *filename, /* File to print */ + title[256]; /* Title string */ + int port; /* Port number */ + int fd; /* Print file */ + int status; /* Status of LPD job */ + int mode; /* Print mode */ + int banner; /* Print banner page? */ + int format; /* Print format */ + int order; /* Order of control/data files */ + int reserve; /* Reserve priviledged port? */ + int sanitize_title; /* Sanitize title string? */ + int manual_copies, /* Do manual copies? */ + timeout, /* Timeout */ + contimeout, /* Connection timeout */ + copies; /* Number of copies */ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ + struct sigaction action; /* Actions for POSIX signals */ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ @@ -196,7 +188,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Extract the hostname and printer name from the URI... */ - httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv), + httpSeparateURI(HTTP_URI_CODING_ALL, backendResolveURI(argv), method, sizeof(method), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); @@ -642,6 +634,9 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ char addrname[256]; /* Address name */ http_addrlist_t *addrlist, /* Address list */ *addr; /* Socket address */ + int snmp_fd, /* SNMP socket */ + start_count, /* Page count via SNMP at start */ + page_count; /* Page count via SNMP */ int copy; /* Copies written */ time_t start_time; /* Time of first connect */ int recoverable; /* Recoverable error shown? */ @@ -883,6 +878,27 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ httpAddrString(&addr->addr, addrname, sizeof(addrname)), ntohs(addr->addr.ipv4.sin_port), lport); + /* + * See if the printer supports SNMP... + */ + + if ((snmp_fd = _cupsSNMPOpen(addr->addr.addr.sa_family)) >= 0) + if (backendSNMPSupplies(snmp_fd, &(addr->addr), &start_count, NULL)) + { + /* + * No, close it... + */ + + _cupsSNMPClose(snmp_fd); + snmp_fd = -1; + } + + /* + * Check for side-channel requests... + */ + + backendCheckSideChannel(snmp_fd, &(addr->addr)); + /* * Next, open the print file and figure out its size... */ @@ -966,6 +982,16 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (order == ORDER_CONTROL_DATA) { + /* + * Check for side-channel requests... + */ + + backendCheckSideChannel(snmp_fd, &(addr->addr)); + + /* + * Send the control file... + */ + if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control), (int)getpid() % 1000, localhost)) { @@ -1010,6 +1036,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (status == 0) { + /* + * Check for side-channel requests... + */ + + backendCheckSideChannel(snmp_fd, &(addr->addr)); + /* * Send the print file... */ @@ -1097,6 +1129,16 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (status == 0 && order == ORDER_DATA_CONTROL) { + /* + * Check for side-channel requests... + */ + + backendCheckSideChannel(snmp_fd, &(addr->addr)); + + /* + * Send control file... + */ + if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control), (int)getpid() % 1000, localhost)) { @@ -1137,6 +1179,24 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ _cupsLangPuts(stderr, _("INFO: Control file sent successfully\n")); } + /* + * Collect the final page count as needed... + */ + + if (snmp_fd >= 0) + { + int printer_state; /* State of printer */ + + + while (!backendSNMPSupplies(snmp_fd, &(addr->addr), &page_count, + &printer_state) && + printer_state != CUPS_TC_idle) + sleep(3); + + if (page_count > start_count) + fprintf(stderr, "PAGE: total %d\n", page_count - start_count); + } + /* * Close the socket connection and input file... */ diff --git a/backend/mdns.c b/backend/mdns.c new file mode 100644 index 000000000..4c12b509f --- /dev/null +++ b/backend/mdns.c @@ -0,0 +1,1408 @@ +/* + * "$Id$" + * + * DNS-SD discovery backend for the Common UNIX Printing System (CUPS). + * + * Copyright 2008 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" + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Browse for printers. + * browse_callback() - Browse devices. + * browse_local_callback() - Browse local devices. + * compare_devices() - Compare two devices. + * get_device() - Create or update a device. + * query_callback() - Process query data. + * unquote() - Unquote a name string. + */ + +/* + * Include necessary headers. + */ + +#include "backend-private.h" +#include +#include + + +/* + * Device structure... + */ + +typedef enum +{ + CUPS_DEVICE_PRINTER = 0, /* lpd://... */ + CUPS_DEVICE_IPP, /* ipp://... */ + CUPS_DEVICE_FAX_IPP, /* ipp://... */ + CUPS_DEVICE_PDL_DATASTREAM, /* socket://... */ + CUPS_DEVICE_RIOUSBPRINT /* riousbprint://... */ +} cups_devtype_t; + + +typedef struct +{ + DNSServiceRef ref; /* Service reference for resolve */ + char *name, /* Service name */ + *domain, /* Domain name */ + *fullName, /* Full name */ + *make_and_model; /* Make and model from TXT record */ + cups_devtype_t type; /* Device registration type */ + int cups_shared, /* CUPS shared printer? */ + sent; /* Did we list the device? */ +} cups_device_t; + + +/* + * Local functions... + */ + +static void browse_callback(DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *serviceName, + const char *regtype, + const char *replyDomain, void *context); +static void browse_local_callback(DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *serviceName, + const char *regtype, + const char *replyDomain, + void *context); +static int compare_devices(cups_device_t *a, cups_device_t *b); +static void exec_backend(char **argv); +static cups_device_t *get_device(cups_array_t *devices, + const char *serviceName, + const char *regtype, + const char *replyDomain); +static void query_callback(DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *fullName, uint16_t rrtype, + uint16_t rrclass, uint16_t rdlen, + const void *rdata, uint32_t ttl, + void *context); +static void unquote(char *dst, const char *src, size_t dstsize); + + +/* + * 'main()' - Browse for printers. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line args */ + char *argv[]) /* I - Command-line arguments */ +{ + DNSServiceRef main_ref, /* Main service reference */ + fax_ipp_ref, /* IPP fax service reference */ + ipp_ref, /* IPP service reference */ + ipp_tls_ref, /* IPP w/TLS 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_printer_ref, /* Local LPD service reference */ + pdl_datastream_ref, /* AppSocket service reference */ + printer_ref, /* LPD service reference */ + riousbprint_ref; /* Remote IO service reference */ + int fd; /* Main file descriptor */ + fd_set input; /* Input set for select() */ + struct timeval timeout; /* Timeout for select() */ + cups_array_t *devices; /* Device array */ + cups_device_t *device; /* Current device */ + + + /* + * Check command-line... + */ + + setbuf(stderr, NULL); + + if (argc >= 6) + exec_backend(argv); + else if (argc != 1) + { + fputs("Usage: mdns job user title copies options [filename(s)]\n", stderr); + return (1); + } + + /* + * Create an array to track devices... + */ + + devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL); + + /* + * Browse for different kinds of printers... + */ + + if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError) + { + perror("ERROR: Unable to create service connection"); + return (1); + } + + fd = DNSServiceRefSockFD(main_ref); + + fax_ipp_ref = main_ref; + DNSServiceBrowse(&fax_ipp_ref, kDNSServiceFlagsShareConnection, 0, + "_fax-ipp._tcp", NULL, browse_callback, devices); + + ipp_ref = main_ref; + DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0, + "_ipp._tcp", NULL, browse_callback, devices); + + ipp_tls_ref = main_ref; + DNSServiceBrowse(&ipp_tls_ref, kDNSServiceFlagsShareConnection, 0, + "_ipp-tls._tcp", NULL, browse_callback, devices); + + local_fax_ipp_ref = main_ref; + DNSServiceBrowse(&local_fax_ipp_ref, kDNSServiceFlagsShareConnection, + kDNSServiceInterfaceIndexLocalOnly, + "_fax-ipp._tcp", NULL, browse_local_callback, devices); + + local_ipp_ref = main_ref; + DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection, + kDNSServiceInterfaceIndexLocalOnly, + "_ipp._tcp", NULL, browse_local_callback, devices); + + local_ipp_tls_ref = main_ref; + DNSServiceBrowse(&local_ipp_tls_ref, kDNSServiceFlagsShareConnection, + kDNSServiceInterfaceIndexLocalOnly, + "_ipp-tls._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; + DNSServiceBrowse(&pdl_datastream_ref, kDNSServiceFlagsShareConnection, 0, + "_pdl-datastream._tcp", NULL, browse_callback, devices); + + printer_ref = main_ref; + DNSServiceBrowse(&printer_ref, kDNSServiceFlagsShareConnection, 0, + "_printer._tcp", NULL, browse_callback, devices); + + riousbprint_ref = main_ref; + DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0, + "_riousbprint._tcp", NULL, browse_callback, devices); + + /* + * Loop until we are killed... + */ + + for (;;) + { + FD_ZERO(&input); + FD_SET(fd, &input); + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + if (select(fd + 1, &input, NULL, NULL, &timeout) < 0) + continue; + + if (FD_ISSET(fd, &input)) + { + /* + * Process results of our browsing... + */ + + DNSServiceProcessResult(main_ref); + } + else + { + /* + * Announce any devices we've found... + */ + + char device_uri[1024]; /* Device URI */ + static const char * const schemes[] = + { "lpd", "ipp", "ipp", "socket", "riousbprint" }; + /* URI schemes for devices */ + + + for (device = (cups_device_t *)cupsArrayFirst(devices); + device; + device = (cups_device_t *)cupsArrayNext(devices)) + if (!device->ref && !device->sent) + { + /* + * Found the device, now get the TXT record(s) for it... + */ + + device->ref = main_ref; + + fprintf(stderr, "DEBUG: Querying \"%s\"...\n", device->fullName); + + if (DNSServiceQueryRecord(&(device->ref), + kDNSServiceFlagsShareConnection, + 0, device->fullName, kDNSServiceType_TXT, + kDNSServiceClass_IN, query_callback, + devices) != kDNSServiceErr_NoError) + fputs("ERROR: Unable to query for TXT records!\n", stderr); + } + else if (!device->sent) + { + /* + * Got the TXT records, now report the device... + */ + + DNSServiceRefDeallocate(device->ref); + device->ref = 0; + + httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri), + schemes[device->type], NULL, device->fullName, 0, + device->cups_shared ? "/cups" : ""); + + printf("network %s \"%s\" \"%s\"\n", device_uri, + device->make_and_model ? device->make_and_model : "Unknown", + device->name); + + device->sent = 1; + } + } + } +} + + +/* + * 'browse_callback()' - Browse devices. + */ + +static void +browse_callback( + DNSServiceRef sdRef, /* I - Service reference */ + DNSServiceFlags flags, /* I - Option flags */ + uint32_t interfaceIndex, /* I - Interface number */ + DNSServiceErrorType errorCode, /* I - Error, if any */ + const char *serviceName, /* I - Name of service/device */ + const char *regtype, /* I - Type of service */ + const char *replyDomain, /* I - Service domain */ + void *context) /* I - Devices array */ +{ + fprintf(stderr, "DEBUG2: browse_callback(sdRef=%p, flags=%x, " + "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", " + "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n", + sdRef, flags, interfaceIndex, errorCode, + serviceName ? serviceName : "(null)", + regtype ? regtype : "(null)", + replyDomain ? replyDomain : "(null)", + context); + + /* + * Only process "add" data... + */ + + if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) + return; + + /* + * Get the device... + */ + + get_device((cups_array_t *)context, serviceName, regtype, replyDomain); +} + + +/* + * 'browse_local_callback()' - Browse local devices. + */ + +static void +browse_local_callback( + DNSServiceRef sdRef, /* I - Service reference */ + DNSServiceFlags flags, /* I - Option flags */ + uint32_t interfaceIndex, /* I - Interface number */ + DNSServiceErrorType errorCode, /* I - Error, if any */ + const char *serviceName, /* I - Name of service/device */ + const char *regtype, /* I - Type of service */ + const char *replyDomain, /* I - Service domain */ + void *context) /* I - Devices array */ +{ + cups_device_t *device; /* Device */ + + + fprintf(stderr, "DEBUG2: browse_local_callback(sdRef=%p, flags=%x, " + "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", " + "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n", + sdRef, flags, interfaceIndex, errorCode, + serviceName ? serviceName : "(null)", + regtype ? regtype : "(null)", + replyDomain ? replyDomain : "(null)", + context); + + /* + * Only process "add" data... + */ + + if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) + return; + + /* + * Get the device... + */ + + device = get_device((cups_array_t *)context, serviceName, regtype, + replyDomain); + + /* + * Hide locally-registered devices... + */ + + fprintf(stderr, "DEBUG: Hiding local printer \"%s\"...\n", + device->fullName); + device->sent = 1; +} + + +/* + * 'compare_devices()' - Compare two devices. + */ + +static int /* O - Result of comparison */ +compare_devices(cups_device_t *a, /* I - First device */ + cups_device_t *b) /* I - Second device */ +{ + int result = strcmp(a->name, b->name); + + if (result) + return (result); + else + return (strcmp(a->domain, b->domain)); +} + + +/* + * 'exec_backend()' - Execute the backend that corresponds to the + * resolved service name. + */ + +static void +exec_backend(char **argv) /* I - Command-line arguments */ +{ + const char *resolved_uri, /* Resolved device URI */ + *cups_serverbin; /* Location of programs */ + char scheme[1024], /* Scheme from URI */ + *ptr, /* Pointer into scheme */ + filename[1024]; /* Backend filename */ + + + /* + * Resolve the device URI... + */ + + resolved_uri = backendResolveURI(argv); + + /* + * Extract the scheme from the URI... + */ + + strlcpy(scheme, resolved_uri, sizeof(scheme)); + if ((ptr = strchr(scheme, ':')) != NULL) + *ptr = '\0'; + + /* + * Get the filename of the backend... + */ + + if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL) + cups_serverbin = CUPS_SERVERBIN; + + snprintf(filename, sizeof(filename), "%s/backend/%s", cups_serverbin, scheme); + + /* + * Overwrite the device URIs and run the new backend... + */ + + setenv("DEVICE_URI", resolved_uri, 1); + + argv[0] = (char *)resolved_uri; + + fprintf(stderr, "DEBUG: Executing backend \"%s\"...\n", filename); + + execv(filename, argv); + + fprintf(stderr, "ERROR: Unable to execute backend \"%s\": %s\n", filename, + strerror(errno)); + exit(CUPS_BACKEND_STOP); +} + + +/* + * 'get_device()' - Create or update a device. + */ + +static cups_device_t * /* O - Device */ +get_device(cups_array_t *devices, /* I - Device array */ + const char *serviceName, /* I - Name of service/device */ + const char *regtype, /* I - Type of service */ + const char *replyDomain) /* I - Service domain */ +{ + cups_device_t key, /* Search key */ + *device; /* Device */ + char fullName[1024]; /* Full name for query */ + + + /* + * See if this is a new device... + */ + + key.name = (char *)serviceName; + key.domain = (char *)replyDomain; + + if (!strcmp(regtype, "_ipp._tcp.") || + !strcmp(regtype, "_ipp-tls._tcp.")) + key.type = CUPS_DEVICE_IPP; + else if (!strcmp(regtype, "_fax-ipp._tcp.")) + key.type = CUPS_DEVICE_FAX_IPP; + else if (!strcmp(regtype, "_printer._tcp.")) + key.type = CUPS_DEVICE_PRINTER; + else if (!strcmp(regtype, "_pdl-datastream._tcp.")) + key.type = CUPS_DEVICE_PDL_DATASTREAM; + else + key.type = CUPS_DEVICE_RIOUSBPRINT; + + if ((device = cupsArrayFind(devices, &key)) != NULL) + { + /* + * No, see if this registration is a higher priority protocol... + */ + + if (key.type > device->type) + { + fprintf(stderr, "DEBUG: Updating \"%s\" to \"%s.%s%s\"...\n", + device->fullName, serviceName, regtype, replyDomain); + + device->type = key.type; + } + } + else + { + /* + * Yes, add the device... + */ + + fprintf(stderr, "DEBUG: Found \"%s.%s%s\"...\n", serviceName, regtype, + replyDomain); + + device = calloc(sizeof(cups_device_t), 1); + device->name = strdup(serviceName); + device->domain = strdup(replyDomain); + device->type = key.type; + + cupsArrayAdd(devices, device); + } + + /* + * Update the "full name" of this service, which is used for queries... + */ + + snprintf(fullName, sizeof(fullName), "%s.%s%s", serviceName, regtype, + replyDomain); + + if (device->fullName) + free(device->fullName); + + device->fullName = strdup(fullName); + + return (device); +} + + +/* + * 'query_callback()' - Process query data. + */ + +static void +query_callback( + DNSServiceRef sdRef, /* I - Service reference */ + DNSServiceFlags flags, /* I - Data flags */ + uint32_t interfaceIndex, /* I - Interface */ + DNSServiceErrorType errorCode, /* I - Error, if any */ + const char *fullName, /* I - Full service name */ + uint16_t rrtype, /* I - Record type */ + uint16_t rrclass, /* I - Record class */ + uint16_t rdlen, /* I - Length of record data */ + const void *rdata, /* I - Record data */ + uint32_t ttl, /* I - Time-to-live */ + void *context) /* I - Devices array */ +{ + cups_array_t *devices; /* Device array */ + char name[1024], /* Service name */ + *ptr; /* Pointer into name */ + cups_device_t key, /* Search key */ + *device; /* Device */ + + + fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, " + "interfaceIndex=%d, errorCode=%d, fullName=\"%s\", " + "rrtype=%u, rrclass=%u, rdlen=%u, rdata=%p, ttl=%u, " + "context=%p)\n", + sdRef, flags, interfaceIndex, errorCode, + fullName ? fullName : "(null)", rrtype, rrclass, rdlen, rdata, ttl, + context); + + /* + * Only process "add" data... + */ + + if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) + return; + + /* + * Lookup the service in the devices array. + */ + + devices = (cups_array_t *)context; + key.name = name; + + unquote(name, fullName, sizeof(name)); + + if ((key.domain = strstr(name, "._tcp.")) != NULL) + key.domain += 6; + else + key.domain = (char *)"local."; + + if ((ptr = strstr(name, "._")) != NULL) + *ptr = '\0'; + + if ((device = cupsArrayFind(devices, &key)) != NULL) + { + /* + * Found it, pull out the make and model from the TXT record and save it... + */ + + const void *value; /* Pointer to value */ + uint8_t valueLen; /* Length of value (max 255) */ + char make_and_model[512], /* Manufacturer and model */ + model[256]; /* Model */ + + + if ((value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MFG", + &valueLen)) == NULL) + value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MANUFACTURER", &valueLen); + + if (value && valueLen) + { + memcpy(make_and_model, value, valueLen); + make_and_model[valueLen] = '\0'; + } + else + make_and_model[0] = '\0'; + + if ((value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MDL", + &valueLen)) == NULL) + value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MODEL", &valueLen); + + if (value && valueLen) + { + memcpy(model, value, valueLen); + model[valueLen] = '\0'; + } + else if ((value = TXTRecordGetValuePtr(rdlen, rdata, "product", + &valueLen)) != NULL && valueLen > 2) + { + memcpy(model, value + 1, valueLen - 2); + model[valueLen - 2] = '\0'; + + if (!strcasecmp(model, "GPL Ghostscript") || + !strcasecmp(model, "GNU Ghostscript") || + !strcasecmp(model, "ESP Ghostscript")) + { + if ((value = TXTRecordGetValuePtr(rdlen, rdata, "ty", + &valueLen)) != NULL) + { + memcpy(model, value, valueLen); + model[valueLen] = '\0'; + + if ((ptr = strchr(model, ',')) != NULL) + *ptr = '\0'; + } + else + strcpy(model, "Unknown"); + } + } + else + strcpy(model, "Unknown"); + + if (device->make_and_model) + free(device->make_and_model); + + if (make_and_model[0]) + { + strlcat(make_and_model, " ", sizeof(make_and_model)); + strlcat(make_and_model, model, sizeof(make_and_model)); + device->make_and_model = strdup(make_and_model); + } + else + device->make_and_model = strdup(model); + + if (device->type == CUPS_DEVICE_IPP && + (value = TXTRecordGetValuePtr(rdlen, rdata, "printer-type", + &valueLen)) != NULL) + { + /* + * This is a CUPS printer! + */ + + device->cups_shared = 1; + } + } + else + fprintf(stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", fullName); +} + + +/* + * 'unquote()' - Unquote a name string. + */ + +static void +unquote(char *dst, /* I - Destination buffer */ + const char *src, /* I - Source string */ + size_t dstsize) /* I - Size of destination buffer */ +{ + char *dstend = dst + dstsize - 1; /* End of destination buffer */ + + + while (*src && dst < dstend) + { + if (*src == '\\') + { + src ++; + if (isdigit(src[0] & 255) && isdigit(src[1] & 255) && + isdigit(src[2] & 255)) + { + *dst++ = ((((src[0] - '0') * 10) + src[1] - '0') * 10) + src[2] - '0'; + src += 3; + } + else + *dst++ = *src++; + } + else + *dst++ = *src ++; + } + + *dst = '\0'; +} + + +/* + * End of "$Id$". + */ +/* + * "$Id$" + * + * DNS-SD discovery backend for the Common UNIX Printing System (CUPS). + * + * Copyright 2008 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" + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Browse for printers. + * browse_callback() - Browse devices. + * browse_local_callback() - Browse local devices. + * compare_devices() - Compare two devices. + * get_device() - Create or update a device. + * query_callback() - Process query data. + * unquote() - Unquote a name string. + */ + +/* + * Include necessary headers. + */ + +#include "backend-private.h" +#include +#include + + +/* + * Device structure... + */ + +typedef enum +{ + CUPS_DEVICE_PRINTER = 0, /* lpd://... */ + CUPS_DEVICE_IPP, /* ipp://... */ + CUPS_DEVICE_FAX_IPP, /* ipp://... */ + CUPS_DEVICE_PDL_DATASTREAM, /* socket://... */ + CUPS_DEVICE_RIOUSBPRINT /* riousbprint://... */ +} cups_devtype_t; + + +typedef struct +{ + DNSServiceRef ref; /* Service reference for resolve */ + char *name, /* Service name */ + *domain, /* Domain name */ + *fullName, /* Full name */ + *make_and_model; /* Make and model from TXT record */ + cups_devtype_t type; /* Device registration type */ + int cups_shared, /* CUPS shared printer? */ + sent; /* Did we list the device? */ +} cups_device_t; + + +/* + * Local functions... + */ + +static void browse_callback(DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *serviceName, + const char *regtype, + const char *replyDomain, void *context); +static void browse_local_callback(DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *serviceName, + const char *regtype, + const char *replyDomain, + void *context); +static int compare_devices(cups_device_t *a, cups_device_t *b); +static void exec_backend(char **argv); +static cups_device_t *get_device(cups_array_t *devices, + const char *serviceName, + const char *regtype, + const char *replyDomain); +static void query_callback(DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *fullName, uint16_t rrtype, + uint16_t rrclass, uint16_t rdlen, + const void *rdata, uint32_t ttl, + void *context); +static void unquote(char *dst, const char *src, size_t dstsize); + + +/* + * 'main()' - Browse for printers. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line args */ + char *argv[]) /* I - Command-line arguments */ +{ + DNSServiceRef main_ref, /* Main service reference */ + fax_ipp_ref, /* IPP fax service reference */ + ipp_ref, /* IPP service reference */ + ipp_tls_ref, /* IPP w/TLS 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_printer_ref, /* Local LPD service reference */ + pdl_datastream_ref, /* AppSocket service reference */ + printer_ref, /* LPD service reference */ + riousbprint_ref; /* Remote IO service reference */ + int fd; /* Main file descriptor */ + fd_set input; /* Input set for select() */ + struct timeval timeout; /* Timeout for select() */ + cups_array_t *devices; /* Device array */ + cups_device_t *device; /* Current device */ + + + /* + * Check command-line... + */ + + setbuf(stderr, NULL); + + if (argc >= 6) + exec_backend(argv); + else if (argc != 1) + { + fputs("Usage: mdns job user title copies options [filename(s)]\n", stderr); + return (1); + } + + /* + * Create an array to track devices... + */ + + devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL); + + /* + * Browse for different kinds of printers... + */ + + if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError) + { + perror("ERROR: Unable to create service connection"); + return (1); + } + + fd = DNSServiceRefSockFD(main_ref); + + fax_ipp_ref = main_ref; + DNSServiceBrowse(&fax_ipp_ref, kDNSServiceFlagsShareConnection, 0, + "_fax-ipp._tcp", NULL, browse_callback, devices); + + ipp_ref = main_ref; + DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0, + "_ipp._tcp", NULL, browse_callback, devices); + + ipp_tls_ref = main_ref; + DNSServiceBrowse(&ipp_tls_ref, kDNSServiceFlagsShareConnection, 0, + "_ipp-tls._tcp", NULL, browse_callback, devices); + + local_fax_ipp_ref = main_ref; + DNSServiceBrowse(&local_fax_ipp_ref, kDNSServiceFlagsShareConnection, + kDNSServiceInterfaceIndexLocalOnly, + "_fax-ipp._tcp", NULL, browse_local_callback, devices); + + local_ipp_ref = main_ref; + DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection, + kDNSServiceInterfaceIndexLocalOnly, + "_ipp._tcp", NULL, browse_local_callback, devices); + + local_ipp_tls_ref = main_ref; + DNSServiceBrowse(&local_ipp_tls_ref, kDNSServiceFlagsShareConnection, + kDNSServiceInterfaceIndexLocalOnly, + "_ipp-tls._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; + DNSServiceBrowse(&pdl_datastream_ref, kDNSServiceFlagsShareConnection, 0, + "_pdl-datastream._tcp", NULL, browse_callback, devices); + + printer_ref = main_ref; + DNSServiceBrowse(&printer_ref, kDNSServiceFlagsShareConnection, 0, + "_printer._tcp", NULL, browse_callback, devices); + + riousbprint_ref = main_ref; + DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0, + "_riousbprint._tcp", NULL, browse_callback, devices); + + /* + * Loop until we are killed... + */ + + for (;;) + { + FD_ZERO(&input); + FD_SET(fd, &input); + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + if (select(fd + 1, &input, NULL, NULL, &timeout) < 0) + continue; + + if (FD_ISSET(fd, &input)) + { + /* + * Process results of our browsing... + */ + + DNSServiceProcessResult(main_ref); + } + else + { + /* + * Announce any devices we've found... + */ + + char device_uri[1024]; /* Device URI */ + static const char * const schemes[] = + { "lpd", "ipp", "ipp", "socket", "riousbprint" }; + /* URI schemes for devices */ + + + for (device = (cups_device_t *)cupsArrayFirst(devices); + device; + device = (cups_device_t *)cupsArrayNext(devices)) + if (!device->ref && !device->sent) + { + /* + * Found the device, now get the TXT record(s) for it... + */ + + device->ref = main_ref; + + fprintf(stderr, "DEBUG: Querying \"%s\"...\n", device->fullName); + + if (DNSServiceQueryRecord(&(device->ref), + kDNSServiceFlagsShareConnection, + 0, device->fullName, kDNSServiceType_TXT, + kDNSServiceClass_IN, query_callback, + devices) != kDNSServiceErr_NoError) + fputs("ERROR: Unable to query for TXT records!\n", stderr); + } + else if (!device->sent) + { + /* + * Got the TXT records, now report the device... + */ + + DNSServiceRefDeallocate(device->ref); + device->ref = 0; + + httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri), + schemes[device->type], NULL, device->fullName, 0, + device->cups_shared ? "/cups" : ""); + + printf("network %s \"%s\" \"%s\"\n", device_uri, + device->make_and_model ? device->make_and_model : "Unknown", + device->name); + + device->sent = 1; + } + } + } +} + + +/* + * 'browse_callback()' - Browse devices. + */ + +static void +browse_callback( + DNSServiceRef sdRef, /* I - Service reference */ + DNSServiceFlags flags, /* I - Option flags */ + uint32_t interfaceIndex, /* I - Interface number */ + DNSServiceErrorType errorCode, /* I - Error, if any */ + const char *serviceName, /* I - Name of service/device */ + const char *regtype, /* I - Type of service */ + const char *replyDomain, /* I - Service domain */ + void *context) /* I - Devices array */ +{ + fprintf(stderr, "DEBUG2: browse_callback(sdRef=%p, flags=%x, " + "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", " + "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n", + sdRef, flags, interfaceIndex, errorCode, + serviceName ? serviceName : "(null)", + regtype ? regtype : "(null)", + replyDomain ? replyDomain : "(null)", + context); + + /* + * Only process "add" data... + */ + + if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) + return; + + /* + * Get the device... + */ + + get_device((cups_array_t *)context, serviceName, regtype, replyDomain); +} + + +/* + * 'browse_local_callback()' - Browse local devices. + */ + +static void +browse_local_callback( + DNSServiceRef sdRef, /* I - Service reference */ + DNSServiceFlags flags, /* I - Option flags */ + uint32_t interfaceIndex, /* I - Interface number */ + DNSServiceErrorType errorCode, /* I - Error, if any */ + const char *serviceName, /* I - Name of service/device */ + const char *regtype, /* I - Type of service */ + const char *replyDomain, /* I - Service domain */ + void *context) /* I - Devices array */ +{ + cups_device_t *device; /* Device */ + + + fprintf(stderr, "DEBUG2: browse_local_callback(sdRef=%p, flags=%x, " + "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", " + "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n", + sdRef, flags, interfaceIndex, errorCode, + serviceName ? serviceName : "(null)", + regtype ? regtype : "(null)", + replyDomain ? replyDomain : "(null)", + context); + + /* + * Only process "add" data... + */ + + if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) + return; + + /* + * Get the device... + */ + + device = get_device((cups_array_t *)context, serviceName, regtype, + replyDomain); + + /* + * Hide locally-registered devices... + */ + + fprintf(stderr, "DEBUG: Hiding local printer \"%s\"...\n", + device->fullName); + device->sent = 1; +} + + +/* + * 'compare_devices()' - Compare two devices. + */ + +static int /* O - Result of comparison */ +compare_devices(cups_device_t *a, /* I - First device */ + cups_device_t *b) /* I - Second device */ +{ + int result = strcmp(a->name, b->name); + + if (result) + return (result); + else + return (strcmp(a->domain, b->domain)); +} + + +/* + * 'exec_backend()' - Execute the backend that corresponds to the + * resolved service name. + */ + +static void +exec_backend(char **argv) /* I - Command-line arguments */ +{ + const char *resolved_uri, /* Resolved device URI */ + *cups_serverbin; /* Location of programs */ + char scheme[1024], /* Scheme from URI */ + *ptr, /* Pointer into scheme */ + filename[1024]; /* Backend filename */ + + + /* + * Resolve the device URI... + */ + + resolved_uri = backendResolveURI(argv); + + /* + * Extract the scheme from the URI... + */ + + strlcpy(scheme, resolved_uri, sizeof(scheme)); + if ((ptr = strchr(scheme, ':')) != NULL) + *ptr = '\0'; + + /* + * Get the filename of the backend... + */ + + if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL) + cups_serverbin = CUPS_SERVERBIN; + + snprintf(filename, sizeof(filename), "%s/backend/%s", cups_serverbin, scheme); + + /* + * Overwrite the device URIs and run the new backend... + */ + + setenv("DEVICE_URI", resolved_uri, 1); + + argv[0] = (char *)resolved_uri; + + fprintf(stderr, "DEBUG: Executing backend \"%s\"...\n", filename); + + execv(filename, argv); + + fprintf(stderr, "ERROR: Unable to execute backend \"%s\": %s\n", filename, + strerror(errno)); + exit(CUPS_BACKEND_STOP); +} + + +/* + * 'get_device()' - Create or update a device. + */ + +static cups_device_t * /* O - Device */ +get_device(cups_array_t *devices, /* I - Device array */ + const char *serviceName, /* I - Name of service/device */ + const char *regtype, /* I - Type of service */ + const char *replyDomain) /* I - Service domain */ +{ + cups_device_t key, /* Search key */ + *device; /* Device */ + char fullName[1024]; /* Full name for query */ + + + /* + * See if this is a new device... + */ + + key.name = (char *)serviceName; + key.domain = (char *)replyDomain; + + if (!strcmp(regtype, "_ipp._tcp.") || + !strcmp(regtype, "_ipp-tls._tcp.")) + key.type = CUPS_DEVICE_IPP; + else if (!strcmp(regtype, "_fax-ipp._tcp.")) + key.type = CUPS_DEVICE_FAX_IPP; + else if (!strcmp(regtype, "_printer._tcp.")) + key.type = CUPS_DEVICE_PRINTER; + else if (!strcmp(regtype, "_pdl-datastream._tcp.")) + key.type = CUPS_DEVICE_PDL_DATASTREAM; + else + key.type = CUPS_DEVICE_RIOUSBPRINT; + + if ((device = cupsArrayFind(devices, &key)) != NULL) + { + /* + * No, see if this registration is a higher priority protocol... + */ + + if (key.type > device->type) + { + fprintf(stderr, "DEBUG: Updating \"%s\" to \"%s.%s%s\"...\n", + device->fullName, serviceName, regtype, replyDomain); + + device->type = key.type; + } + } + else + { + /* + * Yes, add the device... + */ + + fprintf(stderr, "DEBUG: Found \"%s.%s%s\"...\n", serviceName, regtype, + replyDomain); + + device = calloc(sizeof(cups_device_t), 1); + device->name = strdup(serviceName); + device->domain = strdup(replyDomain); + device->type = key.type; + + cupsArrayAdd(devices, device); + } + + /* + * Update the "full name" of this service, which is used for queries... + */ + + snprintf(fullName, sizeof(fullName), "%s.%s%s", serviceName, regtype, + replyDomain); + + if (device->fullName) + free(device->fullName); + + device->fullName = strdup(fullName); + + return (device); +} + + +/* + * 'query_callback()' - Process query data. + */ + +static void +query_callback( + DNSServiceRef sdRef, /* I - Service reference */ + DNSServiceFlags flags, /* I - Data flags */ + uint32_t interfaceIndex, /* I - Interface */ + DNSServiceErrorType errorCode, /* I - Error, if any */ + const char *fullName, /* I - Full service name */ + uint16_t rrtype, /* I - Record type */ + uint16_t rrclass, /* I - Record class */ + uint16_t rdlen, /* I - Length of record data */ + const void *rdata, /* I - Record data */ + uint32_t ttl, /* I - Time-to-live */ + void *context) /* I - Devices array */ +{ + cups_array_t *devices; /* Device array */ + char name[1024], /* Service name */ + *ptr; /* Pointer into name */ + cups_device_t key, /* Search key */ + *device; /* Device */ + + + fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, " + "interfaceIndex=%d, errorCode=%d, fullName=\"%s\", " + "rrtype=%u, rrclass=%u, rdlen=%u, rdata=%p, ttl=%u, " + "context=%p)\n", + sdRef, flags, interfaceIndex, errorCode, + fullName ? fullName : "(null)", rrtype, rrclass, rdlen, rdata, ttl, + context); + + /* + * Only process "add" data... + */ + + if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) + return; + + /* + * Lookup the service in the devices array. + */ + + devices = (cups_array_t *)context; + key.name = name; + + unquote(name, fullName, sizeof(name)); + + if ((key.domain = strstr(name, "._tcp.")) != NULL) + key.domain += 6; + else + key.domain = (char *)"local."; + + if ((ptr = strstr(name, "._")) != NULL) + *ptr = '\0'; + + if ((device = cupsArrayFind(devices, &key)) != NULL) + { + /* + * Found it, pull out the make and model from the TXT record and save it... + */ + + const void *value; /* Pointer to value */ + uint8_t valueLen; /* Length of value (max 255) */ + char make_and_model[512], /* Manufacturer and model */ + model[256]; /* Model */ + + + if ((value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MFG", + &valueLen)) == NULL) + value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MANUFACTURER", &valueLen); + + if (value && valueLen) + { + memcpy(make_and_model, value, valueLen); + make_and_model[valueLen] = '\0'; + } + else + make_and_model[0] = '\0'; + + if ((value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MDL", + &valueLen)) == NULL) + value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MODEL", &valueLen); + + if (value && valueLen) + { + memcpy(model, value, valueLen); + model[valueLen] = '\0'; + } + else if ((value = TXTRecordGetValuePtr(rdlen, rdata, "product", + &valueLen)) != NULL && valueLen > 2) + { + memcpy(model, value + 1, valueLen - 2); + model[valueLen - 2] = '\0'; + + if (!strcasecmp(model, "GPL Ghostscript") || + !strcasecmp(model, "GNU Ghostscript") || + !strcasecmp(model, "ESP Ghostscript")) + { + if ((value = TXTRecordGetValuePtr(rdlen, rdata, "ty", + &valueLen)) != NULL) + { + memcpy(model, value, valueLen); + model[valueLen] = '\0'; + + if ((ptr = strchr(model, ',')) != NULL) + *ptr = '\0'; + } + else + strcpy(model, "Unknown"); + } + } + else + strcpy(model, "Unknown"); + + if (device->make_and_model) + free(device->make_and_model); + + if (make_and_model[0]) + { + strlcat(make_and_model, " ", sizeof(make_and_model)); + strlcat(make_and_model, model, sizeof(make_and_model)); + device->make_and_model = strdup(make_and_model); + } + else + device->make_and_model = strdup(model); + + if (device->type == CUPS_DEVICE_IPP && + (value = TXTRecordGetValuePtr(rdlen, rdata, "printer-type", + &valueLen)) != NULL) + { + /* + * This is a CUPS printer! + */ + + device->cups_shared = 1; + } + } + else + fprintf(stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", fullName); +} + + +/* + * 'unquote()' - Unquote a name string. + */ + +static void +unquote(char *dst, /* I - Destination buffer */ + const char *src, /* I - Source string */ + size_t dstsize) /* I - Size of destination buffer */ +{ + char *dstend = dst + dstsize - 1; /* End of destination buffer */ + + + while (*src && dst < dstend) + { + if (*src == '\\') + { + src ++; + if (isdigit(src[0] & 255) && isdigit(src[1] & 255) && + isdigit(src[2] & 255)) + { + *dst++ = ((((src[0] - '0') * 10) + src[1] - '0') * 10) + src[2] - '0'; + src += 3; + } + else + *dst++ = *src++; + } + else + *dst++ = *src ++; + } + + *dst = '\0'; +} + + +/* + * End of "$Id$". + */ diff --git a/backend/network.c b/backend/network.c new file mode 100644 index 000000000..9827c7db3 --- /dev/null +++ b/backend/network.c @@ -0,0 +1,664 @@ +/* + * "$Id$" + * + * Common network APIs for the Common UNIX Printing System (CUPS). + * + * Copyright 2007-2008 by Apple Inc. + * Copyright 2006-2007 by Easy Software Products, all rights reserved. + * + * 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" + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + */ + +/* + * Include necessary headers. + */ + +#include "backend-private.h" +#include +#ifdef __hpux +# include +#else +# include +#endif /* __hpux */ +#ifdef HAVE_DNSSD +# include +#endif /* HAVE_DNSSD */ + + +/* + * Local functions... + */ + +#ifdef HAVE_DNSSD +static void resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *fullName, const char *hostTarget, + uint16_t port, uint16_t txtLen, + const unsigned char *txtRecord, void *context); +#endif /* HAVE_DNSSD */ + + +/* + * 'backendCheckSideChannel()' - Check the side-channel for pending requests. + */ + + +void +backendCheckSideChannel( + int snmp_fd, /* I - SNMP socket */ + http_addr_t *addr) /* I - Address of device */ +{ + fd_set input; /* Select input set */ + struct timeval timeout; /* Select timeout */ + + + FD_ZERO(&input); + FD_SET(CUPS_SC_FD, &input); + + timeout.tv_sec = timeout.tv_usec = 0; + + if (select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout) > 0) + backendNetworkSideCB(-1, -1, snmp_fd, addr, 0); +} + + +/* + * 'backendNetworkSideCB()' - Handle common network side-channel commands. + */ + +void +backendNetworkSideCB( + int print_fd, /* I - Print file or -1 */ + int device_fd, /* I - Device file or -1 */ + int snmp_fd, /* I - SNMP socket */ + http_addr_t *addr, /* I - Address of device */ + int use_bc) /* I - Use back-channel data? */ +{ + 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 */ + const char *device_id; /* 1284DEVICEID env var */ + + + datalen = sizeof(data); + + if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) + { + _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n")); + return; + } + + switch (command) + { + case CUPS_SC_CMD_DRAIN_OUTPUT : + /* + * Our sockets disable the Nagle algorithm and data is sent immediately. + */ + + if (device_fd < 0) + status = CUPS_SC_STATUS_NOT_IMPLEMENTED; + else if (backendDrainOutput(print_fd, device_fd)) + status = CUPS_SC_STATUS_IO_ERROR; + else + status = CUPS_SC_STATUS_OK; + + datalen = 0; + break; + + case CUPS_SC_CMD_GET_BIDI : + data[0] = use_bc; + datalen = 1; + break; + + case CUPS_SC_CMD_GET_DEVICE_ID : + if (snmp_fd >= 0) + { + cups_snmp_t packet; /* Packet from printer */ + static const int ppmPrinterIEEE1284DeviceId[] = + { CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 }; + + if (_cupsSNMPWrite(snmp_fd, addr, 1, _cupsSNMPDefaultCommunity(), + CUPS_ASN1_GET_REQUEST, 1, + ppmPrinterIEEE1284DeviceId)) + { + if (_cupsSNMPRead(snmp_fd, &packet, 1.0) && + packet.object_type == CUPS_ASN1_OCTET_STRING) + { + strlcpy(data, packet.object_value.string, sizeof(data)); + datalen = (int)strlen(data); + break; + } + } + } + + if ((device_id = getenv("1284DEVICEID")) != NULL) + { + strlcpy(data, device_id, sizeof(data)); + datalen = (int)strlen(data); + break; + } + + default : + status = CUPS_SC_STATUS_NOT_IMPLEMENTED; + datalen = 0; + break; + } + + cupsSideChannelWrite(command, status, data, datalen, 1.0); +} + + +/* + * 'backendResolveURI()' - Get the device URI, resolving as needed. + */ + +const char * /* O - Device URI */ +backendResolveURI(char **argv) /* I - Command-line arguments */ +{ + const char *uri; /* Device URI */ + char scheme[32], /* URI components... */ + userpass[256], + hostname[1024], + resource[1024]; + int port; + http_uri_status_t status; /* URI decode status */ + + /* + * Get the device URI... + */ + + uri = cupsBackendDeviceURI(argv); + + if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, + sizeof(scheme), userpass, sizeof(userpass), + hostname, sizeof(hostname), &port, + resource, sizeof(resource))) < HTTP_URI_OK) + { + fprintf(stderr, "ERROR: Bad device URI \"%s\" (%d)!\n", uri, status); + exit (CUPS_BACKEND_STOP); + } + + /* + * Resolve it as needed... + */ + + if (strstr(hostname, "._tcp")) + { +#ifdef HAVE_DNSSD + DNSServiceRef ref; /* DNS-SD service reference */ + char *regtype, /* Pointer to type in hostname */ + *domain; /* Pointer to domain in hostname */ + static char resolved_uri[HTTP_MAX_URI]; + /* Resolved device URI */ + + /* + * Separate the hostname into service name, registration type, and domain... + */ + + regtype = strchr(hostname, '.'); + *regtype++ = '\0'; + + domain = regtype + strlen(regtype) - 1; + if (domain > regtype && *domain == '.') + *domain = '\0'; + + for (domain = strchr(regtype, '.'); + domain; + domain = strchr(domain + 1, '.')) + if (domain[1] != '_') + break; + + if (domain) + *domain++ = '\0'; + + fprintf(stderr, + "DEBUG: Resolving service \"%s\", regtype \"%s\", domain \"%s\"\n", + hostname, regtype, domain ? domain : "(null)"); + + if (DNSServiceResolve(&ref, 0, 0, hostname, regtype, domain, + resolve_callback, + resolved_uri) == kDNSServiceErr_NoError) + { + if (DNSServiceProcessResult(ref) != kDNSServiceErr_NoError) + uri = NULL; + else + uri = resolved_uri; + + DNSServiceRefDeallocate(ref); + } + else +#endif /* HAVE_DNSSD */ + + uri = NULL; + + if (!uri) + { + fprintf(stderr, "ERROR: Unable to resolve DNS-SD service \"%s\"!\n", uri); + exit(CUPS_BACKEND_STOP); + } + } + + return (uri); +} + + +#ifdef HAVE_DNSSD +/* + * 'resolve_callback()' - Build a device URI for the given service name. + */ + +static void +resolve_callback( + DNSServiceRef sdRef, /* I - Service reference */ + DNSServiceFlags flags, /* I - Results flags */ + uint32_t interfaceIndex, /* I - Interface number */ + DNSServiceErrorType errorCode, /* I - Error, if any */ + const char *fullName, /* I - Full service name */ + const char *hostTarget, /* I - Hostname */ + uint16_t port, /* I - Port number */ + uint16_t txtLen, /* I - Length of TXT record */ + const unsigned char *txtRecord, /* I - TXT record data */ + void *context) /* I - Pointer to URI buffer */ +{ + const char *scheme; /* URI scheme */ + char rp[257]; /* Remote printer */ + const void *value; /* Value from TXT record */ + uint8_t valueLen; /* Length of value */ + + + fprintf(stderr, + "DEBUG2: resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, " + "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, " + "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef, flags, + interfaceIndex, errorCode, fullName, hostTarget, port, txtLen, + txtRecord, context); + + /* + * Figure out the scheme from the full name... + */ + + if (strstr(fullName, "._ipp")) + scheme = "ipp"; + else if (strstr(fullName, "._printer.")) + scheme = "lpd"; + else if (strstr(fullName, "._pdl-datastream.")) + scheme = "socket"; + else + scheme = "riousbprint"; + + /* + * Extract the "remote printer" key from the TXT record... + */ + + if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp", + &valueLen)) != NULL) + { + /* + * Convert to resource by concatenating with a leading "/"... + */ + + rp[0] = '/'; + memcpy(rp, value, valueLen); + rp[valueLen + 1] = '\0'; + } + else + rp[0] = '\0'; + + /* + * Assemble the final device URI... + */ + + httpAssembleURI(HTTP_URI_CODING_ALL, (char *)context, HTTP_MAX_URI, scheme, + NULL, hostTarget, ntohs(port), rp); + + fprintf(stderr, "DEBUG: Resolved URI is \"%s\"...\n", (char *)context); +} +#endif /* HAVE_DNSSD */ + + +/* + * End of "$Id$". + */ +/* + * "$Id$" + * + * Common network APIs for the Common UNIX Printing System (CUPS). + * + * Copyright 2007-2008 by Apple Inc. + * Copyright 2006-2007 by Easy Software Products, all rights reserved. + * + * 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" + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + */ + +/* + * Include necessary headers. + */ + +#include "backend-private.h" +#include +#ifdef __hpux +# include +#else +# include +#endif /* __hpux */ +#ifdef HAVE_DNSSD +# include +#endif /* HAVE_DNSSD */ + + +/* + * Local functions... + */ + +#ifdef HAVE_DNSSD +static void resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *fullName, const char *hostTarget, + uint16_t port, uint16_t txtLen, + const unsigned char *txtRecord, void *context); +#endif /* HAVE_DNSSD */ + + +/* + * 'backendCheckSideChannel()' - Check the side-channel for pending requests. + */ + + +void +backendCheckSideChannel( + int snmp_fd, /* I - SNMP socket */ + http_addr_t *addr) /* I - Address of device */ +{ + fd_set input; /* Select input set */ + struct timeval timeout; /* Select timeout */ + + + FD_ZERO(&input); + FD_SET(CUPS_SC_FD, &input); + + timeout.tv_sec = timeout.tv_usec = 0; + + if (select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout) > 0) + backendNetworkSideCB(-1, -1, snmp_fd, addr, 0); +} + + +/* + * 'backendNetworkSideCB()' - Handle common network side-channel commands. + */ + +void +backendNetworkSideCB( + int print_fd, /* I - Print file or -1 */ + int device_fd, /* I - Device file or -1 */ + int snmp_fd, /* I - SNMP socket */ + http_addr_t *addr, /* I - Address of device */ + int use_bc) /* I - Use back-channel data? */ +{ + 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 */ + const char *device_id; /* 1284DEVICEID env var */ + + + datalen = sizeof(data); + + if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) + { + _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n")); + return; + } + + switch (command) + { + case CUPS_SC_CMD_DRAIN_OUTPUT : + /* + * Our sockets disable the Nagle algorithm and data is sent immediately. + */ + + if (device_fd < 0) + status = CUPS_SC_STATUS_NOT_IMPLEMENTED; + else if (backendDrainOutput(print_fd, device_fd)) + status = CUPS_SC_STATUS_IO_ERROR; + else + status = CUPS_SC_STATUS_OK; + + datalen = 0; + break; + + case CUPS_SC_CMD_GET_BIDI : + data[0] = use_bc; + datalen = 1; + break; + + case CUPS_SC_CMD_GET_DEVICE_ID : + if (snmp_fd >= 0) + { + cups_snmp_t packet; /* Packet from printer */ + static const int ppmPrinterIEEE1284DeviceId[] = + { CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 }; + + if (_cupsSNMPWrite(snmp_fd, addr, 1, _cupsSNMPDefaultCommunity(), + CUPS_ASN1_GET_REQUEST, 1, + ppmPrinterIEEE1284DeviceId)) + { + if (_cupsSNMPRead(snmp_fd, &packet, 1.0) && + packet.object_type == CUPS_ASN1_OCTET_STRING) + { + strlcpy(data, packet.object_value.string, sizeof(data)); + datalen = (int)strlen(data); + break; + } + } + } + + if ((device_id = getenv("1284DEVICEID")) != NULL) + { + strlcpy(data, device_id, sizeof(data)); + datalen = (int)strlen(data); + break; + } + + default : + status = CUPS_SC_STATUS_NOT_IMPLEMENTED; + datalen = 0; + break; + } + + cupsSideChannelWrite(command, status, data, datalen, 1.0); +} + + +/* + * 'backendResolveURI()' - Get the device URI, resolving as needed. + */ + +const char * /* O - Device URI */ +backendResolveURI(char **argv) /* I - Command-line arguments */ +{ + const char *uri; /* Device URI */ + char scheme[32], /* URI components... */ + userpass[256], + hostname[1024], + resource[1024]; + int port; + http_uri_status_t status; /* URI decode status */ + + /* + * Get the device URI... + */ + + uri = cupsBackendDeviceURI(argv); + + if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, + sizeof(scheme), userpass, sizeof(userpass), + hostname, sizeof(hostname), &port, + resource, sizeof(resource))) < HTTP_URI_OK) + { + fprintf(stderr, "ERROR: Bad device URI \"%s\" (%d)!\n", uri, status); + exit (CUPS_BACKEND_STOP); + } + + /* + * Resolve it as needed... + */ + + if (strstr(hostname, "._tcp")) + { +#ifdef HAVE_DNSSD + DNSServiceRef ref; /* DNS-SD service reference */ + char *regtype, /* Pointer to type in hostname */ + *domain; /* Pointer to domain in hostname */ + static char resolved_uri[HTTP_MAX_URI]; + /* Resolved device URI */ + + /* + * Separate the hostname into service name, registration type, and domain... + */ + + regtype = strchr(hostname, '.'); + *regtype++ = '\0'; + + domain = regtype + strlen(regtype) - 1; + if (domain > regtype && *domain == '.') + *domain = '\0'; + + for (domain = strchr(regtype, '.'); + domain; + domain = strchr(domain + 1, '.')) + if (domain[1] != '_') + break; + + if (domain) + *domain++ = '\0'; + + fprintf(stderr, + "DEBUG: Resolving service \"%s\", regtype \"%s\", domain \"%s\"\n", + hostname, regtype, domain ? domain : "(null)"); + + if (DNSServiceResolve(&ref, 0, 0, hostname, regtype, domain, + resolve_callback, + resolved_uri) == kDNSServiceErr_NoError) + { + if (DNSServiceProcessResult(ref) != kDNSServiceErr_NoError) + uri = NULL; + else + uri = resolved_uri; + + DNSServiceRefDeallocate(ref); + } + else +#endif /* HAVE_DNSSD */ + + uri = NULL; + + if (!uri) + { + fprintf(stderr, "ERROR: Unable to resolve DNS-SD service \"%s\"!\n", uri); + exit(CUPS_BACKEND_STOP); + } + } + + return (uri); +} + + +#ifdef HAVE_DNSSD +/* + * 'resolve_callback()' - Build a device URI for the given service name. + */ + +static void +resolve_callback( + DNSServiceRef sdRef, /* I - Service reference */ + DNSServiceFlags flags, /* I - Results flags */ + uint32_t interfaceIndex, /* I - Interface number */ + DNSServiceErrorType errorCode, /* I - Error, if any */ + const char *fullName, /* I - Full service name */ + const char *hostTarget, /* I - Hostname */ + uint16_t port, /* I - Port number */ + uint16_t txtLen, /* I - Length of TXT record */ + const unsigned char *txtRecord, /* I - TXT record data */ + void *context) /* I - Pointer to URI buffer */ +{ + const char *scheme; /* URI scheme */ + char rp[257]; /* Remote printer */ + const void *value; /* Value from TXT record */ + uint8_t valueLen; /* Length of value */ + + + fprintf(stderr, + "DEBUG2: resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, " + "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, " + "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef, flags, + interfaceIndex, errorCode, fullName, hostTarget, port, txtLen, + txtRecord, context); + + /* + * Figure out the scheme from the full name... + */ + + if (strstr(fullName, "._ipp")) + scheme = "ipp"; + else if (strstr(fullName, "._printer.")) + scheme = "lpd"; + else if (strstr(fullName, "._pdl-datastream.")) + scheme = "socket"; + else + scheme = "riousbprint"; + + /* + * Extract the "remote printer" key from the TXT record... + */ + + if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp", + &valueLen)) != NULL) + { + /* + * Convert to resource by concatenating with a leading "/"... + */ + + rp[0] = '/'; + memcpy(rp, value, valueLen); + rp[valueLen + 1] = '\0'; + } + else + rp[0] = '\0'; + + /* + * Assemble the final device URI... + */ + + httpAssembleURI(HTTP_URI_CODING_ALL, (char *)context, HTTP_MAX_URI, scheme, + NULL, hostTarget, ntohs(port), rp); + + fprintf(stderr, "DEBUG: Resolved URI is \"%s\"...\n", (char *)context); +} +#endif /* HAVE_DNSSD */ + + +/* + * End of "$Id$". + */ diff --git a/backend/runloop.c b/backend/runloop.c index bbf565d5f..53c6ac7f1 100644 --- a/backend/runloop.c +++ b/backend/runloop.c @@ -136,71 +136,6 @@ backendDrainOutput(int print_fd, /* I - Print file descriptor */ } -/* - * 'backendNetworkSideCB()' - Handle common network side-channel commands. - */ - -void -backendNetworkSideCB( - int print_fd, /* I - Print file or -1 */ - int device_fd, /* I - Device file or -1 */ - int snmp_fd, /* I - SNMP socket */ - http_addr_t *addr, /* I - Address of device */ - int use_bc) /* I - Use back-channel data? */ -{ - 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 */ - const char *device_id; /* 1284DEVICEID env var */ - - - datalen = sizeof(data); - - if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) - { - _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n")); - return; - } - - switch (command) - { - case CUPS_SC_CMD_DRAIN_OUTPUT : - /* - * Our sockets disable the Nagle algorithm and data is sent immediately. - */ - - if (backendDrainOutput(print_fd, device_fd)) - status = CUPS_SC_STATUS_IO_ERROR; - else - status = CUPS_SC_STATUS_OK; - - datalen = 0; - break; - - case CUPS_SC_CMD_GET_BIDI : - data[0] = use_bc; - datalen = 1; - break; - - case CUPS_SC_CMD_GET_DEVICE_ID : - if ((device_id = getenv("1284DEVICEID")) != NULL) - { - strlcpy(data, device_id, sizeof(data)); - datalen = (int)strlen(data); - break; - } - - default : - status = CUPS_SC_STATUS_NOT_IMPLEMENTED; - datalen = 0; - break; - } - - cupsSideChannelWrite(command, status, data, datalen, 1.0); -} - - /* * 'backendRunLoop()' - Read and write print and back-channel data. */ diff --git a/backend/snmp-supplies.c b/backend/snmp-supplies.c index 806b67f25..ef68dbcd0 100644 --- a/backend/snmp-supplies.c +++ b/backend/snmp-supplies.c @@ -141,8 +141,8 @@ backendSNMPSupplies( if (!httpAddrEqual(addr, ¤t_addr)) backend_init_supplies(snmp_fd, addr); else if (num_supplies > 0) - cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, - cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel, 500, + _cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, + _cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel, 500, backend_walk_cb, NULL); if (page_count) @@ -178,12 +178,12 @@ backendSNMPSupplies( * Get the current printer status bits... */ - if (!cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, - cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, + if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, + _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, hrPrinterDetectedErrorState)) return (-1); - if (!cupsSNMPRead(snmp_fd, &packet, 500) || + if (!_cupsSNMPRead(snmp_fd, &packet, 500) || packet.object_type != CUPS_ASN1_OCTET_STRING) return (-1); @@ -261,12 +261,12 @@ backendSNMPSupplies( if (printer_state) { - if (!cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, - cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, + if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, + _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, hrPrinterStatus)) return (-1); - if (!cupsSNMPRead(snmp_fd, &packet, 500) || + if (!_cupsSNMPRead(snmp_fd, &packet, 500) || packet.object_type != CUPS_ASN1_INTEGER) return (-1); @@ -279,12 +279,12 @@ backendSNMPSupplies( if (page_count) { - if (!cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, - cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, + if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, + _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, prtMarkerLifeCount)) return (-1); - if (!cupsSNMPRead(snmp_fd, &packet, 500) || + if (!_cupsSNMPRead(snmp_fd, &packet, 500) || packet.object_type != CUPS_ASN1_COUNTER) return (-1); @@ -372,12 +372,12 @@ backend_init_supplies( * Get the device description... */ - if (!cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, - cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, + if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, + _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, hrDeviceDescr)) return; - if (!cupsSNMPRead(snmp_fd, &packet, 500) || + if (!_cupsSNMPRead(snmp_fd, &packet, 500) || packet.object_type != CUPS_ASN1_OCTET_STRING) { strlcpy(description, "Unknown", sizeof(description)); @@ -440,8 +440,8 @@ backend_init_supplies( * Walk the printer configuration information... */ - cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, - cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry, 500, + _cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, + _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry, 500, backend_walk_cb, NULL); } @@ -474,8 +474,8 @@ backend_init_supplies( for (i = 0; i < num_supplies; i ++) strcpy(supplies[i].color, "none"); - cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, - cupsSNMPDefaultCommunity(), prtMarkerColorantValue, 500, + _cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, + _cupsSNMPDefaultCommunity(), prtMarkerColorantValue, 500, backend_walk_cb, NULL); /* @@ -561,7 +561,7 @@ backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */ (void)data; - if (cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) && + if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) && packet->object_type == CUPS_ASN1_OCTET_STRING) { /* @@ -584,7 +584,7 @@ backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */ } } } - else if (cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex)) + else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex)) { /* * Get colorant index... @@ -603,7 +603,7 @@ backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */ supplies[i - 1].colorant = packet->object_value.integer; } - else if (cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription)) + else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription)) { /* * Get supply name/description... @@ -623,7 +623,7 @@ backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */ strlcpy(supplies[i - 1].name, packet->object_value.string, sizeof(supplies[0].name)); } - else if (cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesLevel)) + else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesLevel)) { /* * Get level... @@ -642,7 +642,7 @@ backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */ supplies[i - 1].level = packet->object_value.integer; } - else if (cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity)) + else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity)) { /* * Get max capacity... @@ -661,7 +661,7 @@ backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */ supplies[i - 1].max_capacity = packet->object_value.integer; } - else if (cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType)) + else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType)) { /* * Get marker type... diff --git a/backend/snmp.c b/backend/snmp.c index 4e0cd1d6f..0364ee2a2 100644 --- a/backend/snmp.c +++ b/backend/snmp.c @@ -48,7 +48,6 @@ #include "backend-private.h" #include #include -#include #include #include @@ -56,14 +55,12 @@ /* * This backend implements SNMP printer discovery. It uses a broadcast- * based approach to get SNMP response packets from potential printers, - * tries a mDNS lookup (Mac OS X only at present), a URI lookup based on - * the device description string, and finally a probe of port 9100 - * (AppSocket) and 515 (LPD). + * requesting OIDs from the Host and Port Monitor MIBs, does a URI + * lookup based on the device description string, and finally a probe of + * port 9100 (AppSocket) and 515 (LPD). * * The current focus is on printers with internal network cards, although - * the code also works with many external print servers as well. Future - * versions will support scanning for vendor-specific SNMP OIDs and the - * new PWG Port Monitor MIB and not just the Host MIB OIDs. + * the code also works with many external print servers as well. * * The backend reads the snmp.conf file from the CUPS_SERVERROOT directory * which can contain comments, blank lines, or any number of the following @@ -91,6 +88,7 @@ * print servers: * * Axis OfficeBasic, 5400, 5600 + * Brother * EPSON * Genicom * HP JetDirect @@ -125,6 +123,7 @@ typedef struct snmp_cache_s /**** SNMP scan cache ****/ char *addrname, /* Name of device */ *uri, /* device-uri */ *id, /* device-id */ + *info, /* device-info */ *make_and_model; /* device-make-and-model */ } snmp_cache_t; @@ -133,7 +132,7 @@ 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); +extern void _cupsSetError(ipp_status_t status, const char *message); /* @@ -175,10 +174,14 @@ static cups_array_t *Addresses = NULL; static cups_array_t *Communities = NULL; static cups_array_t *Devices = NULL; static int DebugLevel = 0; -static int DeviceDescOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 }; +static const int DeviceDescOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 }; static unsigned DeviceDescRequest; -static int DeviceTypeOID[] = { CUPS_OID_hrDeviceType, 1, -1 }; +static const int DeviceTypeOID[] = { CUPS_OID_hrDeviceType, 1, -1 }; static unsigned DeviceTypeRequest; +static const int DeviceIdOID[] = { CUPS_OID_ppmPrinterIEEE1284DeviceId, 1, -1 }; +static unsigned DeviceIdRequest; +static const int DeviceUriOID[] = { CUPS_OID_ppmPortServiceNameOrURI, 1, 1, -1 }; +static unsigned DeviceUriRequest; static cups_array_t *DeviceURIs = NULL; static int HostNameLookups = 0; static int MaxRunTime = 120; @@ -236,7 +239,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Open the SNMP socket... */ - if ((fd = cupsSNMPOpen(AF_INET)) < 0) + if ((fd = _cupsSNMPOpen(AF_INET)) < 0) return (1); /* @@ -245,7 +248,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ read_snmp_conf(argv[1]); - cupsSNMPSetDebug(DebugLevel); + _cupsSNMPSetDebug(DebugLevel); Devices = cupsArrayNew((cups_array_func_t)compare_cache, NULL); @@ -259,7 +262,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Close, free, and return with no errors... */ - cupsSNMPClose(fd); + _cupsSNMPClose(fd); free_array(Addresses); free_array(Communities); @@ -661,8 +664,9 @@ list_device(snmp_cache_t *cache) /* I - Cached device */ printf("network %s \"%s\" \"%s %s\" \"%s\"\n", cache->uri, cache->make_and_model ? cache->make_and_model : "Unknown", - cache->make_and_model ? cache->make_and_model : "Unknown", - cache->addrname, cache->id ? cache->id : ""); + cache->info ? cache->info : "Unknown", + cache->addrname, + cache->id ? cache->id : ""); fflush(stdout); } } @@ -905,7 +909,7 @@ read_snmp_response(int fd) /* I - SNMP socket file descriptor */ * Read the response data... */ - if (!cupsSNMPRead(fd, &packet, -1.0)) + if (!_cupsSNMPRead(fd, &packet, -1.0)) { fprintf(stderr, "ERROR: Unable to read data from socket: %s\n", strerror(errno)); @@ -968,8 +972,12 @@ read_snmp_response(int fd) /* I - SNMP socket file descriptor */ add_cache(&(packet.address), addrname, NULL, NULL, NULL); - cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, + _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DeviceDescRequest, DeviceDescOID); + _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, + CUPS_ASN1_GET_REQUEST, DeviceIdRequest, DeviceIdOID); + _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, + CUPS_ASN1_GET_REQUEST, DeviceUriRequest, DeviceUriOID); } else if (packet.request_id == DeviceDescRequest && packet.object_type == CUPS_ASN1_OCTET_STRING) @@ -988,19 +996,19 @@ read_snmp_response(int fd) /* I - SNMP socket file descriptor */ return; } - /* - * Convert the description to a make and model string... - */ - if (strchr(packet.object_value.string, ':') && - strchr(packet.object_value.string, ';')) + strchr(packet.object_value.string, ';')) { /* * Description is the IEEE-1284 device ID... */ + if (!device->id) + device->id = strdup(packet.object_value.string); + backendGetMakeModel(packet.object_value.string, make_model, - sizeof(make_model)); + sizeof(make_model)); + device->info = strdup(make_model); } else { @@ -1009,15 +1017,92 @@ read_snmp_response(int fd) /* I - SNMP socket file descriptor */ */ fix_make_model(make_model, packet.object_value.string, - sizeof(make_model)); + sizeof(make_model)); + + device->info = strdup(packet.object_value.string); + } + + if (!device->make_and_model) + device->make_and_model = strdup(make_model); + + /* + * List the device now if we have all the info... + */ + + if (device->id && device->info && device->make_and_model && device->uri) + list_device(device); + } + else if (packet.request_id == DeviceIdRequest && + packet.object_type == CUPS_ASN1_OCTET_STRING) + { + /* + * Update an existing cache entry... + */ + + char make_model[256]; /* Make and model */ + + + if (!device) + { + debug_printf("DEBUG: Discarding device ID for \"%s\"...\n", + addrname); + return; } + if (device->id) + free(device->id); + + device->id = strdup(packet.object_value.string); + + /* + * Convert the ID to a make and model string... + */ + + backendGetMakeModel(packet.object_value.string, make_model, + sizeof(make_model)); if (device->make_and_model) free(device->make_and_model); device->make_and_model = strdup(make_model); - probe_device(device); + /* + * List the device now if we have all the info... + */ + + if (device->id && device->info && device->make_and_model && device->uri) + list_device(device); + } + else if (packet.request_id == DeviceUriRequest && + packet.object_type == CUPS_ASN1_OCTET_STRING) + { + /* + * Update an existing cache entry... + */ + + if (!device) + { + debug_printf("DEBUG: Discarding device URI for \"%s\"...\n", + addrname); + return; + } + + if (!strncmp(packet.object_value.string, "lpr:", 4)) + { + /* + * We want "lpd://..." for the URI... + */ + + packet.object_value.string[2] = 'd'; + } + + device->uri = strdup(packet.object_value.string); + + /* + * List the device now if we have all the info... + */ + + if (device->id && device->info && device->make_and_model && device->uri) + list_device(device); } } @@ -1103,7 +1188,7 @@ scan_devices(int fd) /* I - SNMP socket */ community, address); for (addr = addrs; addr; addr = addr->next) - cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community, + _cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community, CUPS_ASN1_GET_REQUEST, DeviceTypeRequest, DeviceTypeOID); } diff --git a/backend/socket.c b/backend/socket.c index 140061151..77a580274 100644 --- a/backend/socket.c +++ b/backend/socket.c @@ -160,7 +160,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Extract the hostname and port number from the URI... */ - httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv), + httpSeparateURI(HTTP_URI_CODING_ALL, backendResolveURI(argv), method, sizeof(method), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); @@ -363,14 +363,14 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * See if the printer supports SNMP... */ - if ((snmp_fd = cupsSNMPOpen(addr->addr.addr.sa_family)) >= 0) + if ((snmp_fd = _cupsSNMPOpen(addr->addr.addr.sa_family)) >= 0) if (backendSNMPSupplies(snmp_fd, &(addr->addr), &start_count, NULL)) { /* * No, close it... */ - cupsSNMPClose(snmp_fd); + _cupsSNMPClose(snmp_fd); snmp_fd = -1; } diff --git a/backend/testsupplies.c b/backend/testsupplies.c index 1a8246abc..c380f280f 100644 --- a/backend/testsupplies.c +++ b/backend/testsupplies.c @@ -51,7 +51,7 @@ main(int argc, /* I - Number of command-line args */ return (1); } - if ((snmp_fd = cupsSNMPOpen(host->addr.addr.sa_family)) < 0) + if ((snmp_fd = _cupsSNMPOpen(host->addr.addr.sa_family)) < 0) { perror(argv[1]); return (1); diff --git a/config-scripts/cups-compiler.m4 b/config-scripts/cups-compiler.m4 index 4b1f83c8c..004a0990c 100644 --- a/config-scripts/cups-compiler.m4 +++ b/config-scripts/cups-compiler.m4 @@ -96,6 +96,9 @@ AC_ARG_WITH(libcupsimageorder, [ --with-libcupsimagesorder fi) AC_SUBST(LIBCUPSIMAGEORDER) +PHPOPTIONS="" +AC_SUBST(PHPOPTIONS) + if test -n "$GCC"; then # Add GCC-specific compiler options... if test -z "$OPTIM"; then @@ -142,6 +145,7 @@ if test -n "$GCC"; then # Additional warning options for development testing... if test -d .svn; then OPTIM="-Wshadow -Wunused $OPTIM" + PHPOPTIONS="-Wno-shadow" fi fi diff --git a/config-scripts/cups-dnssd.m4 b/config-scripts/cups-dnssd.m4 index eaab2c194..28deb7583 100644 --- a/config-scripts/cups-dnssd.m4 +++ b/config-scripts/cups-dnssd.m4 @@ -25,6 +25,7 @@ AC_ARG_WITH(dnssd-includes, [ --with-dnssd-includes set directory for DNS Ser CPPFLAGS="-I$withval $CPPFLAGS",) DNSSDLIBS="" +MDNS="" if test x$enable_dnssd != xno; then AC_CHECK_HEADER(dns_sd.h, [ @@ -35,10 +36,11 @@ if test x$enable_dnssd != xno; then AC_DEFINE(HAVE_DNSSD) AC_DEFINE(HAVE_COREFOUNDATION) AC_DEFINE(HAVE_SYSTEMCONFIGURATION) + MDNS="mdns" ;; *) # All others... - AC_CHECK_LIB(dns_sd,DNSServiceProcessResult, + AC_CHECK_LIB(dns_sd,DNSServiceCreateConnection, AC_DEFINE(HAVE_DNSSD) DNSSDLIBS="-ldns_sd") ;; @@ -47,6 +49,7 @@ if test x$enable_dnssd != xno; then fi AC_SUBST(DNSSDLIBS) +AC_SUBST(MDNS) dnl dnl End of "$Id$". diff --git a/cups/Dependencies b/cups/Dependencies index 9f00bdad7..eb3def7ea 100644 --- a/cups/Dependencies +++ b/cups/Dependencies @@ -14,6 +14,9 @@ backend.o: backend.h versioning.h string.h ../config.h custom.o: globals.h string.h ../config.h http-private.h http.h versioning.h custom.o: md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h custom.o: i18n.h transcode.h debug.h +debug.o: globals.h string.h ../config.h http-private.h http.h versioning.h +debug.o: md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h +debug.o: i18n.h transcode.h debug.h dest.o: debug.h globals.h string.h ../config.h http-private.h http.h dest.o: versioning.h md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h dest.o: language.h i18n.h transcode.h @@ -24,6 +27,9 @@ encode.o: ipp-private.h string.h ../config.h debug.h file.o: http-private.h ../config.h http.h versioning.h md5.h ipp-private.h file.o: ipp.h globals.h string.h cups.h ppd.h array.h file.h language.h file.o: i18n.h transcode.h debug.h +getdevices.o: globals.h string.h ../config.h http-private.h http.h +getdevices.o: versioning.h md5.h ipp-private.h ipp.h cups.h ppd.h array.h +getdevices.o: file.h language.h i18n.h transcode.h debug.h getifaddrs.o: http-private.h ../config.h http.h versioning.h md5.h getifaddrs.o: ipp-private.h ipp.h getputfile.o: globals.h string.h ../config.h http-private.h http.h @@ -31,7 +37,7 @@ getputfile.o: versioning.h md5.h ipp-private.h ipp.h cups.h ppd.h array.h getputfile.o: file.h language.h i18n.h transcode.h debug.h globals.o: http-private.h ../config.h http.h versioning.h md5.h ipp-private.h globals.o: ipp.h globals.h string.h cups.h ppd.h array.h file.h language.h -globals.o: i18n.h transcode.h debug.h +globals.o: i18n.h transcode.h http.o: http-private.h ../config.h http.h versioning.h md5.h ipp-private.h http.o: ipp.h globals.h string.h cups.h ppd.h array.h file.h language.h http.o: i18n.h transcode.h debug.h @@ -79,7 +85,7 @@ request.o: i18n.h transcode.h debug.h sidechannel.o: sidechannel.h versioning.h string.h ../config.h snmp.o: globals.h string.h ../config.h http-private.h http.h versioning.h snmp.o: md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h -snmp.o: i18n.h transcode.h snmp.h +snmp.o: i18n.h transcode.h snmp-private.h snprintf.o: string.h ../config.h string.o: array.h versioning.h debug.h string.h ../config.h tempfile.o: globals.h string.h ../config.h http-private.h http.h versioning.h @@ -109,7 +115,7 @@ testlang.o: i18n.h transcode.h language.h array.h versioning.h string.h testlang.o: ../config.h testppd.o: ../cups/string.h ../config.h string.h ppd.h array.h versioning.h testppd.o: file.h -testsnmp.o: string.h ../config.h snmp.h http.h versioning.h +testsnmp.o: string.h ../config.h snmp-private.h http.h versioning.h # DO NOT DELETE adminutil.32.o: adminutil.c adminutil.h cups.h ipp.h http.h versioning.h ppd.h array.h @@ -126,6 +132,9 @@ backend.32.o: backend.c backend.h versioning.h string.h ../config.h custom.32.o: custom.c globals.h string.h ../config.h http-private.h http.h versioning.h custom.32.o: custom.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h custom.32.o: custom.c i18n.h transcode.h debug.h +debug.32.o: debug.c globals.h string.h ../config.h http-private.h http.h versioning.h +debug.32.o: debug.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h +debug.32.o: debug.c i18n.h transcode.h debug.h dest.32.o: dest.c debug.h globals.h string.h ../config.h http-private.h http.h dest.32.o: dest.c versioning.h md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h dest.32.o: dest.c language.h i18n.h transcode.h @@ -136,6 +145,9 @@ encode.32.o: encode.c ipp-private.h string.h ../config.h debug.h file.32.o: file.c http-private.h ../config.h http.h versioning.h md5.h ipp-private.h file.32.o: file.c ipp.h globals.h string.h cups.h ppd.h array.h file.h language.h file.32.o: file.c i18n.h transcode.h debug.h +getdevices.32.o: getdevices.c globals.h string.h ../config.h http-private.h http.h +getdevices.32.o: getdevices.c versioning.h md5.h ipp-private.h ipp.h cups.h ppd.h array.h +getdevices.32.o: getdevices.c file.h language.h i18n.h transcode.h debug.h getifaddrs.32.o: getifaddrs.c http-private.h ../config.h http.h versioning.h md5.h getifaddrs.32.o: getifaddrs.c ipp-private.h ipp.h getputfile.32.o: getputfile.c globals.h string.h ../config.h http-private.h http.h @@ -143,7 +155,7 @@ getputfile.32.o: getputfile.c versioning.h md5.h ipp-private.h ipp.h cups.h ppd getputfile.32.o: getputfile.c file.h language.h i18n.h transcode.h debug.h globals.32.o: globals.c http-private.h ../config.h http.h versioning.h md5.h ipp-private.h globals.32.o: globals.c ipp.h globals.h string.h cups.h ppd.h array.h file.h language.h -globals.32.o: globals.c i18n.h transcode.h debug.h +globals.32.o: globals.c i18n.h transcode.h http.32.o: http.c http-private.h ../config.h http.h versioning.h md5.h ipp-private.h http.32.o: http.c ipp.h globals.h string.h cups.h ppd.h array.h file.h language.h http.32.o: http.c i18n.h transcode.h debug.h @@ -191,7 +203,7 @@ request.32.o: request.c i18n.h transcode.h debug.h sidechannel.32.o: sidechannel.c sidechannel.h versioning.h string.h ../config.h snmp.32.o: snmp.c globals.h string.h ../config.h http-private.h http.h versioning.h snmp.32.o: snmp.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h -snmp.32.o: snmp.c i18n.h transcode.h snmp.h +snmp.32.o: snmp.c i18n.h transcode.h snmp-private.h snprintf.32.o: snprintf.c string.h ../config.h string.32.o: string.c array.h versioning.h debug.h string.h ../config.h tempfile.32.o: tempfile.c globals.h string.h ../config.h http-private.h http.h versioning.h @@ -221,7 +233,7 @@ testlang.32.o: testlang.c i18n.h transcode.h language.h array.h versioning.h st testlang.32.o: testlang.c ../config.h testppd.32.o: testppd.c ../cups/string.h ../config.h string.h ppd.h array.h versioning.h testppd.32.o: testppd.c file.h -testsnmp.32.o: testsnmp.c string.h ../config.h snmp.h http.h versioning.h +testsnmp.32.o: testsnmp.c string.h ../config.h snmp-private.h http.h versioning.h # DO NOT DELETE adminutil.64.o: adminutil.c adminutil.h cups.h ipp.h http.h versioning.h ppd.h array.h @@ -238,6 +250,9 @@ backend.64.o: backend.c backend.h versioning.h string.h ../config.h custom.64.o: custom.c globals.h string.h ../config.h http-private.h http.h versioning.h custom.64.o: custom.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h custom.64.o: custom.c i18n.h transcode.h debug.h +debug.64.o: debug.c globals.h string.h ../config.h http-private.h http.h versioning.h +debug.64.o: debug.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h +debug.64.o: debug.c i18n.h transcode.h debug.h dest.64.o: dest.c debug.h globals.h string.h ../config.h http-private.h http.h dest.64.o: dest.c versioning.h md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h dest.64.o: dest.c language.h i18n.h transcode.h @@ -248,6 +263,9 @@ encode.64.o: encode.c ipp-private.h string.h ../config.h debug.h file.64.o: file.c http-private.h ../config.h http.h versioning.h md5.h ipp-private.h file.64.o: file.c ipp.h globals.h string.h cups.h ppd.h array.h file.h language.h file.64.o: file.c i18n.h transcode.h debug.h +getdevices.64.o: getdevices.c globals.h string.h ../config.h http-private.h http.h +getdevices.64.o: getdevices.c versioning.h md5.h ipp-private.h ipp.h cups.h ppd.h array.h +getdevices.64.o: getdevices.c file.h language.h i18n.h transcode.h debug.h getifaddrs.64.o: getifaddrs.c http-private.h ../config.h http.h versioning.h md5.h getifaddrs.64.o: getifaddrs.c ipp-private.h ipp.h getputfile.64.o: getputfile.c globals.h string.h ../config.h http-private.h http.h @@ -255,7 +273,7 @@ getputfile.64.o: getputfile.c versioning.h md5.h ipp-private.h ipp.h cups.h ppd getputfile.64.o: getputfile.c file.h language.h i18n.h transcode.h debug.h globals.64.o: globals.c http-private.h ../config.h http.h versioning.h md5.h ipp-private.h globals.64.o: globals.c ipp.h globals.h string.h cups.h ppd.h array.h file.h language.h -globals.64.o: globals.c i18n.h transcode.h debug.h +globals.64.o: globals.c i18n.h transcode.h http.64.o: http.c http-private.h ../config.h http.h versioning.h md5.h ipp-private.h http.64.o: http.c ipp.h globals.h string.h cups.h ppd.h array.h file.h language.h http.64.o: http.c i18n.h transcode.h debug.h @@ -303,7 +321,7 @@ request.64.o: request.c i18n.h transcode.h debug.h sidechannel.64.o: sidechannel.c sidechannel.h versioning.h string.h ../config.h snmp.64.o: snmp.c globals.h string.h ../config.h http-private.h http.h versioning.h snmp.64.o: snmp.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h -snmp.64.o: snmp.c i18n.h transcode.h snmp.h +snmp.64.o: snmp.c i18n.h transcode.h snmp-private.h snprintf.64.o: snprintf.c string.h ../config.h string.64.o: string.c array.h versioning.h debug.h string.h ../config.h tempfile.64.o: tempfile.c globals.h string.h ../config.h http-private.h http.h versioning.h @@ -333,4 +351,4 @@ testlang.64.o: testlang.c i18n.h transcode.h language.h array.h versioning.h st testlang.64.o: testlang.c ../config.h testppd.64.o: testppd.c ../cups/string.h ../config.h string.h ppd.h array.h versioning.h testppd.64.o: testppd.c file.h -testsnmp.64.o: testsnmp.c string.h ../config.h snmp.h http.h versioning.h +testsnmp.64.o: testsnmp.c string.h ../config.h snmp-private.h http.h versioning.h diff --git a/cups/Makefile b/cups/Makefile index 3ea420681..95a3769f8 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -100,7 +100,6 @@ HEADERS = \ ppd.h \ raster.h \ sidechannel.h \ - snmp.h \ transcode.h \ versioning.h @@ -508,7 +507,7 @@ apihelp: --css ../doc/cups-printable.css \ --header api-filter.header --intro api-filter.shtml \ backchannel.c backend.h backend.c sidechannel.c sidechannel.h \ - snmp.c snmp.h >../doc/help/api-filter.html + >../doc/help/api-filter.html framedhelp: echo Generating CUPS API help files... @@ -552,8 +551,7 @@ framedhelp: --title "Filter and Backend Programming" \ --css ../doc/cups-printable.css \ --header api-filter.header --intro api-filter.shtml \ - backchannel.c backend.h backend.c sidechannel.c sidechannel.h \ - snmp.c snmp.h + backchannel.c backend.h backend.c sidechannel.c sidechannel.h # diff --git a/cups/api-filter.shtml b/cups/api-filter.shtml index f5b6b8cf2..60f28d32f 100644 --- a/cups/api-filter.shtml +++ b/cups/api-filter.shtml @@ -343,6 +343,9 @@ if (!cupsSideChannelRead(&command, &s

Doing SNMP Queries with Network Printers

+

Re-write for side-channel-based SNMP queries.

+ + \ No newline at end of file diff --git a/cups/libcups.exp b/cups/libcups.exp index 4a689e384..bb12c552a 100644 --- a/cups/libcups.exp +++ b/cups/libcups.exp @@ -22,6 +22,16 @@ __cupsMessageLoad __cupsMessageLookup __cupsSetError __cupsSetLocale +__cupsSNMPClose +__cupsSNMPCopyOID +__cupsSNMPDefaultCommunity +__cupsSNMPIsOID +__cupsSNMPIsOIDPrefixed +__cupsSNMPOpen +__cupsSNMPRead +__cupsSNMPSetDebug +__cupsSNMPWalk +__cupsSNMPWrite __cupsStrAlloc __cupsStrFlush __cupsStrFormatd @@ -154,16 +164,6 @@ _cupsPutFile _cupsReadResponseData _cupsRemoveDest _cupsRemoveOption -_cupsSNMPClose -_cupsSNMPCopyOID -_cupsSNMPDefaultCommunity -_cupsSNMPIsOID -_cupsSNMPIsOIDPrefixed -_cupsSNMPOpen -_cupsSNMPRead -_cupsSNMPSetDebug -_cupsSNMPWalk -_cupsSNMPWrite _cupsSendRequest _cupsServer _cupsSetDefaultDest diff --git a/cups/libcups_s.exp b/cups/libcups_s.exp index 261f2ab86..a556cdb89 100644 --- a/cups/libcups_s.exp +++ b/cups/libcups_s.exp @@ -17,6 +17,16 @@ _cupsMessageLoad _cupsMessageLookup _cupsSetError _cupsSetLocale +_cupsSNMPClose +_cupsSNMPCopyOID +_cupsSNMPDefaultCommunity +_cupsSNMPIsOID +_cupsSNMPIsOIDPrefixed +_cupsSNMPOpen +_cupsSNMPRead +_cupsSNMPSetDebug +_cupsSNMPWalk +_cupsSNMPWrite _cupsStrAlloc _cupsStrFlush _cupsStrFormatd diff --git a/cups/snmp-private.h b/cups/snmp-private.h new file mode 100644 index 000000000..364913eb0 --- /dev/null +++ b/cups/snmp-private.h @@ -0,0 +1,292 @@ +/* + * "$Id$" + * + * SNMP definitions for the Common UNIX Printing System (CUPS). + * + * This API is PRIVATE and subject to change. No third-party applications + * should use the SNMP API defined in this file. + * + * Copyright 2007-2008 by Apple Inc. + * Copyright 2006-2007 by Easy Software Products, all rights reserved. + * + * 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" + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_SNMP_H_ +# define _CUPS_SNMP_H_ + + +/* + * Include necessary headers. + */ + +#include "http.h" + + +/* + * Constants... + */ + +#define CUPS_SNMP_PORT 161 /* SNMP well-known port */ +#define CUPS_SNMP_MAX_OID 128 /* Maximum number of OID numbers */ +#define CUPS_SNMP_MAX_PACKET 1472 /* Maximum size of SNMP packet */ +#define CUPS_SNMP_MAX_STRING 512 /* Maximum size of string */ +#define CUPS_SNMP_VERSION_1 0 /* SNMPv1 */ + + +/* + * Types... + */ + +enum cups_asn1_e /**** ASN1 request/object types ****/ +{ + CUPS_ASN1_END_OF_CONTENTS = 0x00, /* End-of-contents */ + CUPS_ASN1_BOOLEAN = 0x01, /* BOOLEAN */ + CUPS_ASN1_INTEGER = 0x02, /* INTEGER or ENUMERATION */ + CUPS_ASN1_BIT_STRING = 0x03, /* BIT STRING */ + CUPS_ASN1_OCTET_STRING = 0x04, /* OCTET STRING */ + CUPS_ASN1_NULL_VALUE = 0x05, /* NULL VALUE */ + CUPS_ASN1_OID = 0x06, /* OBJECT IDENTIFIER */ + CUPS_ASN1_SEQUENCE = 0x30, /* SEQUENCE */ + CUPS_ASN1_HEX_STRING = 0x40, /* Binary string aka Hex-STRING */ + CUPS_ASN1_COUNTER = 0x41, /* 32-bit unsigned aka Counter32 */ + CUPS_ASN1_GAUGE = 0x42, /* 32-bit unsigned aka Gauge32 */ + CUPS_ASN1_TIMETICKS = 0x43, /* 32-bit unsigned aka Timeticks32 */ + CUPS_ASN1_GET_REQUEST = 0xa0, /* GetRequest-PDU */ + CUPS_ASN1_GET_NEXT_REQUEST = 0xa1, /* GetNextRequest-PDU */ + CUPS_ASN1_GET_RESPONSE = 0xa2 /* GetResponse-PDU */ +}; +typedef enum cups_asn1_e cups_asn1_t; /**** ASN1 request/object types ****/ + +struct cups_snmp_hexstring_s /**** Hex-STRING value ****/ +{ + unsigned char bytes[CUPS_SNMP_MAX_STRING]; + /* Bytes in string */ + int num_bytes; /* Number of bytes */ +}; + +union cups_snmp_value_u /**** Object value ****/ +{ + int boolean; /* Boolean value */ + int integer; /* Integer value */ + unsigned counter; /* Counter value */ + unsigned gauge; /* Gauge value */ + unsigned timeticks; /* Timeticks value */ + int oid[CUPS_SNMP_MAX_OID]; /* OID value */ + char string[CUPS_SNMP_MAX_STRING]; + /* String value */ + struct cups_snmp_hexstring_s hex_string; + /* Hex string value */ +}; + +typedef struct cups_snmp_s /**** SNMP data packet ****/ +{ + const char *error; /* Encode/decode error */ + http_addr_t address; /* Source address */ + int version; /* Version number */ + char community[CUPS_SNMP_MAX_STRING]; + /* Community name */ + cups_asn1_t request_type; /* Request type */ + int request_id; /* request-id value */ + int error_status; /* error-status value */ + int error_index; /* error-index value */ + int object_name[CUPS_SNMP_MAX_OID]; + /* object-name value */ + cups_asn1_t object_type; /* object-value type */ + union cups_snmp_value_u + object_value; /* object-value value */ +} cups_snmp_t; + +typedef void (*cups_snmp_cb_t)(cups_snmp_t *packet, void *data); + +/* + * Prototypes... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + +extern void _cupsSNMPClose(int fd) _CUPS_API_1_4; +extern int *_cupsSNMPCopyOID(int *dst, const int *src, int dstsize) + _CUPS_API_1_4; +extern const char *_cupsSNMPDefaultCommunity(void) _CUPS_API_1_4; +extern int _cupsSNMPIsOID(cups_snmp_t *packet, const int *oid) + _CUPS_API_1_4; +extern int _cupsSNMPIsOIDPrefixed(cups_snmp_t *packet, + const int *prefix) _CUPS_API_1_4; +extern int _cupsSNMPOpen(int family) _CUPS_API_1_4; +extern cups_snmp_t *_cupsSNMPRead(int fd, cups_snmp_t *packet, + double timeout) _CUPS_API_1_4; +extern void _cupsSNMPSetDebug(int level) _CUPS_API_1_4; +extern int _cupsSNMPWalk(int fd, http_addr_t *address, int version, + const char *community, const int *prefix, + double timeout, cups_snmp_cb_t cb, + void *data) _CUPS_API_1_4; +extern int _cupsSNMPWrite(int fd, http_addr_t *address, int version, + const char *community, + cups_asn1_t request_type, + const unsigned request_id, + const int *oid) _CUPS_API_1_4; + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_SNMP_H_ */ + + +/* + * End of "$Id$". + */ +/* + * "$Id$" + * + * SNMP definitions for the Common UNIX Printing System (CUPS). + * + * This API is PRIVATE and subject to change. No third-party applications + * should use the SNMP API defined in this file. + * + * Copyright 2007-2008 by Apple Inc. + * Copyright 2006-2007 by Easy Software Products, all rights reserved. + * + * 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" + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_SNMP_H_ +# define _CUPS_SNMP_H_ + + +/* + * Include necessary headers. + */ + +#include "http.h" + + +/* + * Constants... + */ + +#define CUPS_SNMP_PORT 161 /* SNMP well-known port */ +#define CUPS_SNMP_MAX_OID 128 /* Maximum number of OID numbers */ +#define CUPS_SNMP_MAX_PACKET 1472 /* Maximum size of SNMP packet */ +#define CUPS_SNMP_MAX_STRING 512 /* Maximum size of string */ +#define CUPS_SNMP_VERSION_1 0 /* SNMPv1 */ + + +/* + * Types... + */ + +enum cups_asn1_e /**** ASN1 request/object types ****/ +{ + CUPS_ASN1_END_OF_CONTENTS = 0x00, /* End-of-contents */ + CUPS_ASN1_BOOLEAN = 0x01, /* BOOLEAN */ + CUPS_ASN1_INTEGER = 0x02, /* INTEGER or ENUMERATION */ + CUPS_ASN1_BIT_STRING = 0x03, /* BIT STRING */ + CUPS_ASN1_OCTET_STRING = 0x04, /* OCTET STRING */ + CUPS_ASN1_NULL_VALUE = 0x05, /* NULL VALUE */ + CUPS_ASN1_OID = 0x06, /* OBJECT IDENTIFIER */ + CUPS_ASN1_SEQUENCE = 0x30, /* SEQUENCE */ + CUPS_ASN1_HEX_STRING = 0x40, /* Binary string aka Hex-STRING */ + CUPS_ASN1_COUNTER = 0x41, /* 32-bit unsigned aka Counter32 */ + CUPS_ASN1_GAUGE = 0x42, /* 32-bit unsigned aka Gauge32 */ + CUPS_ASN1_TIMETICKS = 0x43, /* 32-bit unsigned aka Timeticks32 */ + CUPS_ASN1_GET_REQUEST = 0xa0, /* GetRequest-PDU */ + CUPS_ASN1_GET_NEXT_REQUEST = 0xa1, /* GetNextRequest-PDU */ + CUPS_ASN1_GET_RESPONSE = 0xa2 /* GetResponse-PDU */ +}; +typedef enum cups_asn1_e cups_asn1_t; /**** ASN1 request/object types ****/ + +struct cups_snmp_hexstring_s /**** Hex-STRING value ****/ +{ + unsigned char bytes[CUPS_SNMP_MAX_STRING]; + /* Bytes in string */ + int num_bytes; /* Number of bytes */ +}; + +union cups_snmp_value_u /**** Object value ****/ +{ + int boolean; /* Boolean value */ + int integer; /* Integer value */ + unsigned counter; /* Counter value */ + unsigned gauge; /* Gauge value */ + unsigned timeticks; /* Timeticks value */ + int oid[CUPS_SNMP_MAX_OID]; /* OID value */ + char string[CUPS_SNMP_MAX_STRING]; + /* String value */ + struct cups_snmp_hexstring_s hex_string; + /* Hex string value */ +}; + +typedef struct cups_snmp_s /**** SNMP data packet ****/ +{ + const char *error; /* Encode/decode error */ + http_addr_t address; /* Source address */ + int version; /* Version number */ + char community[CUPS_SNMP_MAX_STRING]; + /* Community name */ + cups_asn1_t request_type; /* Request type */ + int request_id; /* request-id value */ + int error_status; /* error-status value */ + int error_index; /* error-index value */ + int object_name[CUPS_SNMP_MAX_OID]; + /* object-name value */ + cups_asn1_t object_type; /* object-value type */ + union cups_snmp_value_u + object_value; /* object-value value */ +} cups_snmp_t; + +typedef void (*cups_snmp_cb_t)(cups_snmp_t *packet, void *data); + +/* + * Prototypes... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + +extern void _cupsSNMPClose(int fd) _CUPS_API_1_4; +extern int *_cupsSNMPCopyOID(int *dst, const int *src, int dstsize) + _CUPS_API_1_4; +extern const char *_cupsSNMPDefaultCommunity(void) _CUPS_API_1_4; +extern int _cupsSNMPIsOID(cups_snmp_t *packet, const int *oid) + _CUPS_API_1_4; +extern int _cupsSNMPIsOIDPrefixed(cups_snmp_t *packet, + const int *prefix) _CUPS_API_1_4; +extern int _cupsSNMPOpen(int family) _CUPS_API_1_4; +extern cups_snmp_t *_cupsSNMPRead(int fd, cups_snmp_t *packet, + double timeout) _CUPS_API_1_4; +extern void _cupsSNMPSetDebug(int level) _CUPS_API_1_4; +extern int _cupsSNMPWalk(int fd, http_addr_t *address, int version, + const char *community, const int *prefix, + double timeout, cups_snmp_cb_t cb, + void *data) _CUPS_API_1_4; +extern int _cupsSNMPWrite(int fd, http_addr_t *address, int version, + const char *community, + cups_asn1_t request_type, + const unsigned request_id, + const int *oid) _CUPS_API_1_4; + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_SNMP_H_ */ + + +/* + * End of "$Id$". + */ diff --git a/cups/snmp.c b/cups/snmp.c index 054b633e1..2fbaf5781 100644 --- a/cups/snmp.c +++ b/cups/snmp.c @@ -16,40 +16,40 @@ * * Contents: * - * cupsSNMPClose() - Close a SNMP socket. - * cupsSNMPCopyOID() - Copy an OID. - * cupsSNMPDefaultCommunity() - Get the default SNMP community name. - * cupsSNMPIsOID() - Test whether a SNMP response contains the - * specified OID. - * cupsSNMPIsOIDPrefixed() - Test whether a SNMP response uses the - * specified OID prefix. - * cupsSNMPOpen() - Open a SNMP socket. - * cupsSNMPRead() - Read and parse a SNMP response. - * cupsSNMPSetDebug() - Enable/disable debug logging to stderr. - * cupsSNMPWalk() - Enumerate a group of OIDs. - * cupsSNMPWrite() - Send an SNMP query packet. - * asn1_debug() - Decode an ASN1-encoded message. - * asn1_decode_snmp() - Decode a SNMP packet. - * asn1_encode_snmp() - Encode a SNMP packet. - * asn1_get_integer() - Get an integer value. - * asn1_get_length() - Get a value length. - * asn1_get_oid() - Get an OID value. - * asn1_get_packed() - Get a packed integer value. - * asn1_get_string() - Get a string value. - * asn1_get_type() - Get a value type. - * asn1_set_integer() - Set an integer value. - * asn1_set_length() - Set a value length. - * asn1_set_oid() - Set an OID value. - * asn1_set_packed() - Set a packed integer value. - * asn1_size_integer() - Figure out the number of bytes needed for an - * integer value. - * asn1_size_length() - Figure out the number of bytes needed for a - * length value. - * asn1_size_oid() - Figure out the numebr of bytes needed for an - * OID value. - * asn1_size_packed() - Figure out the number of bytes needed for a - * packed integer value. - * snmp_set_error() - Set the localized error for a packet. + * _cupsSNMPClose() - Close a SNMP socket. + * _cupsSNMPCopyOID() - Copy an OID. + * _cupsSNMPDefaultCommunity() - Get the default SNMP community name. + * _cupsSNMPIsOID() - Test whether a SNMP response contains the + * specified OID. + * _cupsSNMPIsOIDPrefixed() - Test whether a SNMP response uses the + * specified OID prefix. + * _cupsSNMPOpen() - Open a SNMP socket. + * _cupsSNMPRead() - Read and parse a SNMP response. + * _cupsSNMPSetDebug() - Enable/disable debug logging to stderr. + * _cupsSNMPWalk() - Enumerate a group of OIDs. + * _cupsSNMPWrite() - Send an SNMP query packet. + * asn1_debug() - Decode an ASN1-encoded message. + * asn1_decode_snmp() - Decode a SNMP packet. + * asn1_encode_snmp() - Encode a SNMP packet. + * asn1_get_integer() - Get an integer value. + * asn1_get_length() - Get a value length. + * asn1_get_oid() - Get an OID value. + * asn1_get_packed() - Get a packed integer value. + * asn1_get_string() - Get a string value. + * asn1_get_type() - Get a value type. + * asn1_set_integer() - Set an integer value. + * asn1_set_length() - Set a value length. + * asn1_set_oid() - Set an OID value. + * asn1_set_packed() - Set a packed integer value. + * asn1_size_integer() - Figure out the number of bytes needed for an + * integer value. + * asn1_size_length() - Figure out the number of bytes needed for a + * length value. + * asn1_size_oid() - Figure out the numebr of bytes needed for an + * OID value. + * asn1_size_packed() - Figure out the number of bytes needed for a + * packed integer value. + * snmp_set_error() - Set the localized error for a packet. */ /* @@ -57,7 +57,7 @@ */ #include "globals.h" -#include "snmp.h" +#include "snmp-private.h" #include #ifdef HAVE_POLL # include @@ -107,13 +107,13 @@ static void snmp_set_error(cups_snmp_t *packet, /* - * 'cupsSNMPClose()' - Close a SNMP socket. + * '_cupsSNMPClose()' - Close a SNMP socket. * * @since CUPS 1.4@ */ void -cupsSNMPClose(int fd) /* I - SNMP socket file descriptor */ +_cupsSNMPClose(int fd) /* I - SNMP socket file descriptor */ { #ifdef WIN32 closesocket(fd); @@ -124,7 +124,7 @@ cupsSNMPClose(int fd) /* I - SNMP socket file descriptor */ /* - * 'cupsSNMPCopyOID()' - Copy an OID. + * '_cupsSNMPCopyOID()' - Copy an OID. * * The array pointed to by "src" is terminated by the value -1. * @@ -132,9 +132,9 @@ cupsSNMPClose(int fd) /* I - SNMP socket file descriptor */ */ int * /* O - New OID */ -cupsSNMPCopyOID(int *dst, /* I - Destination OID */ - const int *src, /* I - Source OID */ - int dstsize) /* I - Number of integers in dst */ +_cupsSNMPCopyOID(int *dst, /* I - Destination OID */ + const int *src, /* I - Source OID */ + int dstsize) /* I - Number of integers in dst */ { int i; /* Looping var */ @@ -149,7 +149,7 @@ cupsSNMPCopyOID(int *dst, /* I - Destination OID */ /* - * 'cupsSNMPDefaultCommunity()' - Get the default SNMP community name. + * '_cupsSNMPDefaultCommunity()' - Get the default SNMP community name. * * The default community name is the first community name found in the * snmp.conf file. If no community name is defined there, "public" is used. @@ -158,7 +158,7 @@ cupsSNMPCopyOID(int *dst, /* I - Destination OID */ */ const char * /* O - Default community name */ -cupsSNMPDefaultCommunity(void) +_cupsSNMPDefaultCommunity(void) { cups_file_t *fp; /* snmp.conf file */ char line[1024], /* Line from file */ @@ -191,7 +191,7 @@ cupsSNMPDefaultCommunity(void) /* - * 'cupsSNMPIsOID()' - Test whether a SNMP response contains the specified OID. + * '_cupsSNMPIsOID()' - Test whether a SNMP response contains the specified OID. * * The array pointed to by "oid" is terminated by the value -1. * @@ -199,8 +199,8 @@ cupsSNMPDefaultCommunity(void) */ int /* O - 1 if equal, 0 if not equal */ -cupsSNMPIsOID(cups_snmp_t *packet, /* I - Response packet */ - const int *oid) /* I - OID */ +_cupsSNMPIsOID(cups_snmp_t *packet, /* I - Response packet */ + const int *oid) /* I - OID */ { int i; /* Looping var */ @@ -227,8 +227,8 @@ cupsSNMPIsOID(cups_snmp_t *packet, /* I - Response packet */ /* - * 'cupsSNMPIsOIDPrefixed()' - Test whether a SNMP response uses the specified - * OID prefix. + * '_cupsSNMPIsOIDPrefixed()' - Test whether a SNMP response uses the specified + * OID prefix. * * The array pointed to by "prefix" is terminated by the value -1. * @@ -236,7 +236,7 @@ cupsSNMPIsOID(cups_snmp_t *packet, /* I - Response packet */ */ int /* O - 1 if prefixed, 0 if not prefixed */ -cupsSNMPIsOIDPrefixed( +_cupsSNMPIsOIDPrefixed( cups_snmp_t *packet, /* I - Response packet */ const int *prefix) /* I - OID prefix */ { @@ -265,13 +265,13 @@ cupsSNMPIsOIDPrefixed( /* - * 'cupsSNMPOpen()' - Open a SNMP socket. + * '_cupsSNMPOpen()' - Open a SNMP socket. * * @since CUPS 1.4@ */ int /* O - SNMP socket file descriptor */ -cupsSNMPOpen(int family) /* I - Address family - @code AF_INET@ or @code AF_INET6@ */ +_cupsSNMPOpen(int family) /* I - Address family - @code AF_INET@ or @code AF_INET6@ */ { int fd; /* SNMP socket file descriptor */ int val; /* Socket option value */ @@ -302,16 +302,16 @@ cupsSNMPOpen(int family) /* I - Address family - @code AF_INET@ or @code AF_INE /* - * 'cupsSNMPRead()' - Read and parse a SNMP response. + * '_cupsSNMPRead()' - Read and parse a SNMP response. * - * If "timeout" is negative, @code cupsSNMPRead@ will wait for a response + * If "timeout" is negative, @code _cupsSNMPRead@ will wait for a response * indefinitely. * * @since CUPS 1.4@ */ cups_snmp_t * /* O - SNMP packet or @code NULL@ if none */ -cupsSNMPRead(int fd, /* I - SNMP socket file descriptor */ +_cupsSNMPRead(int fd, /* I - SNMP socket file descriptor */ cups_snmp_t *packet, /* I - SNMP packet buffer */ double timeout) /* I - Timeout in seconds */ { @@ -403,13 +403,13 @@ cupsSNMPRead(int fd, /* I - SNMP socket file descriptor */ /* - * 'cupsSNMPSetDebug()' - Enable/disable debug logging to stderr. + * '_cupsSNMPSetDebug()' - Enable/disable debug logging to stderr. * * @since CUPS 1.4@ */ void -cupsSNMPSetDebug(int level) /* I - 1 to enable debug output, 0 otherwise */ +_cupsSNMPSetDebug(int level) /* I - 1 to enable debug output, 0 otherwise */ { _cups_globals_t *cg = _cupsGlobals(); /* Global data */ @@ -419,28 +419,28 @@ cupsSNMPSetDebug(int level) /* I - 1 to enable debug output, 0 otherwise */ /* - * 'cupsSNMPWalk()' - Enumerate a group of OIDs. + * '_cupsSNMPWalk()' - Enumerate a group of OIDs. * * This function queries all of the OIDs with the specified OID prefix, * calling the "cb" function for every response that is received. * * The array pointed to by "prefix" is terminated by the value -1. * - * If "timeout" is negative, @code cupsSNMPWalk@ will wait for a response + * If "timeout" is negative, @code _cupsSNMPWalk@ will wait for a response * indefinitely. * * @since CUPS 1.4@ */ int /* O - Number of OIDs found or -1 on error */ -cupsSNMPWalk(int fd, /* I - SNMP socket */ - http_addr_t *address, /* I - Address to query */ - int version, /* I - SNMP version */ - const char *community, /* I - Community name */ - const int *prefix, /* I - OID prefix */ - double timeout, /* I - Timeout for each response in seconds */ - cups_snmp_cb_t cb, /* I - Function to call for each response */ - void *data) /* I - User data pointer that is passed to the callback function */ +_cupsSNMPWalk(int fd, /* I - SNMP socket */ + http_addr_t *address, /* I - Address to query */ + int version, /* I - SNMP version */ + const char *community,/* I - Community name */ + const int *prefix, /* I - OID prefix */ + double timeout, /* I - Timeout for each response in seconds */ + cups_snmp_cb_t cb, /* I - Function to call for each response */ + void *data) /* I - User data pointer that is passed to the callback function */ { int count = 0; /* Number of OIDs found */ int request_id = 0; /* Current request ID */ @@ -459,21 +459,21 @@ cupsSNMPWalk(int fd, /* I - SNMP socket */ * Copy the OID prefix and then loop until we have no more OIDs... */ - cupsSNMPCopyOID(packet.object_name, prefix, CUPS_SNMP_MAX_OID); + _cupsSNMPCopyOID(packet.object_name, prefix, CUPS_SNMP_MAX_OID); for (;;) { request_id ++; - if (!cupsSNMPWrite(fd, address, version, community, + if (!_cupsSNMPWrite(fd, address, version, community, CUPS_ASN1_GET_NEXT_REQUEST, request_id, packet.object_name)) return (-1); - if (!cupsSNMPRead(fd, &packet, timeout)) + if (!_cupsSNMPRead(fd, &packet, timeout)) return (-1); - if (!cupsSNMPIsOIDPrefixed(&packet, prefix)) + if (!_cupsSNMPIsOIDPrefixed(&packet, prefix)) return (count); if (packet.error || packet.error_status) @@ -487,7 +487,7 @@ cupsSNMPWalk(int fd, /* I - SNMP socket */ /* - * 'cupsSNMPWrite()' - Send an SNMP query packet. + * '_cupsSNMPWrite()' - Send an SNMP query packet. * * The array pointed to by "oid" is terminated by the value -1. * @@ -495,7 +495,7 @@ cupsSNMPWalk(int fd, /* I - SNMP socket */ */ int /* O - 1 on success, 0 on error */ -cupsSNMPWrite( +_cupsSNMPWrite( int fd, /* I - SNMP socket */ http_addr_t *address, /* I - Address to send to */ int version, /* I - SNMP version */ diff --git a/cups/snmp.h b/cups/snmp.h deleted file mode 100644 index 8e5dfa56d..000000000 --- a/cups/snmp.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * "$Id$" - * - * SNMP definitions for the Common UNIX Printing System (CUPS). - * - * Copyright 2007-2008 by Apple Inc. - * Copyright 2006-2007 by Easy Software Products, all rights reserved. - * - * 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" - * "LICENSE" which should have been included with this file. If this - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * This file is subject to the Apple OS-Developed Software exception. - */ - -#ifndef _CUPS_SNMP_H_ -# define _CUPS_SNMP_H_ - - -/* - * Include necessary headers. - */ - -#include "http.h" - - -/* - * Constants... - */ - -#define CUPS_SNMP_PORT 161 /* SNMP well-known port */ -#define CUPS_SNMP_MAX_OID 128 /* Maximum number of OID numbers */ -#define CUPS_SNMP_MAX_PACKET 1472 /* Maximum size of SNMP packet */ -#define CUPS_SNMP_MAX_STRING 512 /* Maximum size of string */ -#define CUPS_SNMP_VERSION_1 0 /* SNMPv1 */ - - -/* - * Types... - */ - -enum cups_asn1_e /**** ASN1 request/object types ****/ -{ - CUPS_ASN1_END_OF_CONTENTS = 0x00, /* End-of-contents */ - CUPS_ASN1_BOOLEAN = 0x01, /* BOOLEAN */ - CUPS_ASN1_INTEGER = 0x02, /* INTEGER or ENUMERATION */ - CUPS_ASN1_BIT_STRING = 0x03, /* BIT STRING */ - CUPS_ASN1_OCTET_STRING = 0x04, /* OCTET STRING */ - CUPS_ASN1_NULL_VALUE = 0x05, /* NULL VALUE */ - CUPS_ASN1_OID = 0x06, /* OBJECT IDENTIFIER */ - CUPS_ASN1_SEQUENCE = 0x30, /* SEQUENCE */ - CUPS_ASN1_HEX_STRING = 0x40, /* Binary string aka Hex-STRING */ - CUPS_ASN1_COUNTER = 0x41, /* 32-bit unsigned aka Counter32 */ - CUPS_ASN1_GAUGE = 0x42, /* 32-bit unsigned aka Gauge32 */ - CUPS_ASN1_TIMETICKS = 0x43, /* 32-bit unsigned aka Timeticks32 */ - CUPS_ASN1_GET_REQUEST = 0xa0, /* GetRequest-PDU */ - CUPS_ASN1_GET_NEXT_REQUEST = 0xa1, /* GetNextRequest-PDU */ - CUPS_ASN1_GET_RESPONSE = 0xa2 /* GetResponse-PDU */ -}; -typedef enum cups_asn1_e cups_asn1_t; /**** ASN1 request/object types ****/ - -struct cups_snmp_hexstring_s /**** Hex-STRING value ****/ -{ - unsigned char bytes[CUPS_SNMP_MAX_STRING]; - /* Bytes in string */ - int num_bytes; /* Number of bytes */ -}; - -union cups_snmp_value_u /**** Object value ****/ -{ - int boolean; /* Boolean value */ - int integer; /* Integer value */ - unsigned counter; /* Counter value */ - unsigned gauge; /* Gauge value */ - unsigned timeticks; /* Timeticks value */ - int oid[CUPS_SNMP_MAX_OID]; /* OID value */ - char string[CUPS_SNMP_MAX_STRING]; - /* String value */ - struct cups_snmp_hexstring_s hex_string; - /* Hex string value */ -}; - -typedef struct cups_snmp_s /**** SNMP data packet ****/ -{ - const char *error; /* Encode/decode error */ - http_addr_t address; /* Source address */ - int version; /* Version number */ - char community[CUPS_SNMP_MAX_STRING]; - /* Community name */ - cups_asn1_t request_type; /* Request type */ - int request_id; /* request-id value */ - int error_status; /* error-status value */ - int error_index; /* error-index value */ - int object_name[CUPS_SNMP_MAX_OID]; - /* object-name value */ - cups_asn1_t object_type; /* object-value type */ - union cups_snmp_value_u - object_value; /* object-value value */ -} cups_snmp_t; - -typedef void (*cups_snmp_cb_t)(cups_snmp_t *packet, void *data); - -/* - * Prototypes... - */ - -# ifdef __cplusplus -extern "C" { -# endif /* __cplusplus */ - -extern void cupsSNMPClose(int fd) _CUPS_API_1_4; -extern int *cupsSNMPCopyOID(int *dst, const int *src, int dstsize) - _CUPS_API_1_4; -extern const char *cupsSNMPDefaultCommunity(void) _CUPS_API_1_4; -extern int cupsSNMPIsOID(cups_snmp_t *packet, const int *oid) - _CUPS_API_1_4; -extern int cupsSNMPIsOIDPrefixed(cups_snmp_t *packet, - const int *prefix) _CUPS_API_1_4; -extern int cupsSNMPOpen(int family) _CUPS_API_1_4; -extern cups_snmp_t *cupsSNMPRead(int fd, cups_snmp_t *packet, - double timeout) _CUPS_API_1_4; -extern void cupsSNMPSetDebug(int level) _CUPS_API_1_4; -extern int cupsSNMPWalk(int fd, http_addr_t *address, int version, - const char *community, const int *prefix, - double timeout, cups_snmp_cb_t cb, - void *data) _CUPS_API_1_4; -extern int cupsSNMPWrite(int fd, http_addr_t *address, int version, - const char *community, - cups_asn1_t request_type, - const unsigned request_id, - const int *oid) _CUPS_API_1_4; - -# ifdef __cplusplus -} -# endif /* __cplusplus */ -#endif /* !_CUPS_SNMP_H_ */ - - -/* - * End of "$Id$". - */ diff --git a/cups/testfile.c b/cups/testfile.c index 4f0f39e10..d8a1b88c9 100644 --- a/cups/testfile.c +++ b/cups/testfile.c @@ -17,6 +17,7 @@ * Contents: * * main() - Main entry. + * random_tests() - Do random access tests. * read_write_tests() - Perform read/write tests. */ @@ -34,6 +35,7 @@ #ifdef HAVE_LIBZ # include #endif /* HAVE_LIBZ */ +#include #include diff --git a/cups/testsnmp.c b/cups/testsnmp.c index eb47254a1..2e0ef0d3d 100644 --- a/cups/testsnmp.c +++ b/cups/testsnmp.c @@ -29,7 +29,7 @@ #include #include #include "string.h" -#include "snmp.h" +#include "snmp-private.h" /* @@ -59,9 +59,9 @@ main(int argc, /* I - Number of command-line args */ const char *community; /* Community name */ - fputs("cupsSNMPDefaultCommunity: ", stdout); + fputs("_cupsSNMPDefaultCommunity: ", stdout); - if ((community = cupsSNMPDefaultCommunity()) == NULL) + if ((community = _cupsSNMPDefaultCommunity()) == NULL) { puts("FAIL (NULL community name)"); return (1); @@ -84,7 +84,7 @@ main(int argc, /* I - Number of command-line args */ community = argv[i]; } else if (!strcmp(argv[i], "-d")) - cupsSNMPSetDebug(10); + _cupsSNMPSetDebug(10); else if (!strcmp(argv[i], "-w")) walk = 1; else if (!host) @@ -97,9 +97,9 @@ main(int argc, /* I - Number of command-line args */ if (fd < 0) { - fputs("cupsSNMPOpen: ", stdout); + fputs("_cupsSNMPOpen: ", stdout); - if ((fd = cupsSNMPOpen(host->addr.addr.sa_family)) < 0) + if ((fd = _cupsSNMPOpen(host->addr.addr.sa_family)) < 0) { printf("FAIL (%s)\n", strerror(errno)); return (1); @@ -263,12 +263,12 @@ show_oid(int fd, /* I - SNMP socket */ if (walk) { - printf("cupsSNMPWalk(%d", oid[0]); + printf("_cupsSNMPWalk(%d", oid[0]); for (i = 1; oid[i] >= 0; i ++) printf(".%d", oid[i]); puts("):"); - if (cupsSNMPWalk(fd, addr, CUPS_SNMP_VERSION_1, community, oid, 5.0, + if (_cupsSNMPWalk(fd, addr, CUPS_SNMP_VERSION_1, community, oid, 5.0, print_packet, NULL) < 0) { printf("FAIL (%s)\n", strerror(errno)); @@ -277,12 +277,12 @@ show_oid(int fd, /* I - SNMP socket */ } else { - printf("cupsSNMPWrite(%d", oid[0]); + printf("_cupsSNMPWrite(%d", oid[0]); for (i = 1; oid[i] >= 0; i ++) printf(".%d", oid[i]); fputs("): ", stdout); - if (!cupsSNMPWrite(fd, addr, CUPS_SNMP_VERSION_1, community, + if (!_cupsSNMPWrite(fd, addr, CUPS_SNMP_VERSION_1, community, CUPS_ASN1_GET_REQUEST, 1, oid)) { printf("FAIL (%s)\n", strerror(errno)); @@ -291,15 +291,15 @@ show_oid(int fd, /* I - SNMP socket */ puts("PASS"); - fputs("cupsSNMPRead(5.0): ", stdout); + fputs("_cupsSNMPRead(5.0): ", stdout); - if (!cupsSNMPRead(fd, &packet, 5.0)) + if (!_cupsSNMPRead(fd, &packet, 5.0)) { puts("FAIL (timeout)"); return (0); } - if (!cupsSNMPIsOID(&packet, oid)) + if (!_cupsSNMPIsOID(&packet, oid)) { printf("FAIL (bad OID %d", packet.object_name[0]); for (i = 1; packet.object_name[i] >= 0; i ++) diff --git a/doc/cups.css b/doc/cups.css index 77fefb044..faaef123a 100644 --- a/doc/cups.css +++ b/doc/cups.css @@ -1,6 +1,6 @@ BODY { - background: #e8e8e8; - color: #000000; + background: white; + color: black; font-family: lucida grande, geneva, helvetica, arial, sans-serif; } @@ -47,8 +47,8 @@ P.formula { } BLOCKQUOTE { - background: #e1e1e1; - border: inset 1px #dddddd; + background: #f0f0f0; + border: inset 1px #eeeeee; padding: 10px; /* These are not implemented by all browsers, but that's OK */ border-radius: 5px; @@ -60,7 +60,7 @@ A IMG { } A:link:hover IMG { - background: #e0e0e0; + background: #f0f0f0; border-radius: 10px; -moz-border-radius: 10px; } @@ -108,7 +108,7 @@ TD.unsel { } TD.sel A, TD.sel A:hover { - color: #ffffff; + color: white; font-weight: normal; text-decoration: none; } @@ -120,18 +120,18 @@ TD.unsel A, TD.unsel A:visited { TD.unsel:hover { background: url(images/unsel-hover.gif); - color: #ffffff; + color: white; } TD.unsel A:link:hover, TD.unsel A:visited:hover, TD.unsel A:active { - color: #ffffff; + color: white; font-weight: normal; text-decoration: none; } TD.trailer { - background: #e1e1e1; - border: solid thin #cccccc; + background: #f0f0f0; + border: solid thin #e0e0e0; color: #666666; font-size: 80%; padding: 5px; @@ -195,7 +195,7 @@ DIV.table TABLE TD { } DIV.table TABLE TH { - background: #eeeeee; + background: #f0f0f0; border: none; border-bottom: solid thin #999999; } @@ -225,9 +225,9 @@ HR { } SPAN.info { - background: #000000; - border: thin solid #000000; - color: #ffffff; + background: black; + border: thin solid black; + color: white; font-size: 80%; font-style: italic; font-weight: bold; @@ -279,8 +279,8 @@ DIV.sidebar P.l2 { } TABLE.inset { - background: #e1e1e1; - border: inset 1px #dddddd; + background: #f0f0f0; + border: inset 1px #eeeeee; padding: 0; /* These are not implemented by all browsers, but that's OK */ border-radius: 5px; @@ -335,7 +335,7 @@ DIV.summary TABLE TD, DIV.summary TABLE TH { } DIV.summary TABLE THEAD TH { - background: #eeeeee; + background: #f0f0f0; } /* API documentation styles... */ diff --git a/doc/help/api-filedir.html b/doc/help/api-filedir.html index ff5b2e1a9..cf466c39c 100644 --- a/doc/help/api-filedir.html +++ b/doc/help/api-filedir.html @@ -634,8 +634,9 @@ int cupsFileNumber (
existing file, "a" to append to an existing file or create a new file, or "s" to open a socket connection.

-When opening for writing ("w") or appending ("a"), an optional number from -1 to 9 can be supplied which enables Flate compression of the file.
+When opening for writing ("w"), an optional number from 1 to 9 can be +supplied which enables Flate compression of the file. Compression is +not supported for the "a" (append) mode.

When opening a socket connection, the filename is a string of the form "address:port" or "hostname:port". The socket will make an IPv4 or IPv6 @@ -660,11 +661,12 @@ a choice.

Return Value

CUPS file or NULL if the file could not be opened

Discussion

-

The "mode" parameter can be "r" to read, "a" or "w" to write, or "s" -to treat the file descriptor as a bidirectional socket connection.
+

The "mode" parameter can be "r" to read, "w" to write, "a" to append, +or "s" to treat the file descriptor as a bidirectional socket connection.

-When opening for writing ("w") or appending ("a"), an optional number from -1 to 9 can be supplied which enables Flate compression of the file. +When opening for writing ("w"), an optional number from 1 to 9 can be +supplied which enables Flate compression of the file. Compression is +not supported for the "a" (append) mode.

 CUPS 1.2 cupsFilePeekChar

diff --git a/doc/help/api-filter.html b/doc/help/api-filter.html index ed24e8c6e..5febe8a86 100644 --- a/doc/help/api-filter.html +++ b/doc/help/api-filter.html @@ -309,40 +309,18 @@ div.contents ul.subcontents li {
  • cupsBackChannelRead
  • cupsBackChannelWrite
  • cupsBackendDeviceURI
  • -
  • cupsSNMPClose
  • -
  • cupsSNMPCopyOID
  • -
  • cupsSNMPDefaultCommunity
  • -
  • cupsSNMPIsOID
  • -
  • cupsSNMPIsOIDPrefixed
  • -
  • cupsSNMPOpen
  • -
  • cupsSNMPRead
  • -
  • cupsSNMPSetDebug
  • -
  • cupsSNMPWalk
  • -
  • cupsSNMPWrite
  • cupsSideChannelDoRequest
  • cupsSideChannelRead
  • cupsSideChannelWrite
  • Data Types
  • -
  • Structures
  • -
  • Unions
  • Constants
      -
    • cups_asn1_e
    • cups_backend_e
    • cups_sc_bidi_e
    • cups_sc_command_e
    • @@ -695,6 +673,9 @@ if (!cupsSideChannelRead(&command, &s

      Doing SNMP Queries with Network Printers

      +

      Re-write for side-channel-based SNMP queries.

      + +

      Functions

       CUPS 1.2 cupsBackChannelRead

      Read data from the backchannel.

      @@ -838,219 +819,6 @@ const char *cupsBackendDeviceURI (
      function returns the device URI passed in the DEVICE_URI environment variable or the device URI passed in argv[0], whichever is found first.

      -

       CUPS 1.4 cupsSNMPClose

      -

      Close a SNMP socket.

      -

      -void cupsSNMPClose (
      -    int fd
      -);

      -

      Parameters

      -
      -
      fd
      -
      SNMP socket file descriptor
      -
      -

       CUPS 1.4 cupsSNMPCopyOID

      -

      Copy an OID.

      -

      -int *cupsSNMPCopyOID (
      -    int *dst,
      -    const int *src,
      -    int dstsize
      -);

      -

      Parameters

      -
      -
      dst
      -
      Destination OID
      -
      src
      -
      Source OID
      -
      dstsize
      -
      Number of integers in dst
      -
      -

      Return Value

      -

      New OID

      -

      Discussion

      -

      The array pointed to by "src" is terminated by the value -1. - -

      -

       CUPS 1.4 cupsSNMPDefaultCommunity

      -

      Get the default SNMP community name.

      -

      -const char *cupsSNMPDefaultCommunity (void);

      -

      Return Value

      -

      Default community name

      -

      Discussion

      -

      The default community name is the first community name found in the -snmp.conf file. If no community name is defined there, "public" is used. - -

      -

       CUPS 1.4 cupsSNMPIsOID

      -

      Test whether a SNMP response contains the specified OID.

      -

      -int cupsSNMPIsOID (
      -    cups_snmp_t *packet,
      -    const int *oid
      -);

      -

      Parameters

      -
      -
      packet
      -
      Response packet
      -
      oid
      -
      OID
      -
      -

      Return Value

      -

      1 if equal, 0 if not equal

      -

      Discussion

      -

      The array pointed to by "oid" is terminated by the value -1. - -

      -

       CUPS 1.4 cupsSNMPIsOIDPrefixed

      -

      Test whether a SNMP response uses the specified -OID prefix.

      -

      -int cupsSNMPIsOIDPrefixed (
      -    cups_snmp_t *packet,
      -    const int *prefix
      -);

      -

      Parameters

      -
      -
      packet
      -
      Response packet
      -
      prefix
      -
      OID prefix
      -
      -

      Return Value

      -

      1 if prefixed, 0 if not prefixed

      -

      Discussion

      -

      The array pointed to by "prefix" is terminated by the value -1. - -

      -

       CUPS 1.4 cupsSNMPOpen

      -

      Open a SNMP socket.

      -

      -int cupsSNMPOpen (
      -    int family
      -);

      -

      Parameters

      -
      -
      family
      -
      Address family - AF_INET or AF_INET6
      -
      -

      Return Value

      -

      SNMP socket file descriptor

      -

       CUPS 1.4 cupsSNMPRead

      -

      Read and parse a SNMP response.

      -

      -cups_snmp_t *cupsSNMPRead (
      -    int fd,
      -    cups_snmp_t *packet,
      -    double timeout
      -);

      -

      Parameters

      -
      -
      fd
      -
      SNMP socket file descriptor
      -
      packet
      -
      SNMP packet buffer
      -
      timeout
      -
      Timeout in seconds
      -
      -

      Return Value

      -

      SNMP packet or NULL if none

      -

      Discussion

      -

      If "timeout" is negative, cupsSNMPRead will wait for a response -indefinitely. - -

      -

       CUPS 1.4 cupsSNMPSetDebug

      -

      Enable/disable debug logging to stderr.

      -

      -void cupsSNMPSetDebug (
      -    int level
      -);

      -

      Parameters

      -
      -
      level
      -
      1 to enable debug output, 0 otherwise
      -
      -

       CUPS 1.4 cupsSNMPWalk

      -

      Enumerate a group of OIDs.

      -

      -int cupsSNMPWalk (
      -    int fd,
      -    http_addr_t *address,
      -    int version,
      -    const char *community,
      -    const int *prefix,
      -    double timeout,
      -    cups_snmp_cb_t cb,
      -    void *data
      -);

      -

      Parameters

      -
      -
      fd
      -
      SNMP socket
      -
      address
      -
      Address to query
      -
      version
      -
      SNMP version
      -
      community
      -
      Community name
      -
      prefix
      -
      OID prefix
      -
      timeout
      -
      Timeout for each response in seconds
      -
      cb
      -
      Function to call for each response
      -
      data
      -
      User data pointer that is passed to the callback function
      -
      -

      Return Value

      -

      Number of OIDs found or -1 on error

      -

      Discussion

      -

      This function queries all of the OIDs with the specified OID prefix, -calling the "cb" function for every response that is received.
      -
      -The array pointed to by "prefix" is terminated by the value -1.
      -
      -If "timeout" is negative, cupsSNMPWalk will wait for a response -indefinitely. - -

      -

       CUPS 1.4 cupsSNMPWrite

      -

      Send an SNMP query packet.

      -

      -int cupsSNMPWrite (
      -    int fd,
      -    http_addr_t *address,
      -    int version,
      -    const char *community,
      -    cups_asn1_t request_type,
      -    const unsigned request_id,
      -    const int *oid
      -);

      -

      Parameters

      -
      -
      fd
      -
      SNMP socket
      -
      address
      -
      Address to send to
      -
      version
      -
      SNMP version
      -
      community
      -
      Community name
      -
      request_type
      -
      Request type
      -
      request_id
      -
      Request ID
      -
      oid
      -
      OID
      -
      -

      Return Value

      -

      1 on success, 0 on error

      -

      Discussion

      -

      The array pointed to by "oid" is terminated by the value -1. - -

       CUPS 1.3 cupsSideChannelDoRequest

      Send a side-channel command to a backend and wait for a response.

      @@ -1152,11 +920,6 @@ responses to a filter, driver, or port monitor program.

      Data Types

      -

      cups_asn1_t

      -

      ASN1 request/object types

      -

      -typedef enum cups_asn1_e cups_asn1_t; -

      cups_backend_t

      Backend exit codes

      @@ -1182,138 +945,7 @@ typedef enum cups_sc_state_e cups_sc_state_t;

      typedef enum cups_sc_status_e cups_sc_status_t;

      -

      cups_snmp_cb_t

      -

      Prototypes...

      -

      -typedef void (*cups_snmp_cb_t)(cups_snmp_t *packet, void *data); -

      -

      cups_snmp_t

      -

      SNMP data packet

      -

      -typedef struct cups_snmp_s cups_snmp_t; -

      -

      Structures

      -

      cups_snmp_hexstring_s

      -

      Hex-STRING value

      -

      struct cups_snmp_hexstring_s {
      -    unsigned char bytes[CUPS_SNMP_MAX_STRING];
      -    int num_bytes;
      -};

      -

      Members

      -
      -
      bytes[CUPS_SNMP_MAX_STRING]
      -
      Bytes in string
      -
      num_bytes
      -
      Number of bytes
      -
      -

      cups_snmp_s

      -

      SNMP data packet

      -

      struct cups_snmp_s {
      -    http_addr_t address;
      -    char community[CUPS_SNMP_MAX_STRING];
      -    const char *error;
      -    int error_index;
      -    int error_status;
      -    int object_name[CUPS_SNMP_MAX_OID];
      -    cups_asn1_t object_type;
      -    union cups_snmp_value_u object_value;
      -    int request_id;
      -    cups_asn1_t request_type;
      -    int version;
      -};

      -

      Members

      -
      -
      address
      -
      Source address
      -
      community[CUPS_SNMP_MAX_STRING]
      -
      Community name
      -
      error
      -
      Encode/decode error
      -
      error_index
      -
      error-index value
      -
      error_status
      -
      error-status value
      -
      object_name[CUPS_SNMP_MAX_OID]
      -
      object-name value
      -
      object_type
      -
      object-value type
      -
      object_value
      -
      object-value value
      -
      request_id
      -
      request-id value
      -
      request_type
      -
      Request type
      -
      version
      -
      Version number
      -
      -

      Unions

      -

      cups_snmp_value_u

      -

      Object value

      -

      union cups_snmp_value_u {
      -    int boolean;
      -    unsigned counter;
      -    unsigned gauge;
      -    struct cups_snmp_hexstring_s hex_string;
      -    int integer;
      -    int oid[CUPS_SNMP_MAX_OID];
      -    char string[CUPS_SNMP_MAX_STRING];
      -    unsigned timeticks;
      -};

      -

      Members

      -
      -
      boolean
      -
      Boolean value
      -
      counter
      -
      Counter value
      -
      gauge
      -
      Gauge value
      -
      hex_string
      -
      Hex string value
      -
      integer
      -
      Integer value
      -
      oid[CUPS_SNMP_MAX_OID]
      -
      OID value
      -
      string[CUPS_SNMP_MAX_STRING]
      -
      String value
      -
      timeticks
      -
      Timeticks value
      -

      Constants

      -

      cups_asn1_e

      -

      ASN1 request/object types

      -

      Constants

      -
      -
      CUPS_ASN1_BIT_STRING
      -
      BIT STRING
      -
      CUPS_ASN1_BOOLEAN
      -
      BOOLEAN
      -
      CUPS_ASN1_COUNTER
      -
      32-bit unsigned aka Counter32
      -
      CUPS_ASN1_END_OF_CONTENTS
      -
      End-of-contents
      -
      CUPS_ASN1_GAUGE
      -
      32-bit unsigned aka Gauge32
      -
      CUPS_ASN1_GET_NEXT_REQUEST
      -
      GetNextRequest-PDU
      -
      CUPS_ASN1_GET_REQUEST
      -
      GetRequest-PDU
      -
      CUPS_ASN1_GET_RESPONSE
      -
      GetResponse-PDU
      -
      CUPS_ASN1_HEX_STRING
      -
      Binary string aka Hex-STRING
      -
      CUPS_ASN1_INTEGER
      -
      INTEGER or ENUMERATION
      -
      CUPS_ASN1_NULL_VALUE
      -
      NULL VALUE
      -
      CUPS_ASN1_OCTET_STRING
      -
      OCTET STRING
      -
      CUPS_ASN1_OID
      -
      OBJECT IDENTIFIER
      -
      CUPS_ASN1_SEQUENCE
      -
      SEQUENCE
      -
      CUPS_ASN1_TIMETICKS
      -
      32-bit unsigned aka Timeticks32
      -

      cups_backend_e

      Backend exit codes

      Constants

      diff --git a/filter/Makefile b/filter/Makefile index 6bd1f556e..09df33085 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -18,7 +18,7 @@ include ../Makedefs -FILTERS = gziptoany hpgltops texttops pstops $(IMGFILTERS) \ +FILTERS = commandtops gziptoany hpgltops texttops pstops $(IMGFILTERS) \ $(PDFTOPS) rastertolabel rastertoepson rastertohp TARGETS = $(FILTERS) \ $(LIBCUPSIMAGE) \ @@ -39,7 +39,7 @@ IMAGE32OBJS = $(IMAGEOBJS:.o=.32.o) IMAGE64OBJS = $(IMAGEOBJS:.o=.64.o) FORMOBJS = form-attr.o form-main.o form-ps.o form-text.o form-tree.o OBJS = $(HPGLOBJS) $(IMAGEOBJS) $(FORMOBJS) \ - gziptoany.o imagetops.o imagetoraster.o common.o \ + commandtops.o gziptoany.o imagetops.o imagetoraster.o common.o \ pdftops.o pstops.o \ rasterbench.o rastertoepson.o rastertohp.o rastertolabel.o \ testimage.o testraster.o textcommon.o texttops.o @@ -205,6 +205,15 @@ framedhelp: ../cups/raster.h interpret.c raster.c +# +# commandtops +# + +commandtops: commandtops.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ commandtops.o $(LIBS) + + # # formtops # diff --git a/filter/commandtops.c b/filter/commandtops.c new file mode 100644 index 000000000..ea7caf10d --- /dev/null +++ b/filter/commandtops.c @@ -0,0 +1,329 @@ +/* + * "$Id$" + * + * PostScript command filter for CUPS. + * + * Copyright 2008 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/". + * + * + * Contents: + * + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + + +/* + * Local functions... + */ + +static void auto_configure(ppd_file_t *ppd, const char *user); +static void print_self_test_page(ppd_file_t *ppd, const char *user); +static void report_levels(ppd_file_t *ppd, const char *user); + + +/* + * 'main()' - Process a CUPS command file. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + cups_file_t *fp; /* Command file */ + char line[1024], /* Line from file */ + *value; /* Value on line */ + int linenum; /* Line number in file */ + ppd_file_t *ppd; /* PPD file */ + + + /* + * Check for valid arguments... + */ + + if (argc < 6 || argc > 7) + { + /* + * We don't have the correct number of arguments; write an error message + * and return. + */ + + fputs("ERROR: commandtops job-id user title copies options [file]\n", stderr); + return (1); + } + + /* + * Open the PPD file... + */ + + if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL) + { + fputs("ERROR: Unable to open PPD file!\n", stderr); + return (1); + } + + /* + * Open the command file as needed... + */ + + if (argc == 7) + { + if ((fp = cupsFileOpen(argv[6], "r")) == NULL) + { + perror("ERROR: Unable to open command file - "); + return (1); + } + } + else + fp = cupsFileStdin(); + + /* + * Read the commands from the file and send the appropriate commands... + */ + + linenum = 0; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + /* + * Parse the command... + */ + + if (!strcasecmp(line, "AutoConfigure")) + auto_configure(ppd, argv[2]); + else if (!strcasecmp(line, "PrintSelfTestPage")) + print_self_test_page(ppd, argv[2]); + else if (!strcasecmp(line, "ReportLevels")) + report_levels(ppd, argv[2]); + else + fprintf(stderr, "ERROR: Invalid printer command \"%s\"!\n", line); + } + + return (0); +} + + +/* + * 'auto_configure()' - Automatically configure the printer using PostScript + * query commands and/or SNMP lookups. + */ + +static void +auto_configure(ppd_file_t *ppd, /* I - PPD file */ + const char *user) /* I - Printing user */ +{ + ppd_option_t *option; /* Current option in PPD */ + ppd_attr_t *attr; /* Query command attribute */ + char buffer[1024], /* String buffer */ + *bufptr; /* Pointer into buffer */ + ssize_t bytes; /* Number of bytes read */ + int datalen; /* Side-channel data length */ + + + /* + * See if the backend supports bidirectional I/O... + */ + + datalen = 1; + if (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, buffer, &datalen, + 30.0) != CUPS_SC_STATUS_OK || + buffer[0] != CUPS_SC_BIDI_SUPPORTED) + { + fputs("DEBUG: Unable to auto-configure PostScript Printer - no " + "bidirectional I/O available!\n", stderr); + return; + } + + /* + * Put the printer in PostScript mode... + */ + + if (ppd->jcl_begin) + { + fputs(ppd->jcl_begin, stdout); + fputs(ppd->jcl_ps, stdout); + } + + puts("%!"); + fflush(stdout); + + /* + * Then loop through every option in the PPD file and ask for the current + * value... + */ + + fputs("DEBUG: Auto-configuring PostScript printer...\n", stderr); + + for (option = ppdFirstOption(ppd); option; option = ppdNextOption(ppd)) + { + /* + * See if we have a query command for this option... + */ + + snprintf(buffer, sizeof(buffer), "?%s", option->keyword); + + if ((attr = ppdFindAttr(ppd, buffer, NULL)) == NULL || !attr->value) + { + fprintf(stderr, "DEBUG: Skipping %s option...\n", option->keyword); + continue; + } + + /* + * Send the query code to the printer... + */ + + fprintf(stderr, "DEBUG: Querying %s...\n", option->keyword); + fputs(attr->value, stdout); + fflush(stdout); + + datalen = 0; + cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer, &datalen, 5.0); + + /* + * Read the response data... + */ + + while ((bytes = cupsBackChannelRead(buffer, sizeof(buffer) - 1, 5.0)) > 0) + { + /* + * Trim whitespace from both ends... + */ + + buffer[bytes] = '\0'; + + for (bufptr = buffer + bytes - 1; bufptr >= buffer; bufptr --) + if (isspace(*bufptr & 255)) + *bufptr = '\0'; + else + break; + + for (bufptr = buffer; isspace(*bufptr & 255); bufptr ++); + + /* + * Skip blank lines... + */ + + if (!*bufptr) + continue; + + /* + * Write out the result and move on to the next option... + */ + + fprintf(stderr, "DEBUG: Default%s=%s\n", option->keyword, bufptr); + fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, bufptr); + break; + } + } + + /* + * Finish the job... + */ + + if (ppd->jcl_begin) + fputs(ppd->jcl_begin, stdout); + else + putchar(0x04); + + fflush(stdout); +} + + +/* + * 'print_self_test_page()' - Print a self-test page. + */ + +static void +print_self_test_page(ppd_file_t *ppd, /* I - PPD file */ + const char *user) /* I - Printing user */ +{ + /* + * Put the printer in PostScript mode... + */ + + if (ppd->jcl_begin) + { + fputs(ppd->jcl_begin, stdout); + fputs(ppd->jcl_ps, stdout); + } + + puts("%!"); + + /* + * Send a simple file the draws a box around the imageable area and shows + * the product/interpreter information... + */ + + puts("% You are using the wrong driver for your printer!\n" + "0 setgray\n" + "2 setlinewidth\n" + "initclip newpath clippath gsave stroke grestore pathbbox\n" + "exch pop exch pop exch 9 add exch 9 sub moveto\n" + "/Courier findfont 12 scalefont setfont\n" + "0 -12 rmoveto gsave product show grestore\n" + "0 -12 rmoveto gsave version show ( ) show revision 20 string cvs show " + "grestore\n" + "0 -12 rmoveto gsave serialnumber 20 string cvs show grestore\n" + "showpage"); + + /* + * Finish the job... + */ + + if (ppd->jcl_begin) + fputs(ppd->jcl_begin, stdout); + else + putchar(0x04); + + fflush(stdout); +} + + +/* + * 'report_levels()' - Report supply levels. + */ + +static void +report_levels(ppd_file_t *ppd, /* I - PPD file */ + const char *user) /* I - Printing user */ +{ + /* + * Put the printer in PostScript mode... + */ + + if (ppd->jcl_begin) + { + fputs(ppd->jcl_begin, stdout); + fputs(ppd->jcl_ps, stdout); + } + + puts("%!"); + + /* + * Finish the job... + */ + + if (ppd->jcl_begin) + fputs(ppd->jcl_begin, stdout); + else + putchar(0x04); + + fflush(stdout); +} + + +/* + * End of "$Id$". + */ diff --git a/packaging/cups.list.in b/packaging/cups.list.in index 56ca4a937..ac535a2c7 100644 --- a/packaging/cups.list.in +++ b/packaging/cups.list.in @@ -148,6 +148,7 @@ $LIB32DIR=@LIB32DIR@ $LIB64DIR=@LIB64DIR@ $IMGFILTERS=@IMGFILTERS@ +$MDNS=@MDNS@ $PDFTOPS=@PDFTOPS@ $CUPS_USER=@CUPS_USER@ @@ -188,6 +189,9 @@ d 0755 root sys $SERVERBIN/backend - f 0700 root sys $SERVERBIN/backend/ipp backend/ipp l 0700 root sys $SERVERBIN/backend/http ipp f 0700 root sys $SERVERBIN/backend/lpd backend/lpd +%if MDNS +f 0700 root sys $SERVERBIN/backend/mdns backend/mdns +%endif %system !darwin f 0755 root sys $SERVERBIN/backend/parallel backend/parallel f 0755 root sys $SERVERBIN/backend/scsi backend/scsi @@ -211,6 +215,7 @@ f 0755 root sys $SERVERBIN/driver/drv ppdc/drv d 0755 root sys $SERVERBIN/filter - f 0755 root sys $SERVERBIN/filter/commandtoespcx driver/commandtoescpx f 0755 root sys $SERVERBIN/filter/commandtopclx driver/commandtopclx +f 0755 root sys $SERVERBIN/filter/commandtops filter/commandtops f 0755 root sys $SERVERBIN/filter/gziptoany filter/gziptoany f 0755 root sys $SERVERBIN/filter/hpgltops filter/hpgltops %if IMGFILTERS diff --git a/packaging/cups.spec.in b/packaging/cups.spec.in index 401de885a..8deff15b5 100644 --- a/packaging/cups.spec.in +++ b/packaging/cups.spec.in @@ -94,74 +94,6 @@ UNIX The Common UNIX Printing System provides a portable printing layer for UNIX® operating systems. This package provides LPD client support. -%description da -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Danish support. - -%description de -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides German support. - -%description es -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Spanish support. - -%description et -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Estonian support. - -%description fi -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Finnish support. - -%description fr -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides French support. - -%description he -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Hebrew support. - -%description it -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Italian support. - -%description ja -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Japanese support. - -%description ko -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Korean support. - -%description nl -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Dutch support. - -%description no -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Norwegian support. - -%description pl -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Polish support. - -%description pt -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Portuguese support. - -%description ru -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Russian support. - -%description sv -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Swedish support. - -%description zh -The Common UNIX Printing System provides a portable printing layer for -UNIX® operating systems. This package provides Chinese support. - %if %{?_with_php:1}%{!?_with_php:0} %description php The Common UNIX Printing System provides a portable printing layer for diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c index 5bc61f680..8af4571e8 100644 --- a/scheduler/dirsvc.c +++ b/scheduler/dirsvc.c @@ -14,52 +14,6 @@ * * Contents: * - * cupsdDeregisterPrinter() - Stop sending broadcast information for a local - * printer and remove any pending references to - * remote printers. - * cupsdLoadRemoteCache() - Load the remote printer cache. - * cupsdRegisterPrinter() - Start sending broadcast information for a - * printer or update the broadcast contents. - * cupsdRestartPolling() - Restart polling servers as needed. - * cupsdSaveRemoteCache() - Save the remote printer cache. - * cupsdSendBrowseList() - Send new browsing information as necessary. - * cupsdStartBrowsing() - Start sending and receiving broadcast - * information. - * cupsdStartPolling() - Start polling servers as needed. - * cupsdStopBrowsing() - Stop sending and receiving broadcast - * information. - * cupsdStopPolling() - Stop polling servers as needed. - * cupsdUpdateDNSSDBrowse() - Handle DNS-SD queries. - * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP... - * cupsdUpdateSLPBrowse() - Get browsing information via SLP. - * dequote() - Remote quotes from a string. - * get_hostconfig() - Get an /etc/hostconfig service setting. - * is_local_queue() - Determine whether the URI points at a local - * queue. - * process_browse_data() - Process new browse data. - * dnssdBuildTxtRecord() - Build a TXT record from printer info. - * dnssdDeregisterPrinter() - Stop sending broadcast information for a - * printer. - * dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT - * record format. - * dnssdRegisterCallback() - DNSServiceRegister callback. - * dnssdRegisterPrinter() - Start sending broadcast information for a - * printer or update the broadcast contents. - * process_implicit_classes() - Create/update implicit classes as needed. - * send_cups_browse() - Send new browsing information using the CUPS - * protocol. - * send_ldap_browse() - Send LDAP printer registrations. - * send_slp_browse() - Register the specified printer with SLP. - * slp_attr_callback() - SLP attribute callback - * slp_dereg_printer() - SLPDereg() the specified printer - * slp_get_attr() - Get an attribute from an SLP registration. - * slp_reg_callback() - Empty SLPRegReport. - * slp_url_callback() - SLP service url callback - * update_cups_browse() - Update the browse lists using the CUPS - * protocol. - * update_lpd() - Update the LPD configuration as needed. - * update_polling() - Read status messages from the poll daemons. - * update_smb() - Update the SMB configuration as needed. */ /* @@ -112,6 +66,21 @@ static void update_polling(void); static void update_smb(int onoff); +#ifdef HAVE_DNSSD +static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p, + int for_lpd); +static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b); +static void dnssdDeregisterPrinter(cupsd_printer_t *p); +static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2], + int count); +static void dnssdRegisterCallback(DNSServiceRef sdRef, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + const char *name, const char *regtype, + const char *domain, void *context); +static void dnssdRegisterPrinter(cupsd_printer_t *p); +#endif /* HAVE_DNSSD */ + #ifdef HAVE_OPENLDAP static const char * const ldap_attrs[] =/* CUPS LDAP attributes */ { @@ -165,26 +134,6 @@ static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl, SLPError errcode, void *cookie); #endif /* HAVE_LIBSLP */ -#ifdef HAVE_DNSSD -/* - * For IPP register using a subtype of 'cups' so that shared printer browsing - * only finds other CUPS servers (not all IPP based printers). - */ -static char dnssdIPPRegType[] = "_ipp._tcp,_cups"; -static char dnssdIPPFaxRegType[] = "_fax-ipp._tcp"; - -static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p); -static void dnssdDeregisterPrinter(cupsd_printer_t *p); -static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2], - int count); -static void dnssdRegisterCallback(DNSServiceRef sdRef, - DNSServiceFlags flags, - DNSServiceErrorType errorCode, - const char *name, const char *regtype, - const char *domain, void *context); -static void dnssdRegisterPrinter(cupsd_printer_t *p); -#endif /* HAVE_DNSSD */ - /* * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a @@ -198,7 +147,7 @@ cupsdDeregisterPrinter( int removeit) /* I - Printer being permanently removed */ { /* - * Only deregister if browsing is enabled and it's a local printers... + * Only deregister if browsing is enabled and it's a local printer... */ if (!Browsing || !p->shared || @@ -226,7 +175,7 @@ cupsdDeregisterPrinter( #endif /* HAVE_LIBSLP */ #ifdef HAVE_DNSSD - if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD)) + if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDPort) dnssdDeregisterPrinter(p); #endif /* HAVE_DNSSD */ } @@ -256,10 +205,10 @@ cupsdLoadRemoteCache(void) /* - * Don't load the cache if the CUPS remote protocol is disabled... + * Don't load the cache if the remote protocols are disabled... */ - if (!Browsing || !(BrowseRemoteProtocols & BROWSE_CUPS)) + if (!Browsing) { cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdLoadRemoteCache: Not loading remote cache."); @@ -628,7 +577,7 @@ cupsdLoadRemoteCache(void) void cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ { - if (!Browsing || !BrowseLocalProtocols || !BrowseInterval || !NumBrowsers || + if (!Browsing || !BrowseLocalProtocols || (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))) return; @@ -638,7 +587,7 @@ cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ #endif /* HAVE_LIBSLP */ #ifdef HAVE_DNSSD - if (BrowseLocalProtocols & BROWSE_DNSSD) + if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDPort) dnssdRegisterPrinter(p); #endif /* HAVE_DNSSD */ } @@ -923,7 +872,7 @@ cupsdSendBrowseList(void) cupsArraySave(Printers); cupsdDeletePrinter(p, 1); cupsArrayRestore(Printers); - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); } } } @@ -1038,6 +987,74 @@ cupsdStartBrowsing(void) else BrowseSocket = -1; +#ifdef HAVE_DNSSD + if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD) + { + DNSServiceErrorType error; /* Error from service creation */ + cupsd_listener_t *lis; /* Current listening socket */ + + + /* + * First create a "master" connection for all registrations... + */ + + if ((error = DNSServiceCreateConnection(&DNSSDRef)) + != kDNSServiceErr_NoError) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create master DNS-SD reference: %d", error); + else + { + /* + * Add the master connection to the select list... + */ + + cupsdAddSelect(DNSServiceRefSockFD(DNSSDRef), + (cupsd_selfunc_t)cupsdUpdateDNSSDBrowse, NULL, NULL); + + /* + * Then get the port we use for registrations. If we are not listening + * on any non-local ports, there is no sense sharing local printers via + * Bonjour... + */ + + DNSSDPort = 0; + + for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); + lis; + lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) + { + if (httpAddrLocalhost(&(lis->address))) + continue; + + if (lis->address.addr.sa_family == AF_INET) + { + DNSSDPort = ntohs(lis->address.ipv4.sin_port); + break; + } + else if (lis->address.addr.sa_family == AF_INET6) + { + DNSSDPort = ntohs(lis->address.ipv6.sin6_port); + break; + } + } + + /* + * Create an array to track the printers we share... + */ + + if (BrowseRemoteProtocols & BROWSE_DNSSD) + DNSSDPrinters = cupsArrayNew((cups_array_func_t)dnssdComparePrinters, + NULL); + + /* + * Set the computer name and register the web interface... + */ + + cupsdUpdateDNSSDName(); + } + } +#endif /* HAVE_DNSSD */ + #ifdef HAVE_LIBSLP if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) { @@ -1319,6 +1336,31 @@ cupsdStopBrowsing(void) BrowseSocket = -1; } +#ifdef HAVE_DNSSD + if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef) + { + if (WebIFRef) + { + DNSServiceRefDeallocate(WebIFRef); + WebIFRef = NULL; + } + + if (RemoteRef) + { + DNSServiceRefDeallocate(RemoteRef); + RemoteRef = NULL; + } + + cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef)); + + DNSServiceRefDeallocate(DNSSDRef); + DNSSDRef = NULL; + + cupsArrayDelete(DNSSDPrinters); + DNSSDPrinters = NULL; + } +#endif /* HAVE_DNSSD */ + #ifdef HAVE_LIBSLP if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) && BrowseSLPHandle) @@ -1387,24 +1429,84 @@ cupsdStopPolling(void) */ void -cupsdUpdateDNSSDBrowse( - cupsd_printer_t *p) /* I - Printer being queried */ +cupsdUpdateDNSSDBrowse(void) { DNSServiceErrorType sdErr; /* Service discovery error */ - if ((sdErr = DNSServiceProcessResult(p->dnssd_ipp_ref)) - != kDNSServiceErr_NoError) - { + if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError) cupsdLogMessage(CUPSD_LOG_ERROR, - "DNS Service Discovery registration error %d for \"%s\"!", - sdErr, p->name); - cupsdRemoveSelect(p->dnssd_ipp_fd); - DNSServiceRefDeallocate(p->dnssd_ipp_ref); + "DNS Service Discovery registration error %d!", + sdErr); +} + + +/* + * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing... + */ + +void +cupsdUpdateDNSSDName(void) +{ + DNSServiceErrorType error; /* Error from service creation */ + char webif[1024]; /* Web interface share name */ +#ifdef HAVE_COREFOUNDATION_H + CFStringRef nameRef; /* Computer name CFString */ + char nameBuffer[1024]; /* C-string buffer */ + CFStringEncoding nameEncoding; /* Computer name encoding */ +#endif /* HAVE_COREFOUNDATION_H */ + + + /* + * Only share the web interface and printers when non-local listening is + * enabled... + */ + + if (!DNSSDPort) + return; + + /* + * Get the computer name as a c-string... + */ + +#ifdef HAVE_COREFOUNDATION_H + cupsdClearString(&DNSSDName); + + if ((nameRef = SCDynamicStoreCopyComputerName(NULL, + &nameEncoding)) != NULL) + { + if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer), + kCFStringEncodingUTF8)) + cupsdSetString(&DNSSDName, nameBuffer); - p->dnssd_ipp_ref = NULL; - p->dnssd_ipp_fd = -1; + CFRelease(nameRef); } + +#else + cupsdSetString(&DNSSDName, ServerName); +#endif /* HAVE_COREFOUNDATION_H */ + + /* + * Then (re)register the web interface... + */ + + if (DNSSDName) + snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDName); + else + strlcpy(webif, "CUPS Web Interface", sizeof(webif)); + + if (WebIFRef) + DNSServiceRefDeallocate(WebIFRef); + + WebIFRef = DNSSDRef; + if ((error = DNSServiceRegister(&WebIFRef, + kDNSServiceFlagsShareConnection, + 0, webif, "_http._tcp", NULL, + NULL, htons(DNSSDPort), 7, + "\006path=/", dnssdRegisterCallback, + NULL)) != kDNSServiceErr_NoError) + cupsdLogMessage(CUPSD_LOG_ERROR, + "DNS-SD web interface registration failed: %d", error); } #endif /* HAVE_DNSSD */ @@ -1624,1131 +1726,1147 @@ dequote(char *d, /* I - Destination string */ } -#ifdef __APPLE__ +#ifdef HAVE_DNSSD /* - * 'get_hostconfig()' - Get an /etc/hostconfig service setting. + * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info. */ -static int /* O - 1 for YES or AUTOMATIC, 0 for NO */ -get_hostconfig(const char *name) /* I - Name of service */ +static char * /* O - TXT record */ +dnssdBuildTxtRecord( + int *txt_len, /* O - TXT record length */ + cupsd_printer_t *p, /* I - Printer information */ + int for_lpd) /* I - 1 = LPD, 0 = IPP */ { - cups_file_t *fp; /* Hostconfig file */ - char line[1024], /* Line from file */ - *ptr; /* Pointer to value */ - int state = 1; /* State of service */ + int i, j; /* Looping vars */ + char type_str[32], /* Type to string buffer */ + state_str[32], /* State to string buffer */ + rp_str[1024], /* Queue name string buffer */ + air_str[1024], /* auth-info-required string buffer */ + *keyvalue[32][2]; /* Table of key/value pairs */ /* - * Try opening the /etc/hostconfig file; if we can't open it, assume that - * the service is enabled/auto. + * Load up the key value pairs... */ - if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL) - { - /* - * Read lines from the file until we find the service... - */ + i = 0; - while (cupsFileGets(fp, line, sizeof(line))) - { - if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL) - continue; + keyvalue[i ][0] = "txtvers"; + keyvalue[i++][1] = "1"; - *ptr++ = '\0'; + keyvalue[i ][0] = "qtotal"; + keyvalue[i++][1] = "1"; - if (!strcasecmp(line, name)) - { - /* - * Found the service, see if it is set to "-NO-"... - */ + keyvalue[i ][0] = "rp"; + keyvalue[i++][1] = rp_str; + if (for_lpd) + strlcpy(rp_str, p->name, sizeof(rp_str)); + else + snprintf(rp_str, sizeof(rp_str), "%s/%s", + (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name); - if (!strncasecmp(ptr, "-NO-", 4)) - state = 0; - break; - } - } + keyvalue[i ][0] = "ty"; + keyvalue[i++][1] = p->make_model; - cupsFileClose(fp); + if (p->location && *p->location != '\0') + { + keyvalue[i ][0] = "note"; + keyvalue[i++][1] = p->location; } - return (state); -} -#endif /* __APPLE__ */ - - -/* - * 'is_local_queue()' - Determine whether the URI points at a local queue. - */ + keyvalue[i ][0] = "priority"; + keyvalue[i++][1] = for_lpd ? "100" : "0"; -static int /* O - 1 = local, 0 = remote, -1 = bad URI */ -is_local_queue(const char *uri, /* I - Printer URI */ - char *host, /* O - Host string */ - int hostlen, /* I - Length of host buffer */ - char *resource, /* O - Resource string */ - int resourcelen) /* I - Length of resource buffer */ -{ - char scheme[32], /* Scheme portion of URI */ - username[HTTP_MAX_URI]; /* Username portion of URI */ - int port; /* Port portion of URI */ - cupsd_netif_t *iface; /* Network interface */ + keyvalue[i ][0] = "product"; + keyvalue[i++][1] = p->product ? p->product : "Unknown"; + snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE); + snprintf(state_str, sizeof(state_str), "%d", p->state); - /* - * Pull the URI apart to see if this is a local or remote printer... - */ + keyvalue[i ][0] = "printer-state"; + keyvalue[i++][1] = state_str; - if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), - username, sizeof(username), host, hostlen, &port, - resource, resourcelen) < HTTP_URI_OK) - return (-1); + keyvalue[i ][0] = "printer-type"; + keyvalue[i++][1] = type_str; - DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName)); + keyvalue[i ][0] = "Transparent"; + keyvalue[i++][1] = "T"; - /* - * Check for local server addresses... - */ + keyvalue[i ][0] = "Binary"; + keyvalue[i++][1] = "T"; - if (!strcasecmp(host, ServerName) && port == LocalPort) - return (1); + if ((p->type & CUPS_PRINTER_FAX)) + { + keyvalue[i ][0] = "Fax"; + keyvalue[i++][1] = "T"; + } - cupsdNetIFUpdate(); + if ((p->type & CUPS_PRINTER_COLOR)) + { + keyvalue[i ][0] = "Color"; + keyvalue[i++][1] = "T"; + } - for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList); - iface; - iface = (cupsd_netif_t *)cupsArrayNext(NetIFList)) - if (!strcasecmp(host, iface->hostname) && port == iface->port) - return (1); + if ((p->type & CUPS_PRINTER_DUPLEX)) + { + keyvalue[i ][0] = "Duplex"; + keyvalue[i++][1] = "T"; + } - /* - * If we get here, the printer is remote... - */ + if ((p->type & CUPS_PRINTER_STAPLE)) + { + keyvalue[i ][0] = "Staple"; + keyvalue[i++][1] = "T"; + } - return (0); -} + if ((p->type & CUPS_PRINTER_COPIES)) + { + keyvalue[i ][0] = "Copies"; + keyvalue[i++][1] = "T"; + } + if ((p->type & CUPS_PRINTER_COLLATE)) + { + keyvalue[i ][0] = "Collate"; + keyvalue[i++][1] = "T"; + } -/* - * 'process_browse_data()' - Process new browse data. - */ - -static void -process_browse_data( - const char *uri, /* I - URI of printer/class */ - const char *host, /* I - Hostname */ - const char *resource, /* I - Resource path */ - cups_ptype_t type, /* I - Printer type */ - ipp_pstate_t state, /* I - Printer state */ - const char *location, /* I - Printer location */ - const char *info, /* I - Printer information */ - const char *make_model, /* I - Printer make and model */ - int num_attrs, /* I - Number of attributes */ - cups_option_t *attrs) /* I - Attributes */ -{ - int i; /* Looping var */ - int update; /* Update printer attributes? */ - char finaluri[HTTP_MAX_URI], /* Final URI for printer */ - name[IPP_MAX_NAME], /* Name of printer */ - newname[IPP_MAX_NAME], /* New name of printer */ - *hptr, /* Pointer into hostname */ - *sptr; /* Pointer into ServerName */ - char local_make_model[IPP_MAX_NAME]; - /* Local make and model */ - cupsd_printer_t *p; /* Printer information */ - const char *ipp_options, /* ipp-options value */ - *lease_duration; /* lease-duration value */ - - - /* - * Determine if the URI contains any illegal characters in it... - */ - - if (strncmp(uri, "ipp://", 6) || !host[0] || - (strncmp(resource, "/printers/", 10) && - strncmp(resource, "/classes/", 9))) + if ((p->type & CUPS_PRINTER_PUNCH)) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "process_browse_data: Bad printer URI in browse data: %s", - uri); - return; + keyvalue[i ][0] = "Punch"; + keyvalue[i++][1] = "T"; } - if (strchr(resource, '?') || - (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) || - (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/'))) + if ((p->type & CUPS_PRINTER_BIND)) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "process_browse_data: Bad resource in browse data: %s", - resource); - return; + keyvalue[i ][0] = "Bind"; + keyvalue[i++][1] = "T"; } - /* - * OK, this isn't a local printer; add any remote options... - */ + if ((p->type & CUPS_PRINTER_SORT)) + { + keyvalue[i ][0] = "Sort"; + keyvalue[i++][1] = "T"; + } - ipp_options = cupsGetOption("ipp-options", num_attrs, attrs); + keyvalue[i ][0] = "pdl"; + keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript"; - if (BrowseRemoteOptions) + if (p->num_auth_info_required) { - if (BrowseRemoteOptions[0] == '?') - { - /* - * Override server-supplied options... - */ + char *air = air_str; /* Pointer into string */ - snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions); - } - else if (ipp_options) - { - /* - * Combine the server and local options... - */ - snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options, - BrowseRemoteOptions); - } - else + for (j = 0; j < p->num_auth_info_required; j ++) { - /* - * Just use the local options... - */ + if (air >= (air_str + sizeof(air_str) - 2)) + break; - snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions); - } + if (j) + *air++ = ','; - uri = finaluri; - } - else if (ipp_options) - { - /* - * Just use the server-supplied options... - */ + strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str)); + air += strlen(air); + } - snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options); - uri = finaluri; + keyvalue[i ][0] = "air"; + keyvalue[i++][1] = air; } /* - * See if we already have it listed in the Printers list, and add it if not... + * Then pack them into a proper txt record... */ - type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED; - type &= ~CUPS_PRINTER_IMPLICIT; - update = 0; - hptr = strchr(host, '.'); - sptr = strchr(ServerName, '.'); + return (dnssdPackTxtRecord(txt_len, keyvalue, i)); +} - if (!ServerNameIsIP && sptr != NULL && hptr != NULL) - { - /* - * Strip the common domain name components... - */ - while (hptr != NULL) - { - if (!strcasecmp(hptr, sptr)) - { - *hptr = '\0'; - break; - } - else - hptr = strchr(hptr + 1, '.'); - } +/* + * 'dnssdComparePrinters()' - Compare the registered names of two printers. + */ + +static int /* O - Result of comparison */ +dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */ + cupsd_printer_t *b)/* I - Second printer */ +{ + return (strcasecmp(a->reg_name, b->reg_name)); +} + + +/* + * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a + * printer. + */ + +static void +dnssdDeregisterPrinter( + cupsd_printer_t *p) /* I - Printer */ +{ + cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name); + + /* + * Closing the socket deregisters the service + */ + + if (p->ipp_ref) + { + DNSServiceRefDeallocate(p->ipp_ref); + p->ipp_ref = NULL; } - if (type & CUPS_PRINTER_CLASS) + cupsArrayRemove(DNSSDPrinters, p); + cupsdClearString(&p->reg_name); + + if (p->ipp_txt) { /* - * Remote destination is a class... + * p->ipp_txt is malloc'd, not _cupsStrAlloc'd... */ - if (!strncmp(resource, "/classes/", 9)) - snprintf(name, sizeof(name), "%s@%s", resource + 9, host); - else - return; + free(p->ipp_txt); + p->ipp_txt = NULL; + } +} - if (hptr && !*hptr) - *hptr = '.'; /* Resource FQDN */ - if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames) - { - if ((p = cupsdFindDest(resource + 9)) != NULL) - { - if (p->hostname && strcasecmp(p->hostname, host)) - { - /* - * Nope, this isn't the same host; if the hostname isn't the local host, - * add it to the other class and then find a class using the full host - * name... - */ +/* + * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the + * TXT record format. + */ - if (p->type & CUPS_PRINTER_REMOTE) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Renamed remote class \"%s\" to \"%s@%s\"...", - p->name, p->name, p->hostname); - cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, - "Class \'%s\' deleted by directory services.", - p->name); +static char * /* O - TXT record */ +dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */ + char *keyvalue[][2], /* I - Table of key value pairs */ + int count) /* I - Items in table */ +{ + int i; /* Looping var */ + int length; /* Length of TXT record */ + int length2; /* Length of value */ + char *txtRecord; /* TXT record buffer */ + char *cursor; /* Looping pointer */ - snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname); - cupsdRenamePrinter(p, newname); - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, - "Class \'%s\' added by directory services.", - p->name); - } + /* + * Calculate the buffer size + */ - p = NULL; - } - else if (!p->hostname) - { - /* - * Hostname not set, so this must be a cached remote printer - * that was created for a pending print job... - */ + for (length = i = 0; i < count; i++) + length += 1 + strlen(keyvalue[i][0]) + + (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0); - cupsdSetString(&p->hostname, host); - cupsdSetString(&p->uri, uri); - cupsdSetString(&p->device_uri, uri); - update = 1; - } - } - else - { - /* - * Use the short name for this shared class. - */ + /* + * Allocate and fill it + */ - strlcpy(name, resource + 9, sizeof(name)); - } - } - else if (p && !p->hostname) + txtRecord = malloc(length); + if (txtRecord) + { + *txt_len = length; + + for (cursor = txtRecord, i = 0; i < count; i++) { /* - * Hostname not set, so this must be a cached remote printer - * that was created for a pending print job... + * Drop in the p-string style length byte followed by the data */ - cupsdSetString(&p->hostname, host); - cupsdSetString(&p->uri, uri); - cupsdSetString(&p->device_uri, uri); - update = 1; - } + length = strlen(keyvalue[i][0]); + length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0; - if (!p) - { - /* - * Class doesn't exist; add it... - */ + *cursor++ = (unsigned char)(length + length2); - p = cupsdAddClass(name); + memcpy(cursor, keyvalue[i][0], length); + cursor += length; - cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote class \"%s\"...", name); + if (length2) + { + length2 --; + *cursor++ = '='; + memcpy(cursor, keyvalue[i][1], length2); + cursor += length2; + } + } + } - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, - "Class \'%s\' added by directory services.", name); + return (txtRecord); +} - /* - * Force the URI to point to the real server... - */ - p->type = type & ~CUPS_PRINTER_REJECTING; - p->accepting = 1; - cupsdSetString(&p->uri, uri); - cupsdSetString(&p->device_uri, uri); - cupsdSetString(&p->hostname, host); +/* + * 'dnssdRegisterCallback()' - DNSServiceRegister callback. + */ - update = 1; +static void +dnssdRegisterCallback( + DNSServiceRef sdRef, /* I - DNS Service reference */ + DNSServiceFlags flags, /* I - Reserved for future use */ + DNSServiceErrorType errorCode, /* I - Error code */ + const char *name, /* I - Service name */ + const char *regtype, /* I - Service type */ + const char *domain, /* I - Domain. ".local" for now */ + void *context) /* I - User-defined context */ +{ + cupsd_printer_t *p = (cupsd_printer_t *)context; + /* Current printer */ - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); - } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s", + name, regtype, p ? p->name : "Web Interface"); + + if (errorCode) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "DNSServiceRegister failed with error %d", (int)errorCode); + return; } - else + else if (p && strcasecmp(name, p->reg_name)) { - /* - * Remote destination is a printer... - */ + cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"", + name, p->name); - if (!strncmp(resource, "/printers/", 10)) - snprintf(name, sizeof(name), "%s@%s", resource + 10, host); - else - return; + cupsArrayRemove(DNSSDPrinters, p); + cupsdSetString(&p->reg_name, name); + cupsArrayAdd(DNSSDPrinters, p); - if (hptr && !*hptr) - *hptr = '.'; /* Resource FQDN */ + LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED; + } +} - if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames) - { - if ((p = cupsdFindDest(resource + 10)) != NULL) - { - if (p->hostname && strcasecmp(p->hostname, host)) - { - /* - * Nope, this isn't the same host; if the hostname isn't the local host, - * add it to the other printer and then find a printer using the full host - * name... - */ - if (p->type & CUPS_PRINTER_REMOTE) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Renamed remote printer \"%s\" to \"%s@%s\"...", - p->name, p->name, p->hostname); - cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, - "Printer \'%s\' deleted by directory services.", - p->name); +/* + * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer + * or update the broadcast contents. + */ - snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname); - cupsdRenamePrinter(p, newname); +static void +dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ +{ + DNSServiceErrorType se; /* dnssd errors */ + char *ipp_txt, /* IPP TXT record buffer */ + *printer_txt, /* LPD TXT record buffer */ + name[1024], /* Service name */ + *nameptr; /* Pointer into name */ + int ipp_len, /* IPP TXT record length */ + printer_len; /* LPD TXT record length */ + char resource[1024]; /* Resource path for printer */ + const char *regtype; /* Registration type */ + const char *domain; /* Registration domain */ + cupsd_location_t *location, /* Printer location */ + *policy; /* Operation policy for Print-Job */ + unsigned address[4]; /* INADDR_ANY address */ - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, - "Printer \'%s\' added by directory services.", - p->name); - } - p = NULL; - } - else if (!p->hostname) - { - /* - * Hostname not set, so this must be a cached remote printer - * that was created for a pending print job... - */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name, + !p->ipp_ref ? "new" : "update"); - cupsdSetString(&p->hostname, host); - cupsdSetString(&p->uri, uri); - cupsdSetString(&p->device_uri, uri); - update = 1; - } - } - else - { - /* - * Use the short name for this shared printer. - */ + /* + * If per-printer sharing was just disabled make sure we're not + * registered before returning. + */ - strlcpy(name, resource + 10, sizeof(name)); - } - } - else if (p && !p->hostname) - { - /* - * Hostname not set, so this must be a cached remote printer - * that was created for a pending print job... - */ + if (!p->shared) + { + dnssdDeregisterPrinter(p); + return; + } - cupsdSetString(&p->hostname, host); - cupsdSetString(&p->uri, uri); - cupsdSetString(&p->device_uri, uri); - update = 1; - } + /* + * The registered name takes the form of " @ "... + */ - if (!p) - { - /* - * Printer doesn't exist; add it... - */ + if (p->info && strlen(p->info) > 0) + { + if (DNSSDName) + snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDName); + else + strlcpy(name, p->info, sizeof(name)); + } + else if (DNSSDName) + snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDName); + else + strlcpy(name, p->name, sizeof(name)); - p = cupsdAddPrinter(name); + /* + * If an existing printer was renamed, unregister it and start over... + */ - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, - "Printer \'%s\' added by directory services.", name); + if (p->reg_name && strcmp(p->reg_name, name)) + dnssdDeregisterPrinter(p); - cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote printer \"%s\"...", name); + if (!p->reg_name) + { + cupsdSetString(&p->reg_name, name); + cupsArrayAdd(DNSSDPrinters, p); + } - /* - * Force the URI to point to the real server... - */ + /* + * If 'Allow printing from the Internet' is enabled (i.e. from any address) + * let dnssd decide on the domain, otherwise restrict it to ".local". + */ - p->type = type & ~CUPS_PRINTER_REJECTING; - p->accepting = 1; - cupsdSetString(&p->hostname, host); - cupsdSetString(&p->uri, uri); - cupsdSetString(&p->device_uri, uri); + if (p->type & CUPS_PRINTER_CLASS) + snprintf(resource, sizeof(resource), "/classes/%s", p->name); + else + snprintf(resource, sizeof(resource), "/printers/%s", p->name); - update = 1; + address[0] = address[1] = address[2] = address[3] = 0; + location = cupsdFindBest(resource, HTTP_POST); + policy = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB); - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); - } - } + if ((location && !cupsdCheckAccess(address, "", 0, location)) || + (policy && !cupsdCheckAccess(address, "", 0, policy))) + domain = "local."; + else + domain = NULL; /* - * Update the state... + * Register IPP and (optionally) LPD... */ - p->state = state; - p->browse_time = time(NULL); + ipp_len = 0; /* anti-compiler-warning-code */ + ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0); - if ((lease_duration = cupsGetOption("lease-duration", num_attrs, - attrs)) != NULL) + if (!p->ipp_ref) { /* - * Grab the lease-duration for the browse data; anything less then 1 - * second or more than 1 week gets the default BrowseTimeout... + * Initial registration. Use the _fax subtype for fax queues... */ - i = atoi(lease_duration); - if (i < 1 || i > 604800) - i = BrowseTimeout; + regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" : + "_ipp._tcp,_cups"; - p->browse_expire = p->browse_time + i; - } - else - p->browse_expire = p->browse_time + BrowseTimeout; + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Registering DNS-SD printer %s with name \"%s\", " + "type \"%s\", and domain \"%s\"", p->name, name, regtype, + domain ? domain : "(null)"); - if (type & CUPS_PRINTER_REJECTING) - { - type &= ~CUPS_PRINTER_REJECTING; + /* + * Register the queue, dropping characters as needed until we succeed... + */ - if (p->accepting) + nameptr = name + strlen(name); + + do { - update = 1; - p->accepting = 0; + p->ipp_ref = DNSSDRef; + if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection, + 0, name, regtype, domain, NULL, + htons(DNSSDPort), ipp_len, ipp_txt, + dnssdRegisterCallback, + p)) == kDNSServiceErr_BadParam) + { + /* + * Name is too long, drop trailing characters, taking into account + * UTF-8 encoding... + */ + + nameptr --; + + while (nameptr > name && (*nameptr & 0xc0) == 0x80) + nameptr --; + + if (nameptr > name) + *nameptr = '\0'; + } + } + while (se == kDNSServiceErr_BadParam && nameptr > name); + + if (se == kDNSServiceErr_NoError) + { + p->ipp_txt = ipp_txt; + p->ipp_len = ipp_len; + ipp_txt = NULL; } + else + cupsdLogMessage(CUPSD_LOG_WARN, + "DNS-SD IPP registration of \"%s\" failed: %d", + p->name, se); } - else if (!p->accepting) + else if (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len)) { - update = 1; - p->accepting = 1; - } + /* + * Update the existing registration... + */ - if (p->type != type) - { - p->type = type; - update = 1; - } + /* A TTL of 0 means use record's original value (Radar 3176248) */ + DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt, 0); - if (location && (!p->location || strcmp(p->location, location))) - { - cupsdSetString(&p->location, location); - update = 1; + if (p->ipp_txt) + free(p->ipp_txt); + + p->ipp_txt = ipp_txt; + p->ipp_len = ipp_len; + ipp_txt = NULL; } - if (info && (!p->info || strcmp(p->info, info))) + if (ipp_txt) + free(ipp_txt); + + if (BrowseLocalProtocols & BROWSE_LPD) { - cupsdSetString(&p->info, info); - update = 1; + printer_len = 0; /* anti-compiler-warning-code */ + printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1); - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); - } + if (!p->printer_ref) + { + /* + * Initial registration... + */ - if (!make_model || !make_model[0]) - { - if (type & CUPS_PRINTER_CLASS) - snprintf(local_make_model, sizeof(local_make_model), - "Remote Class on %s", host); - else - snprintf(local_make_model, sizeof(local_make_model), - "Remote Printer on %s", host); - } - else - snprintf(local_make_model, sizeof(local_make_model), - "%s on %s", make_model, host); - - if (!p->make_model || strcmp(p->make_model, local_make_model)) - { - cupsdSetString(&p->make_model, local_make_model); - update = 1; - } - - if (p->num_options) - { - if (!update && !(type & CUPS_PRINTER_DELETE)) + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Registering DNS-SD printer %s with name \"%s\", " + "type \"_printer._tcp\", and domain \"%s\"", p->name, + name, domain ? domain : "(null)"); + + p->printer_ref = DNSSDRef; + if ((se = DNSServiceRegister(&p->printer_ref, + kDNSServiceFlagsShareConnection, + 0, name, "_printer._tcp", domain, NULL, + htons(515), printer_len, printer_txt, + dnssdRegisterCallback, + p)) == kDNSServiceErr_NoError) + { + p->printer_txt = printer_txt; + p->printer_len = printer_len; + printer_txt = NULL; + } + else + cupsdLogMessage(CUPSD_LOG_WARN, + "DNS-SD LPD registration of \"%s\" failed: %d", + p->name, se); + } + else if (printer_len != p->printer_len || + memcmp(printer_txt, p->printer_txt, printer_len)) { /* - * See if we need to update the attributes... + * Update the existing registration... */ - if (p->num_options != num_attrs) - update = 1; - else - { - for (i = 0; i < num_attrs; i ++) - if (strcmp(attrs[i].name, p->options[i].name) || - (!attrs[i].value != !p->options[i].value) || - (attrs[i].value && strcmp(attrs[i].value, p->options[i].value))) - { - update = 1; - break; - } - } - } + /* A TTL of 0 means use record's original value (Radar 3176248) */ + DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len, + printer_txt, 0); - /* - * Free the old options... - */ + if (p->printer_txt) + free(p->printer_txt); - cupsFreeOptions(p->num_options, p->options); + p->printer_txt = printer_txt; + p->printer_len = printer_len; + printer_txt = NULL; + } + + if (printer_txt) + free(printer_txt); } +} +#endif /* HAVE_DNSSD */ - p->num_options = num_attrs; - p->options = attrs; - if (type & CUPS_PRINTER_DELETE) - { - cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, - "%s \'%s\' deleted by directory services.", - (type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", p->name); +#ifdef __APPLE__ +/* + * 'get_hostconfig()' - Get an /etc/hostconfig service setting. + */ + +static int /* O - 1 for YES or AUTOMATIC, 0 for NO */ +get_hostconfig(const char *name) /* I - Name of service */ +{ + cups_file_t *fp; /* Hostconfig file */ + char line[1024], /* Line from file */ + *ptr; /* Pointer to value */ + int state = 1; /* State of service */ - cupsdExpireSubscriptions(p, NULL); - - cupsdDeletePrinter(p, 1); - cupsdUpdateImplicitClasses(); - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); - } - else if (update) - { - cupsdSetPrinterAttrs(p); - cupsdUpdateImplicitClasses(); - } /* - * See if we have a default printer... If not, make the first network - * default printer the default. + * Try opening the /etc/hostconfig file; if we can't open it, assume that + * the service is enabled/auto. */ - if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault) + if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL) { /* - * Find the first network default printer and use it... + * Read lines from the file until we find the service... */ - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); - p; - p = (cupsd_printer_t *)cupsArrayNext(Printers)) - if (p->type & CUPS_PRINTER_DEFAULT) + while (cupsFileGets(fp, line, sizeof(line))) + { + if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL) + continue; + + *ptr++ = '\0'; + + if (!strcasecmp(line, name)) { - DefaultPrinter = p; - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); - break; + /* + * Found the service, see if it is set to "-NO-"... + */ + + if (!strncasecmp(ptr, "-NO-", 4)) + state = 0; + break; } - } + } - /* - * Do auto-classing if needed... - */ + cupsFileClose(fp); + } - process_implicit_classes(); + return (state); } +#endif /* __APPLE__ */ -#ifdef HAVE_DNSSD /* - * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info. + * 'is_local_queue()' - Determine whether the URI points at a local queue. */ -static char * /* O - TXT record */ -dnssdBuildTxtRecord( - int *txt_len, /* O - TXT record length */ - cupsd_printer_t *p) /* I - Printer information */ +static int /* O - 1 = local, 0 = remote, -1 = bad URI */ +is_local_queue(const char *uri, /* I - Printer URI */ + char *host, /* O - Host string */ + int hostlen, /* I - Length of host buffer */ + char *resource, /* O - Resource string */ + int resourcelen) /* I - Length of resource buffer */ { - int i, j; /* Looping vars */ - char type_str[32], /* Type to string buffer */ - state_str[32], /* State to string buffer */ - rp_str[1024], /* Queue name string buffer */ - air_str[1024], /* auth-info-required string buffer */ - *keyvalue[32][2]; /* Table of key/value pairs */ + char scheme[32], /* Scheme portion of URI */ + username[HTTP_MAX_URI]; /* Username portion of URI */ + int port; /* Port portion of URI */ + cupsd_netif_t *iface; /* Network interface */ /* - * Load up the key value pairs... + * Pull the URI apart to see if this is a local or remote printer... */ - i = 0; + if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), + username, sizeof(username), host, hostlen, &port, + resource, resourcelen) < HTTP_URI_OK) + return (-1); - keyvalue[i ][0] = "txtvers"; - keyvalue[i++][1] = "1"; + DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName)); - keyvalue[i ][0] = "qtotal"; - keyvalue[i++][1] = "1"; + /* + * Check for local server addresses... + */ - keyvalue[i ][0] = "rp"; - keyvalue[i++][1] = rp_str; - snprintf(rp_str, sizeof(rp_str), "%s/%s", - (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name); + if (!strcasecmp(host, ServerName) && port == LocalPort) + return (1); - keyvalue[i ][0] = "ty"; - keyvalue[i++][1] = p->make_model; + cupsdNetIFUpdate(); - if (p->location && *p->location != '\0') - { - keyvalue[i ][0] = "note"; - keyvalue[i++][1] = p->location; - } + for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList); + iface; + iface = (cupsd_netif_t *)cupsArrayNext(NetIFList)) + if (!strcasecmp(host, iface->hostname) && port == iface->port) + return (1); - keyvalue[i ][0] = "product"; - keyvalue[i++][1] = p->product ? p->product : "Unknown"; + /* + * If we get here, the printer is remote... + */ - snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE); - snprintf(state_str, sizeof(state_str), "%d", p->state); + return (0); +} - keyvalue[i ][0] = "printer-state"; - keyvalue[i++][1] = state_str; - keyvalue[i ][0] = "printer-type"; - keyvalue[i++][1] = type_str; +/* + * 'process_browse_data()' - Process new browse data. + */ - keyvalue[i ][0] = "Transparent"; - keyvalue[i++][1] = "T"; +static void +process_browse_data( + const char *uri, /* I - URI of printer/class */ + const char *host, /* I - Hostname */ + const char *resource, /* I - Resource path */ + cups_ptype_t type, /* I - Printer type */ + ipp_pstate_t state, /* I - Printer state */ + const char *location, /* I - Printer location */ + const char *info, /* I - Printer information */ + const char *make_model, /* I - Printer make and model */ + int num_attrs, /* I - Number of attributes */ + cups_option_t *attrs) /* I - Attributes */ +{ + int i; /* Looping var */ + int update; /* Update printer attributes? */ + char finaluri[HTTP_MAX_URI], /* Final URI for printer */ + name[IPP_MAX_NAME], /* Name of printer */ + newname[IPP_MAX_NAME], /* New name of printer */ + *hptr, /* Pointer into hostname */ + *sptr; /* Pointer into ServerName */ + char local_make_model[IPP_MAX_NAME]; + /* Local make and model */ + cupsd_printer_t *p; /* Printer information */ + const char *ipp_options, /* ipp-options value */ + *lease_duration; /* lease-duration value */ - keyvalue[i ][0] = "Binary"; - keyvalue[i++][1] = "T"; - if ((p->type & CUPS_PRINTER_FAX)) - { - keyvalue[i ][0] = "Fax"; - keyvalue[i++][1] = "T"; - } + /* + * Determine if the URI contains any illegal characters in it... + */ - if ((p->type & CUPS_PRINTER_COLOR)) + if (strncmp(uri, "ipp://", 6) || !host[0] || + (strncmp(resource, "/printers/", 10) && + strncmp(resource, "/classes/", 9))) { - keyvalue[i ][0] = "Color"; - keyvalue[i++][1] = "T"; + cupsdLogMessage(CUPSD_LOG_ERROR, + "process_browse_data: Bad printer URI in browse data: %s", + uri); + return; } - if ((p->type & CUPS_PRINTER_DUPLEX)) + if (strchr(resource, '?') || + (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) || + (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/'))) { - keyvalue[i ][0] = "Duplex"; - keyvalue[i++][1] = "T"; + cupsdLogMessage(CUPSD_LOG_ERROR, + "process_browse_data: Bad resource in browse data: %s", + resource); + return; } - if ((p->type & CUPS_PRINTER_STAPLE)) - { - keyvalue[i ][0] = "Staple"; - keyvalue[i++][1] = "T"; - } + /* + * OK, this isn't a local printer; add any remote options... + */ - if ((p->type & CUPS_PRINTER_COPIES)) + ipp_options = cupsGetOption("ipp-options", num_attrs, attrs); + + if (BrowseRemoteOptions) { - keyvalue[i ][0] = "Copies"; - keyvalue[i++][1] = "T"; - } + if (BrowseRemoteOptions[0] == '?') + { + /* + * Override server-supplied options... + */ - if ((p->type & CUPS_PRINTER_COLLATE)) - { - keyvalue[i ][0] = "Collate"; - keyvalue[i++][1] = "T"; - } + snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions); + } + else if (ipp_options) + { + /* + * Combine the server and local options... + */ - if ((p->type & CUPS_PRINTER_PUNCH)) - { - keyvalue[i ][0] = "Punch"; - keyvalue[i++][1] = "T"; - } + snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options, + BrowseRemoteOptions); + } + else + { + /* + * Just use the local options... + */ - if ((p->type & CUPS_PRINTER_BIND)) - { - keyvalue[i ][0] = "Bind"; - keyvalue[i++][1] = "T"; - } + snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions); + } - if ((p->type & CUPS_PRINTER_SORT)) - { - keyvalue[i ][0] = "Sort"; - keyvalue[i++][1] = "T"; + uri = finaluri; } - - keyvalue[i ][0] = "pdl"; - keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript"; - - if (p->num_auth_info_required) + else if (ipp_options) { - char *air = air_str; /* Pointer into string */ - - - for (j = 0; j < p->num_auth_info_required; j ++) - { - if (air >= (air_str + sizeof(air_str) - 2)) - break; - - if (j) - *air++ = ','; - - strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str)); - air += strlen(air); - } + /* + * Just use the server-supplied options... + */ - keyvalue[i ][0] = "air"; - keyvalue[i++][1] = air; + snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options); + uri = finaluri; } /* - * Then pack them into a proper txt record... + * See if we already have it listed in the Printers list, and add it if not... */ - return (dnssdPackTxtRecord(txt_len, keyvalue, i)); -} - - -/* - * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a - * printer. - */ - -static void -dnssdDeregisterPrinter( - cupsd_printer_t *p) /* I - Printer */ -{ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name); - - /* - * Closing the socket deregisters the service - */ + type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED; + type &= ~CUPS_PRINTER_IMPLICIT; + update = 0; + hptr = strchr(host, '.'); + sptr = strchr(ServerName, '.'); - if (p->dnssd_ipp_ref) + if (!ServerNameIsIP && sptr != NULL && hptr != NULL) { - cupsdRemoveSelect(p->dnssd_ipp_fd); - DNSServiceRefDeallocate(p->dnssd_ipp_ref); - p->dnssd_ipp_ref = NULL; - p->dnssd_ipp_fd = -1; - } + /* + * Strip the common domain name components... + */ - cupsdClearString(&p->reg_name); + while (hptr != NULL) + { + if (!strcasecmp(hptr, sptr)) + { + *hptr = '\0'; + break; + } + else + hptr = strchr(hptr + 1, '.'); + } + } - if (p->txt_record) + if (type & CUPS_PRINTER_CLASS) { /* - * p->txt_record is malloc'd, not _cupsStrAlloc'd... + * Remote destination is a class... */ - free(p->txt_record); - p->txt_record = NULL; - } -} + if (!strncmp(resource, "/classes/", 9)) + snprintf(name, sizeof(name), "%s@%s", resource + 9, host); + else + return; + if (hptr && !*hptr) + *hptr = '.'; /* Resource FQDN */ -/* - * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the - * TXT record format. - */ + if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames) + { + if ((p = cupsdFindDest(resource + 9)) != NULL) + { + if (p->hostname && strcasecmp(p->hostname, host)) + { + /* + * Nope, this isn't the same host; if the hostname isn't the local host, + * add it to the other class and then find a class using the full host + * name... + */ -static char * /* O - TXT record */ -dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */ - char *keyvalue[][2], /* I - Table of key value pairs */ - int count) /* I - Items in table */ -{ - int i; /* Looping var */ - int length; /* Length of TXT record */ - int length2; /* Length of value */ - char *txtRecord; /* TXT record buffer */ - char *cursor; /* Looping pointer */ + if (p->type & CUPS_PRINTER_REMOTE) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Renamed remote class \"%s\" to \"%s@%s\"...", + p->name, p->name, p->hostname); + cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, + "Class \'%s\' deleted by directory services.", + p->name); + + snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname); + cupsdRenamePrinter(p, newname); + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, + "Class \'%s\' added by directory services.", + p->name); + } - /* - * Calculate the buffer size - */ + p = NULL; + } + else if (!p->hostname) + { + /* + * Hostname not set, so this must be a cached remote printer + * that was created for a pending print job... + */ - for (length = i = 0; i < count; i++) - length += 1 + strlen(keyvalue[i][0]) + - (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0); + cupsdSetString(&p->hostname, host); + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); + update = 1; + } + } + else + { + /* + * Use the short name for this shared class. + */ - /* - * Allocate and fill it - */ + strlcpy(name, resource + 9, sizeof(name)); + } + } + else if (p && !p->hostname) + { + /* + * Hostname not set, so this must be a cached remote printer + * that was created for a pending print job... + */ - txtRecord = malloc(length); - if (txtRecord) - { - *txt_len = length; + cupsdSetString(&p->hostname, host); + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); + update = 1; + } - for (cursor = txtRecord, i = 0; i < count; i++) + if (!p) { /* - * Drop in the p-string style length byte followed by the data + * Class doesn't exist; add it... */ - length = strlen(keyvalue[i][0]); - length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0; + p = cupsdAddClass(name); - *cursor++ = (unsigned char)(length + length2); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote class \"%s\"...", name); - memcpy(cursor, keyvalue[i][0], length); - cursor += length; + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, + "Class \'%s\' added by directory services.", name); - if (length2) - { - length2 --; - *cursor++ = '='; - memcpy(cursor, keyvalue[i][1], length2); - cursor += length2; - } - } - } + /* + * Force the URI to point to the real server... + */ - return (txtRecord); -} + p->type = type & ~CUPS_PRINTER_REJECTING; + p->accepting = 1; + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); + cupsdSetString(&p->hostname, host); + update = 1; -/* - * 'dnssdRegisterCallback()' - DNSServiceRegister callback. - */ + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); + } + } + else + { + /* + * Remote destination is a printer... + */ -static void -dnssdRegisterCallback( - DNSServiceRef sdRef, /* I - DNS Service reference */ - DNSServiceFlags flags, /* I - Reserved for future use */ - DNSServiceErrorType errorCode, /* I - Error code */ - const char *name, /* I - Service name */ - const char *regtype, /* I - Service type */ - const char *domain, /* I - Domain. ".local" for now */ - void *context) /* I - User-defined context */ -{ - cupsd_printer_t *p = (cupsd_printer_t *)context; - /* Current printer */ + if (!strncmp(resource, "/printers/", 10)) + snprintf(name, sizeof(name), "%s@%s", resource + 10, host); + else + return; + if (hptr && !*hptr) + *hptr = '.'; /* Resource FQDN */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s", - name, regtype, p->name); + if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames) + { + if ((p = cupsdFindDest(resource + 10)) != NULL) + { + if (p->hostname && strcasecmp(p->hostname, host)) + { + /* + * Nope, this isn't the same host; if the hostname isn't the local host, + * add it to the other printer and then find a printer using the full host + * name... + */ - if (errorCode) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "DNSServiceRegister failed with error %d", (int)errorCode); - return; - } - else if (strcasecmp(name, p->reg_name)) - { - cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"", - name, p->name); + if (p->type & CUPS_PRINTER_REMOTE) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Renamed remote printer \"%s\" to \"%s@%s\"...", + p->name, p->name, p->hostname); + cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, + "Printer \'%s\' deleted by directory services.", + p->name); - cupsdSetString(&p->reg_name, name); - LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED; - } -} + snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname); + cupsdRenamePrinter(p, newname); + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, + "Printer \'%s\' added by directory services.", + p->name); + } + + p = NULL; + } + else if (!p->hostname) + { + /* + * Hostname not set, so this must be a cached remote printer + * that was created for a pending print job... + */ -/* - * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer - * or update the broadcast contents. - */ + cupsdSetString(&p->hostname, host); + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); + update = 1; + } + } + else + { + /* + * Use the short name for this shared printer. + */ -static void -dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ -{ - DNSServiceErrorType se; /* dnssd errors */ - cupsd_listener_t *lis; /* Current listening socket */ - char *txt_record, /* TXT record buffer */ - *name; /* Service name */ - int txt_len, /* TXT record length */ - port; /* IPP port number */ - char resource[1024], /* Resource path for printer */ - str_buffer[1024]; - /* C-string buffer */ - const char *computerName; /* Computer name c-string ptr */ - const char *regtype; /* Registration type */ - const char *domain; /* Registration domain */ - cupsd_location_t *location, /* Printer location */ - *policy; /* Operation policy for Print-Job */ - unsigned address[4]; /* INADDR_ANY address */ -#ifdef HAVE_COREFOUNDATION_H - CFStringRef computerNameRef;/* Computer name CFString */ - CFStringEncoding nameEncoding; /* Computer name encoding */ - CFMutableStringRef shortNameRef; /* Mutable name string */ - CFIndex nameLength; /* Name string length */ -#else - int nameLength; /* Name string length */ -#endif /* HAVE_COREFOUNDATION_H */ + strlcpy(name, resource + 10, sizeof(name)); + } + } + else if (p && !p->hostname) + { + /* + * Hostname not set, so this must be a cached remote printer + * that was created for a pending print job... + */ + cupsdSetString(&p->hostname, host); + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); + update = 1; + } - cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name, - !p->dnssd_ipp_ref ? "new" : "update"); + if (!p) + { + /* + * Printer doesn't exist; add it... + */ - /* - * If per-printer sharing was just disabled make sure we're not - * registered before returning. - */ + p = cupsdAddPrinter(name); - if (!p->shared) - { - dnssdDeregisterPrinter(p); - return; - } + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, + "Printer \'%s\' added by directory services.", name); - /* - * Get the computer name as a c-string... - */ + cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote printer \"%s\"...", name); -#ifdef HAVE_COREFOUNDATION_H - computerName = NULL; - if ((computerNameRef = SCDynamicStoreCopyComputerName(NULL, &nameEncoding))) - if ((computerName = CFStringGetCStringPtr(computerNameRef, - kCFStringEncodingUTF8)) == NULL) - if (CFStringGetCString(computerNameRef, str_buffer, sizeof(str_buffer), - kCFStringEncodingUTF8)) - computerName = str_buffer; -#else - computerName = ServerName; -#endif /* HAVE_COREFOUNDATION_H */ + /* + * Force the URI to point to the real server... + */ - /* - * The registered name takes the form of " @ "... - */ + p->type = type & ~CUPS_PRINTER_REJECTING; + p->accepting = 1; + cupsdSetString(&p->hostname, host); + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); - name = NULL; - if (computerName) - cupsdSetStringf(&name, "%s @ %s", - (p->info && strlen(p->info)) ? p->info : p->name, - computerName); - else - cupsdSetString(&name, (p->info && strlen(p->info)) ? p->info : p->name); + update = 1; -#ifdef HAVE_COREFOUNDATION_H - if (computerNameRef) - CFRelease(computerNameRef); -#endif /* HAVE_COREFOUNDATION_H */ + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); + } + } /* - * If an existing printer was renamed, unregister it and start over... + * Update the state... */ - if (p->reg_name && strcmp(p->reg_name, name)) - dnssdDeregisterPrinter(p); - - txt_len = 0; /* anti-compiler-warning-code */ - txt_record = dnssdBuildTxtRecord(&txt_len, p); + p->state = state; + p->browse_time = time(NULL); - if (!p->dnssd_ipp_ref) + if ((lease_duration = cupsGetOption("lease-duration", num_attrs, + attrs)) != NULL) { /* - * Initial registration... + * Grab the lease-duration for the browse data; anything less then 1 + * second or more than 1 week gets the default BrowseTimeout... */ - cupsdSetString(&p->reg_name, name); + i = atoi(lease_duration); + if (i < 1 || i > 604800) + i = BrowseTimeout; + + p->browse_expire = p->browse_time + i; + } + else + p->browse_expire = p->browse_time + BrowseTimeout; - port = ippPort(); + if (type & CUPS_PRINTER_REJECTING) + { + type &= ~CUPS_PRINTER_REJECTING; - for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); - lis; - lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) + if (p->accepting) { - if (lis->address.addr.sa_family == AF_INET) - { - port = ntohs(lis->address.ipv4.sin_port); - break; - } - else if (lis->address.addr.sa_family == AF_INET6) - { - port = ntohs(lis->address.ipv6.sin6_port); - break; - } + update = 1; + p->accepting = 0; } + } + else if (!p->accepting) + { + update = 1; + p->accepting = 1; + } - /* - * If 'Allow printing from the Internet' is enabled (i.e. from any address) - * let dnssd decide on the domain, otherwise restrict it to ".local". - */ - - if (p->type & CUPS_PRINTER_CLASS) - snprintf(resource, sizeof(resource), "/classes/%s", p->name); - else - snprintf(resource, sizeof(resource), "/printers/%s", p->name); + if (p->type != type) + { + p->type = type; + update = 1; + } - address[0] = address[1] = address[2] = address[3] = 0; - location = cupsdFindBest(resource, HTTP_POST); - policy = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB); + if (location && (!p->location || strcmp(p->location, location))) + { + cupsdSetString(&p->location, location); + update = 1; + } - if ((location && !cupsdCheckAccess(address, "", 0, location)) || - (policy && !cupsdCheckAccess(address, "", 0, policy))) - domain = "local."; - else - domain = NULL; + if (info && (!p->info || strcmp(p->info, info))) + { + cupsdSetString(&p->info, info); + update = 1; - /* - * Use the _fax subtype for fax queues... - */ + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); + } - regtype = (p->type & CUPS_PRINTER_FAX) ? dnssdIPPFaxRegType : - dnssdIPPRegType; + if (!make_model || !make_model[0]) + { + if (type & CUPS_PRINTER_CLASS) + snprintf(local_make_model, sizeof(local_make_model), + "Remote Class on %s", host); + else + snprintf(local_make_model, sizeof(local_make_model), + "Remote Printer on %s", host); + } + else + snprintf(local_make_model, sizeof(local_make_model), + "%s on %s", make_model, host); + if (!p->make_model || strcmp(p->make_model, local_make_model)) + { + cupsdSetString(&p->make_model, local_make_model); + update = 1; + } - cupsdLogMessage(CUPSD_LOG_DEBUG, - "dnssdRegisterPrinter(%s) type, domain is \"%s\", \"%s\"", - p->name, regtype, domain ? domain : "(null)"); + if (p->num_options) + { + if (!update && !(type & CUPS_PRINTER_DELETE)) + { + /* + * See if we need to update the attributes... + */ - se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, name, regtype, - domain, NULL, htons(port), txt_len, txt_record, - dnssdRegisterCallback, p); + if (p->num_options != num_attrs) + update = 1; + else + { + for (i = 0; i < num_attrs; i ++) + if (strcmp(attrs[i].name, p->options[i].name) || + (!attrs[i].value != !p->options[i].value) || + (attrs[i].value && strcmp(attrs[i].value, p->options[i].value))) + { + update = 1; + break; + } + } + } /* - * In case the name is too long, try shortening the string one character - * at a time... + * Free the old options... */ - if (se == kDNSServiceErr_BadParam) - { -#ifdef HAVE_COREFOUNDATION_H - if ((shortNameRef = CFStringCreateMutable(NULL, 0)) != NULL) - { - CFStringAppendCString(shortNameRef, name, kCFStringEncodingUTF8); - nameLength = CFStringGetLength(shortNameRef); - - while (se == kDNSServiceErr_BadParam && nameLength > 1) - { - CFStringDelete(shortNameRef, CFRangeMake(--nameLength, 1)); - if (CFStringGetCString(shortNameRef, str_buffer, sizeof(str_buffer), - kCFStringEncodingUTF8)) - { - se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer, - regtype, NULL, NULL, htons(port), - txt_len, txt_record, - dnssdRegisterCallback, p); - } - } + cupsFreeOptions(p->num_options, p->options); + } - CFRelease(shortNameRef); - } -#else - nameLength = strlen(name); - while (se == kDNSServiceErr_BadParam && nameLength > 1) - { - name[--nameLength] = '\0'; - se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer, regtype, - NULL, NULL, htons(port), txt_len, txt_record, - dnssdRegisterCallback, p); - } -#endif /* HAVE_COREFOUNDATION_H */ - } + p->num_options = num_attrs; + p->options = attrs; - if (se == kDNSServiceErr_NoError) - { - p->dnssd_ipp_fd = DNSServiceRefSockFD(p->dnssd_ipp_ref); - p->txt_record = txt_record; - p->txt_len = txt_len; - txt_record = NULL; + if (type & CUPS_PRINTER_DELETE) + { + cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, + "%s \'%s\' deleted by directory services.", + (type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", p->name); - cupsdAddSelect(p->dnssd_ipp_fd, (cupsd_selfunc_t)cupsdUpdateDNSSDBrowse, - NULL, (void *)p); - } - else - cupsdLogMessage(CUPSD_LOG_WARN, - "DNS-SD registration of \"%s\" failed with %d", - p->name, se); + cupsdExpireSubscriptions(p, NULL); + + cupsdDeletePrinter(p, 1); + cupsdUpdateImplicitClasses(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); } - else if (txt_len != p->txt_len || memcmp(txt_record, p->txt_record, txt_len)) + else if (update) { - /* - * Update the existing registration... - */ + cupsdSetPrinterAttrs(p); + cupsdUpdateImplicitClasses(); + } - /* A TTL of 0 means use record's original value (Radar 3176248) */ - se = DNSServiceUpdateRecord(p->dnssd_ipp_ref, NULL, 0, - txt_len, txt_record, 0); + /* + * See if we have a default printer... If not, make the first network + * default printer the default. + */ - if (p->txt_record) - free(p->txt_record); + if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault) + { + /* + * Find the first network default printer and use it... + */ - p->txt_record = txt_record; - p->txt_len = txt_len; - txt_record = NULL; + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + if (p->type & CUPS_PRINTER_DEFAULT) + { + DefaultPrinter = p; + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); + break; + } } - if (txt_record) - free(txt_record); + /* + * Do auto-classing if needed... + */ - cupsdClearString(&name); + process_implicit_classes(); } -#endif /* HAVE_DNSSD */ /* @@ -2837,7 +2955,7 @@ process_implicit_classes(void) update = 1; - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE); cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...", name); @@ -3679,10 +3797,19 @@ update_cups_browse(void) { cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.", strerror(errno)); - cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off."); + cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off."); + +#ifdef WIN32 + closesocket(BrowseSocket); +#else + close(BrowseSocket); +#endif /* WIN32 */ + + cupsdRemoveSelect(BrowseSocket); + BrowseSocket = -1; - cupsdStopBrowsing(); - Browsing = 0; + BrowseLocalProtocols &= ~BROWSE_CUPS; + BrowseRemoteProtocols &= ~BROWSE_CUPS; } return; diff --git a/scheduler/dirsvc.h b/scheduler/dirsvc.h index 5ff06c3ee..16693c293 100644 --- a/scheduler/dirsvc.h +++ b/scheduler/dirsvc.h @@ -127,6 +127,21 @@ VAR int PollPipe VALUE(0); VAR cupsd_statbuf_t *PollStatusBuffer VALUE(NULL); /* Status buffer for pollers */ +#ifdef HAVE_DNSSD +VAR char *DNSSDName VALUE(NULL); + /* Computer/server name */ +VAR int DNSSDPort VALUE(0); + /* Port number to register */ +VAR cups_array_t *DNSSDPrinters VALUE(NULL); + /* Printers we have registered */ +VAR DNSServiceRef DNSSDRef VALUE(NULL), + /* Master DNS-SD service reference */ + WebIFRef VALUE(NULL), + /* Service reference for the web interface */ + RemoteRef VALUE(NULL); + /* Remote printer browse reference */ +#endif /* HAVE_DNSSD */ + #ifdef HAVE_LIBSLP VAR SLPHandle BrowseSLPHandle VALUE(NULL); /* SLP API handle */ @@ -173,7 +188,8 @@ extern void cupsdStartPolling(void); extern void cupsdStopBrowsing(void); extern void cupsdStopPolling(void); #ifdef HAVE_DNSSD -extern void cupsdUpdateDNSSDBrowse(cupsd_printer_t *p); +extern void cupsdUpdateDNSSDBrowse(void); +extern void cupsdUpdateDNSSDName(void); #endif /* HAVE_DNSSD */ #ifdef HAVE_LDAP extern void cupsdUpdateLDAPBrowse(void); diff --git a/scheduler/main.c b/scheduler/main.c index 4c7c697e9..f5d408e78 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -853,8 +853,8 @@ main(int argc, /* I - Number of command-line args */ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) - cupsdLogMessage(CUPSD_LOG_EMERG, "printer[%s] %d", p->name, - p->dnssd_ipp_fd); + cupsdLogMessage(CUPSD_LOG_EMERG, "printer[%s] reg_name=\"%s\"", p->name, + p->reg_name ? p->reg_name : "(null)"); #endif /* HAVE_DNSSD */ break; @@ -1646,7 +1646,7 @@ process_children(void) for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); job; job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) - if (job->state_value == IPP_JOB_PROCESSING) + if (job->state_value >= IPP_JOB_HELD && job->filters[0]) { for (i = 0; job->filters[i]; i ++) if (job->filters[i] == pid) @@ -1663,9 +1663,6 @@ process_children(void) else job->backend = -pid; - if (job->state_value == IPP_JOB_CANCELED) - status = 0; /* Ignore errors when canceling jobs */ - if (status && job->status >= 0) { /* @@ -1724,7 +1721,7 @@ process_children(void) if (status) { if (WIFEXITED(status)) - cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) stopped with status %d!", + cupsdLogMessage(CUPSD_LOG_DEBUG, "PID %d (%s) stopped with status %d!", pid, name, WEXITSTATUS(status)); else cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) crashed on signal %d!", diff --git a/scheduler/printers.c b/scheduler/printers.c index 11abd6b8d..8cd2e6e4a 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -2297,11 +2297,15 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ if (ppd->num_filters == 0) { /* - * If there are no filters, add a PostScript printing filter. + * If there are no filters, add PostScript printing filters. */ + add_printer_filter(p, p->filetype, + "application/vnd.cups-command 0 commandtops"); add_printer_filter(p, p->filetype, "application/vnd.cups-postscript 0 -"); + + p->type |= CUPS_PRINTER_COMMANDS; } /* @@ -2782,7 +2786,8 @@ cupsdSetPrinterState( * Let the browse protocols reflect the change... */ - cupsdRegisterPrinter(p); + if (update) + cupsdRegisterPrinter(p); /* * Save the printer configuration if a printer goes from idle or processing diff --git a/scheduler/printers.h b/scheduler/printers.h index a7fecdad5..d28789bf1 100644 --- a/scheduler/printers.h +++ b/scheduler/printers.h @@ -96,10 +96,12 @@ typedef struct cupsd_printer_s char *reg_name, /* Name used for service registration */ *product, /* PPD Product string */ *pdl, /* pdl value for TXT record */ - *txt_record; /* TXT record contents */ - int txt_len; /* TXT record length */ - DNSServiceRef dnssd_ipp_ref; /* DNSServiceRegister ref for _ipp */ - int dnssd_ipp_fd; /* File descriptor for DNSServiceRegister reference */ + *ipp_txt, /* IPP TXT record contents */ + *printer_txt; /* LPD TXT record contents */ + int ipp_len, /* IPP TXT record length */ + printer_len; /* LPD TXT record length */ + DNSServiceRef ipp_ref, /* Reference for _ipp._tcp,_cups */ + printer_ref; /* Reference for _printer._tcp */ #endif /* HAVE_DNSSD */ } cupsd_printer_t; diff --git a/scheduler/sysman.c b/scheduler/sysman.c index 636cc9475..b6d175142 100644 --- a/scheduler/sysman.c +++ b/scheduler/sysman.c @@ -455,6 +455,12 @@ cupsdUpdateSystemMonitor(void) p = (cupsd_printer_t *)cupsArrayNext(Printers)) cupsdDeregisterPrinter(p, 1); + /* + * Update the computer name... + */ + + cupsdUpdateDNSSDName(); + /* * Now re-register them... */ diff --git a/scripting/php/Makefile b/scripting/php/Makefile index 09b07fb24..b2135802c 100644 --- a/scripting/php/Makefile +++ b/scripting/php/Makefile @@ -21,7 +21,7 @@ include ../../Makedefs # PHPDIR = $(BUILDROOT)`$(PHPCONFIG) --extension-dir` -OPTIONS = -I../.. `$(PHPCONFIG) --includes` +OPTIONS = $(PHPOPTIONS) # diff --git a/systemv/cupstestppd.c b/systemv/cupstestppd.c index 6bbf63ada..ac4e67de5 100644 --- a/systemv/cupstestppd.c +++ b/systemv/cupstestppd.c @@ -18,6 +18,18 @@ * * Contents: * + * main() - Main entry for test program. + * check_basics() - Check for CR LF, mixed line endings, and blank + * lines. + * check_constraints() - Check UIConstraints in the PPD file. + * check_defaults() - Check default option keywords in the PPD file. + * check_filters() - Check filters in the PPD file. + * check_profiles() - Check ICC color profiles in the PPD file. + * check_translations() - Check translations in the PPD file. + * show_conflicts() - Show option conflicts in a PPD file. + * test_raster() - Test PostScript commands for raster printers. + * usage() - Show program usage... + * valid_utf8() - Check whether a string contains valid UTF-8 text. */ /* @@ -118,7 +130,6 @@ main(int argc, /* I - Number of command-line args */ int ppdversion; /* PPD spec version in PPD file */ ppd_status_t error; /* Status of ppdOpen*() */ int line; /* Line number for error */ - struct stat statbuf; /* File information */ char *root; /* Root directory */ int xdpi, /* X resolution */ ydpi; /* Y resolution */ @@ -1370,7 +1381,7 @@ main(int argc, /* I - Number of command-line args */ attr != NULL; attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL)) { - if ((!attr->value || stat(attr->value, &statbuf)) && verbose >= 0) + if ((!attr->value || access(attr->value, 0)) && verbose >= 0) _cupsLangPrintf(stdout, _(" WARN Missing " "APDialogExtension file \"%s\"\n"), attr->value ? attr->value : ""); @@ -1384,7 +1395,7 @@ main(int argc, /* I - Number of command-line args */ attr != NULL; attr = ppdFindNextAttr(ppd, "APPrinterIconPath", NULL)) { - if ((!attr->value || stat(attr->value, &statbuf)) && verbose >= 0) + if ((!attr->value || access(attr->value, 0)) && verbose >= 0) _cupsLangPrintf(stdout, _(" WARN Missing " "APPrinterIconPath file \"%s\"\n"), attr->value ? attr->value : ""); diff --git a/test/5.1-lpadmin.sh b/test/5.1-lpadmin.sh index 6288c47d6..2e054ea47 100644 --- a/test/5.1-lpadmin.sh +++ b/test/5.1-lpadmin.sh @@ -16,8 +16,8 @@ echo "Add Printer Test" echo "" -echo " lpadmin -p Test3 -v file:/dev/null -E -m deskjet.ppd" -../systemv/lpadmin -p Test3 -v file:/dev/null -E -m deskjet.ppd 2>&1 +echo " lpadmin -p Test3 -v file:/dev/null -E -m drv:///sample.drv/DESKJET.PPD" +../systemv/lpadmin -p Test3 -v file:/dev/null -E -m drv:///sample.drv/DESKJET.PPD 2>&1 if test $? != 0; then echo " FAILED" exit 1 diff --git a/test/run-stp-tests.sh b/test/run-stp-tests.sh index 967677860..b05c7ab8b 100755 --- a/test/run-stp-tests.sh +++ b/test/run-stp-tests.sh @@ -212,7 +212,9 @@ mkdir /tmp/cups-$user/bin/filter mkdir /tmp/cups-$user/certs mkdir /tmp/cups-$user/share mkdir /tmp/cups-$user/share/banners +mkdir /tmp/cups-$user/share/drv mkdir /tmp/cups-$user/share/model +mkdir /tmp/cups-$user/share/ppdc mkdir /tmp/cups-$user/interfaces mkdir /tmp/cups-$user/log mkdir /tmp/cups-$user/ppd @@ -223,6 +225,7 @@ mkdir /tmp/cups-$user/ssl ln -s $root/backend/http /tmp/cups-$user/bin/backend ln -s $root/backend/ipp /tmp/cups-$user/bin/backend ln -s $root/backend/lpd /tmp/cups-$user/bin/backend +ln -s $root/backend/mdns /tmp/cups-$user/bin/backend ln -s $root/backend/parallel /tmp/cups-$user/bin/backend ln -s $root/backend/serial /tmp/cups-$user/bin/backend ln -s $root/backend/snmp /tmp/cups-$user/bin/backend @@ -233,6 +236,7 @@ ln -s $root/ppdc/drv /tmp/cups-$user/bin/driver ln -s $root/monitor /tmp/cups-$user/bin ln -s $root/notifier /tmp/cups-$user/bin ln -s $root/scheduler /tmp/cups-$user/bin/daemon +ln -s $root/filter/commandtops /tmp/cups-$user/bin/filter ln -s $root/filter/hpgltops /tmp/cups-$user/bin/filter ln -s $root/filter/pstops /tmp/cups-$user/bin/filter ln -s $root/filter/rastertoepson /tmp/cups-$user/bin/filter @@ -249,7 +253,9 @@ ln -s $root/data /tmp/cups-$user/share/charmaps ln -s $root/data /tmp/cups-$user/share/charsets ln -s $root/data /tmp/cups-$user/share ln -s $root/fonts /tmp/cups-$user/share -ln -s $root/ppd/*.ppd /tmp/cups-$user/share/model +ln -s $root/ppdc/sample.drv /tmp/cups-$user/share/drv +ln -s $root/data/*.h /tmp/cups-$user/share/ppdc +ln -s $root/data/*.defs /tmp/cups-$user/share/ppdc ln -s $root/templates /tmp/cups-$user/share if test $ssltype != 0; then @@ -308,7 +314,7 @@ MaxLogSize 0 AccessLog /tmp/cups-$user/log/access_log ErrorLog /tmp/cups-$user/log/error_log PageLog /tmp/cups-$user/log/page_log -LogLevel debug +LogLevel debug2 PreserveJobHistory Yes @@ -549,10 +555,11 @@ echo "Test Summary" echo "" echo "

      Summary

      " >>$strfile -# Pages printed on Test1 +# Pages printed on Test1 (within 1 page for timing-dependent cancel issues) count=`grep '^Test1 ' /tmp/cups-$user/log/page_log | awk 'BEGIN{count=0}{count=count+$7}END{print count}'` expected=`expr $pjobs \* 2 + 35` -if test $count != $expected; then +expected2=`expr $expected + 1` +if test $count != $expected -a $count != $expected2; then echo "FAIL: Printer 'Test1' produced $count page(s), expected $expected." echo "

      FAIL: Printer 'Test1' produced $count page(s), expected $expected.

      " >>$strfile fail=`expr $fail + 1` @@ -692,9 +699,9 @@ fi # Debug2 log messages count=`grep '^d ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'` -if test $count != 0; then - echo "FAIL: $count debug2 messages, expected 0." - echo "

      FAIL: $count debug2 messages, expected 0.

      " >>$strfile +if test $count = 0; then + echo "FAIL: $count debug2 messages, expected more than 0." + echo "

      FAIL: $count debug2 messages, expected more than 0.

      " >>$strfile fail=`expr $fail + 1` else echo "PASS: $count debug2 messages." @@ -709,7 +716,7 @@ echo "" >>$strfile echo "

      error_log

      " >>$strfile echo "
      " >>$strfile
      -sed -e '1,$s/&/&/g' -e '1,$s/>$strfile
      +grep -v '^[dD]' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&/g' -e '1,$s/>$strfile
       echo "
      " >>$strfile echo "

      page_log

      " >>$strfile -- 2.39.2