]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Merge CUPS 1.4svn-r7524.
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Thu, 1 May 2008 21:18:10 +0000 (21:18 +0000)
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Thu, 1 May 2008 21:18:10 +0000 (21:18 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@733 a1ca3aef-8c08-0410-bb20-df032aa958be

43 files changed:
CHANGES.txt
Makedefs.in
backend/Dependencies
backend/Makefile
backend/backend-private.h
backend/ipp.c
backend/lpd.c
backend/mdns.c [new file with mode: 0644]
backend/network.c [new file with mode: 0644]
backend/runloop.c
backend/snmp-supplies.c
backend/snmp.c
backend/socket.c
backend/testsupplies.c
config-scripts/cups-compiler.m4
config-scripts/cups-dnssd.m4
cups/Dependencies
cups/Makefile
cups/api-filter.shtml
cups/libcups.exp
cups/libcups_s.exp
cups/snmp-private.h [new file with mode: 0644]
cups/snmp.c
cups/snmp.h [deleted file]
cups/testfile.c
cups/testsnmp.c
doc/cups.css
doc/help/api-filedir.html
doc/help/api-filter.html
filter/Makefile
filter/commandtops.c [new file with mode: 0644]
packaging/cups.list.in
packaging/cups.spec.in
scheduler/dirsvc.c
scheduler/dirsvc.h
scheduler/main.c
scheduler/printers.c
scheduler/printers.h
scheduler/sysman.c
scripting/php/Makefile
systemv/cupstestppd.c
test/5.1-lpadmin.sh
test/run-stp-tests.sh

index 6f6e3ed92321cb472aff0388f06081390fa26d5c..bb2c8d68e8ea9c9f1841b86dae34e09b39daa1ee 100644 (file)
@@ -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
index d4a8929d634071ab2c74c285f83b570b4c1aeb0e..27fc8351e7a4c80e0a3d51cc818b009120ab2418 100644 (file)
@@ -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@
 
index 26652c8443a2cedeb20093726e5291c111fa15ab..3925daacd9aa1f3e6664a8d055ef78cbefbf4eb9 100644 (file)
@@ -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
index c8af61b381838e730aaffd6ac1613363602af58b..45bf74c25ef6317f433d7928d6238e50f6f9fea0 100644 (file)
 
 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)
 
 
 #
index 9bbfa1e50e90ee9c65e313dd72cf632bd63589dd..1a295b9a53da5f00f13b751ee9f336f6c56b5150 100644 (file)
@@ -28,7 +28,7 @@
 #  include <cups/cups.h>
 #  include <cups/debug.h>
 #  include <cups/i18n.h>
-#  include <cups/snmp.h>
+#  include <cups/snmp-private.h>
 #  include <stdlib.h>
 #  include <errno.h>
 #  include <cups/string.h>
@@ -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
 }
index 1feb6fdb1d70fc48e0dcd625c4764ac19011e132..4704741de49f9091e6b04a83b3b213d0a974e9cb 100644 (file)
  */
 
 #include <cups/http-private.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
+#include "backend-private.h"
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <cups/backend.h>
-#include <cups/cups.h>
-#include <cups/language.h>
-#include <cups/i18n.h>
-#include <cups/string.h>
-#include <signal.h>
 #include <sys/wait.h>
 
 /*
@@ -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...
   */
index 100868f980522367399827bc5d8961e9b71d1166..8f173d27bb10d39d6580f4a5e8778b7271729aff 100644 (file)
  * Include necessary headers.
  */
 
-#include <cups/backend.h>
 #include <cups/http-private.h>
-#include <cups/cups.h>
-#include <cups/i18n.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include "backend-private.h"
 #include <stdarg.h>
-#include <ctype.h>
-#include <cups/string.h>
-#include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <signal.h>
 
 #ifdef WIN32
 #  include <winsock.h>
@@ -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 (file)
index 0000000..4c12b50
--- /dev/null
@@ -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 <cups/array.h>
+#include <dns_sd.h>
+
+
+/*
+ * 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 <cups/array.h>
+#include <dns_sd.h>
+
+
+/*
+ * 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 (file)
index 0000000..9827c7d
--- /dev/null
@@ -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 <limits.h>
+#ifdef __hpux
+#  include <sys/time.h>
+#else
+#  include <sys/select.h>
+#endif /* __hpux */
+#ifdef HAVE_DNSSD
+#  include <dns_sd.h>
+#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 <limits.h>
+#ifdef __hpux
+#  include <sys/time.h>
+#else
+#  include <sys/select.h>
+#endif /* __hpux */
+#ifdef HAVE_DNSSD
+#  include <dns_sd.h>
+#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$".
+ */
index bbf565d5fee73cdc742cd1eabbb9052da3d207ad..53c6ac7f101d6fbfad2fe2f91cb7c62231c05537 100644 (file)
@@ -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.
  */
index 806b67f2519aeb556372adece67e8b0e4e3ca618..ef68dbcd0b36bd15ac191005e4ea081ce81f1d8e 100644 (file)
@@ -141,8 +141,8 @@ backendSNMPSupplies(
   if (!httpAddrEqual(addr, &current_addr))
     backend_init_supplies(snmp_fd, addr);
   else if (num_supplies > 0)
-    cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
-                cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel, 500,
+    _cupsSNMPWalk(snmp_fd, &current_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, &current_addr, CUPS_SNMP_VERSION_1,
-                cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry, 500,
+    _cupsSNMPWalk(snmp_fd, &current_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, &current_addr, CUPS_SNMP_VERSION_1,
-               cupsSNMPDefaultCommunity(), prtMarkerColorantValue, 500,
+  _cupsSNMPWalk(snmp_fd, &current_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...
index 4e0cd1d6f764d40f400d8e0d1584e6f4f4d82409..0364ee2a2313b48ed0657348bedf44039f766f28 100644 (file)
@@ -48,7 +48,6 @@
 #include "backend-private.h"
 #include <cups/array.h>
 #include <cups/file.h>
-#include <cups/snmp.h>
 #include <cups/http-private.h>
 #include <regex.h>
 
 /*
  * 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);
     }
 
index 140061151c2ad49cbcc451eb9b809f7c799057a0..77a5802749da2261a757b2fa08e49029f94f073d 100644 (file)
@@ -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;
     }
 
index 1a8246abc67d943df344111b0478b1a009a02e74..c380f280f36e9668f4e052b6adf3a250855e6c7d 100644 (file)
@@ -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);
index 4b1f83c8c8ec77b4a327cd121502387ce1f10e47..004a0990c666ed14669bef9c2b541befc959522b 100644 (file)
@@ -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
 
index eaab2c194d097423439289e7e78d8962e35a6e99..28deb75838143a07b3459147a35c48647e4ec753 100644 (file)
@@ -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$".
index 9f00bdad743f4dc0ccd7ea9b8742321277ed678d..eb3def7ea29743d7e7c6ab119e626aee8eeb3901 100644 (file)
@@ -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
index 3ea42068148f497a1d9da3e3696c1ab36b65b10e..95a3769f8e3d3d708ff359f55b9d19ec03ace785 100644 (file)
@@ -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
 
 
 #
index f5b6b8cf2c622ebbfa5450b3363e6f7d39204229..60f28d32f127b8e0763bc119dea3ade5ef48132d 100644 (file)
@@ -343,6 +343,9 @@ if (!<a href="#cupsSideChannelRead">cupsSideChannelRead</a>(&amp;command, &amp;s
 
 <h3><a name="SNMP">Doing SNMP Queries with Network Printers</a></h3>
 
+<p>Re-write for side-channel-based SNMP queries.</p>
+
+<!--
 <p>The Simple Network Management Protocol (SNMP) allows you to get the current
 status, page counter, and supply levels from most network printers. Every
 piece of information is associated with an Object Identifier (OID), and
@@ -415,3 +418,4 @@ void *my_data;
 <a href="#cupsSNMPWalk">cupsSNMPWalk</a>(snmp, &amp;(host->addr), CUPS_SNMP_VERSION_1,
                <a href="#cupsSNMPDefaultCommunity">cupsSNMPDefaultCommunity</a>(), printer_mib_oid, my_callback, my_data);
 </pre>
+-->
\ No newline at end of file
index 4a689e384f0b83c9603265627dcf26c0c3604819..bb12c552a810c5de0210b66917f8109d59681f14 100644 (file)
@@ -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
index 261f2ab86ab64216129f29083b750ae1e1844f22..a556cdb891b7ecbe6f753ef2bb987ac1f3058a5b 100644 (file)
@@ -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 (file)
index 0000000..364913e
--- /dev/null
@@ -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$".
+ */
index 054b633e1de5fbc723c7a2b247964b95a33dfb0d..2fbaf57819657d3d4f0ea7492fb2c2fd0fc725d2 100644 (file)
  *
  * 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 <errno.h>
 #ifdef HAVE_POLL
 #  include <sys/poll.h>
@@ -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 (file)
index 8e5dfa5..0000000
+++ /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$".
- */
index 4f0f39e109ccc82dc6a0b40e198aff7dac5df0ca..d8a1b88c9535d7c57879684471921087e6bfa302 100644 (file)
@@ -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 <zlib.h>
 #endif /* HAVE_LIBZ */
+#include <unistd.h>
 #include <fcntl.h>
 
 
index eb47254a1d686079024f816080929874004d28d7..2e0ef0d3d93751f4c73ad03d562525f6f08de9bf 100644 (file)
@@ -29,7 +29,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #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 ++)
index 77fefb04488d07639e1594908b08bfc0c887d7e9..faaef123a1b9b3cd6458396c72776bce92a7d98c 100644 (file)
@@ -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... */
index ff5b2e1a9b8017f5df51c9fb5fd4f11bee20c371..cf466c39cefb71591cda9598c70d6c8e8fc32793 100644 (file)
@@ -634,8 +634,9 @@ int cupsFileNumber (<br>
 existing file, &quot;a&quot; to append to an existing file or create a new file,
 or &quot;s&quot; to open a socket connection.<br>
 <br>
-When opening for writing (&quot;w&quot;) or appending (&quot;a&quot;), an optional number from
-1 to 9 can be supplied which enables Flate compression of the file.<br>
+When opening for writing (&quot;w&quot;), an optional number from 1 to 9 can be
+supplied which enables Flate compression of the file.  Compression is
+not supported for the &quot;a&quot; (append) mode.<br>
 <br>
 When opening a socket connection, the filename is a string of the form
 &quot;address:port&quot; or &quot;hostname:port&quot;. The socket will make an IPv4 or IPv6
@@ -660,11 +661,12 @@ a choice.
 <h4 class="returnvalue">Return Value</h4>
 <p class="description">CUPS file or <code>NULL</code> if the file could not be opened</p>
 <h4 class="discussion">Discussion</h4>
-<p class="discussion">The &quot;mode&quot; parameter can be &quot;r&quot; to read, &quot;a&quot; or &quot;w&quot; to write, or &quot;s&quot;
-to treat the file descriptor as a bidirectional socket connection.<br>
+<p class="discussion">The &quot;mode&quot; parameter can be &quot;r&quot; to read, &quot;w&quot; to write, &quot;a&quot; to append,
+or &quot;s&quot; to treat the file descriptor as a bidirectional socket connection.<br>
 <br>
-When opening for writing (&quot;w&quot;) or appending (&quot;a&quot;), an optional number from
-1 to 9 can be supplied which enables Flate compression of the file.
+When opening for writing (&quot;w&quot;), an optional number from 1 to 9 can be
+supplied which enables Flate compression of the file.  Compression is
+not supported for the &quot;a&quot; (append) mode.
 
 </p>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.2&nbsp;</span><a name="cupsFilePeekChar">cupsFilePeekChar</a></h3>
index ed24e8c6e279493775ee49eb969795322d58c1ce..5febe8a868524322ba0cd7aea84ff82dc9834aa4 100644 (file)
@@ -309,40 +309,18 @@ div.contents ul.subcontents li {
 <li><a href="#cupsBackChannelRead" title="Read data from the backchannel.">cupsBackChannelRead</a></li>
 <li><a href="#cupsBackChannelWrite" title="Write data to the backchannel.">cupsBackChannelWrite</a></li>
 <li><a href="#cupsBackendDeviceURI" title="Get the device URI for a backend.">cupsBackendDeviceURI</a></li>
-<li><a href="#cupsSNMPClose" title="Close a SNMP socket.">cupsSNMPClose</a></li>
-<li><a href="#cupsSNMPCopyOID" title="Copy an OID.">cupsSNMPCopyOID</a></li>
-<li><a href="#cupsSNMPDefaultCommunity" title="Get the default SNMP community name.">cupsSNMPDefaultCommunity</a></li>
-<li><a href="#cupsSNMPIsOID" title="Test whether a SNMP response contains the specified OID.">cupsSNMPIsOID</a></li>
-<li><a href="#cupsSNMPIsOIDPrefixed" title="Test whether a SNMP response uses the specified
-OID prefix.">cupsSNMPIsOIDPrefixed</a></li>
-<li><a href="#cupsSNMPOpen" title="Open a SNMP socket.">cupsSNMPOpen</a></li>
-<li><a href="#cupsSNMPRead" title="Read and parse a SNMP response.">cupsSNMPRead</a></li>
-<li><a href="#cupsSNMPSetDebug" title="Enable/disable debug logging to stderr.">cupsSNMPSetDebug</a></li>
-<li><a href="#cupsSNMPWalk" title="Enumerate a group of OIDs.">cupsSNMPWalk</a></li>
-<li><a href="#cupsSNMPWrite" title="Send an SNMP query packet.">cupsSNMPWrite</a></li>
 <li><a href="#cupsSideChannelDoRequest" title="Send a side-channel command to a backend and wait for a response.">cupsSideChannelDoRequest</a></li>
 <li><a href="#cupsSideChannelRead" title="Read a side-channel message.">cupsSideChannelRead</a></li>
 <li><a href="#cupsSideChannelWrite" title="Write a side-channel message.">cupsSideChannelWrite</a></li>
 </ul>
 <li><a href="#TYPES">Data Types</a><ul class="code">
-       <li><a href="#cups_asn1_t" title="ASN1 request/object types">cups_asn1_t</a></li>
        <li><a href="#cups_backend_t" title="Backend exit codes">cups_backend_t</a></li>
        <li><a href="#cups_sc_bidi_t" title="Bidirectional capabilities">cups_sc_bidi_t</a></li>
        <li><a href="#cups_sc_command_t" title="Request command codes">cups_sc_command_t</a></li>
        <li><a href="#cups_sc_state_t" title="Printer state bits">cups_sc_state_t</a></li>
        <li><a href="#cups_sc_status_t" title="Response status codes">cups_sc_status_t</a></li>
-       <li><a href="#cups_snmp_cb_t" title="Prototypes...">cups_snmp_cb_t</a></li>
-       <li><a href="#cups_snmp_t" title="SNMP data packet">cups_snmp_t</a></li>
-</ul></li>
-<li><a href="#STRUCTURES">Structures</a><ul class="code">
-       <li><a href="#cups_snmp_hexstring_s" title="Hex-STRING value">cups_snmp_hexstring_s</a></li>
-       <li><a href="#cups_snmp_s" title="SNMP data packet">cups_snmp_s</a></li>
-</ul></li>
-<li><a href="#UNIONS">Unions</a><ul class="code">
-       <li><a href="#cups_snmp_value_u" title="Object value">cups_snmp_value_u</a></li>
 </ul></li>
 <li><a href="#ENUMERATIONS">Constants</a><ul class="code">
-       <li><a href="#cups_asn1_e" title="ASN1 request/object types">cups_asn1_e</a></li>
        <li><a href="#cups_backend_e" title="Backend exit codes">cups_backend_e</a></li>
        <li><a href="#cups_sc_bidi_e" title="Bidirectional capabilities">cups_sc_bidi_e</a></li>
        <li><a href="#cups_sc_command_e" title="Request command codes">cups_sc_command_e</a></li>
@@ -695,6 +673,9 @@ if (!<a href="#cupsSideChannelRead">cupsSideChannelRead</a>(&amp;command, &amp;s
 
 <h3><a name="SNMP">Doing SNMP Queries with Network Printers</a></h3>
 
+<p>Re-write for side-channel-based SNMP queries.</p>
+
+<!--
 <p>The Simple Network Management Protocol (SNMP) allows you to get the current
 status, page counter, and supply levels from most network printers. Every
 piece of information is associated with an Object Identifier (OID), and
@@ -767,7 +748,7 @@ void *my_data;
 <a href="#cupsSNMPWalk">cupsSNMPWalk</a>(snmp, &amp;(host->addr), CUPS_SNMP_VERSION_1,
                <a href="#cupsSNMPDefaultCommunity">cupsSNMPDefaultCommunity</a>(), printer_mib_oid, my_callback, my_data);
 </pre>
-<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+--><h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.2&nbsp;</span><a name="cupsBackChannelRead">cupsBackChannelRead</a></h3>
 <p class="description">Read data from the backchannel.</p>
 <p class="code">
@@ -838,219 +819,6 @@ const char *cupsBackendDeviceURI (<br>
 function returns the device URI passed in the DEVICE_URI environment
 variable or the device URI passed in argv[0], whichever is found
 first.</p>
-<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSNMPClose">cupsSNMPClose</a></h3>
-<p class="description">Close a SNMP socket.</p>
-<p class="code">
-void cupsSNMPClose (<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int fd<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>fd</dt>
-<dd class="description">SNMP socket file descriptor</dd>
-</dl>
-<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSNMPCopyOID">cupsSNMPCopyOID</a></h3>
-<p class="description">Copy an OID.</p>
-<p class="code">
-int *cupsSNMPCopyOID (<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int *dst,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;const int *src,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int dstsize<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>dst</dt>
-<dd class="description">Destination OID</dd>
-<dt>src</dt>
-<dd class="description">Source OID</dd>
-<dt>dstsize</dt>
-<dd class="description">Number of integers in dst</dd>
-</dl>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">New OID</p>
-<h4 class="discussion">Discussion</h4>
-<p class="discussion">The array pointed to by &quot;src&quot; is terminated by the value -1.
-
-</p>
-<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSNMPDefaultCommunity">cupsSNMPDefaultCommunity</a></h3>
-<p class="description">Get the default SNMP community name.</p>
-<p class="code">
-const char *cupsSNMPDefaultCommunity (void);</p>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">Default community name</p>
-<h4 class="discussion">Discussion</h4>
-<p class="discussion">The default community name is the first community name found in the
-snmp.conf file. If no community name is defined there, &quot;public&quot; is used.
-
-</p>
-<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSNMPIsOID">cupsSNMPIsOID</a></h3>
-<p class="description">Test whether a SNMP response contains the specified OID.</p>
-<p class="code">
-int cupsSNMPIsOID (<br>
-&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_snmp_t">cups_snmp_t</a> *packet,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;const int *oid<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>packet</dt>
-<dd class="description">Response packet</dd>
-<dt>oid</dt>
-<dd class="description">OID</dd>
-</dl>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">1 if equal, 0 if not equal</p>
-<h4 class="discussion">Discussion</h4>
-<p class="discussion">The array pointed to by &quot;oid&quot; is terminated by the value -1.
-
-</p>
-<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSNMPIsOIDPrefixed">cupsSNMPIsOIDPrefixed</a></h3>
-<p class="description">Test whether a SNMP response uses the specified
-OID prefix.</p>
-<p class="code">
-int cupsSNMPIsOIDPrefixed (<br>
-&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_snmp_t">cups_snmp_t</a> *packet,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;const int *prefix<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>packet</dt>
-<dd class="description">Response packet</dd>
-<dt>prefix</dt>
-<dd class="description">OID prefix</dd>
-</dl>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">1 if prefixed, 0 if not prefixed</p>
-<h4 class="discussion">Discussion</h4>
-<p class="discussion">The array pointed to by &quot;prefix&quot; is terminated by the value -1.
-
-</p>
-<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSNMPOpen">cupsSNMPOpen</a></h3>
-<p class="description">Open a SNMP socket.</p>
-<p class="code">
-int cupsSNMPOpen (<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int family<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>family</dt>
-<dd class="description">Address family - <code>AF_INET</code> or <code>AF_INET6</code></dd>
-</dl>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">SNMP socket file descriptor</p>
-<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSNMPRead">cupsSNMPRead</a></h3>
-<p class="description">Read and parse a SNMP response.</p>
-<p class="code">
-<a href="#cups_snmp_t">cups_snmp_t</a> *cupsSNMPRead (<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int fd,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_snmp_t">cups_snmp_t</a> *packet,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;double timeout<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>fd</dt>
-<dd class="description">SNMP socket file descriptor</dd>
-<dt>packet</dt>
-<dd class="description">SNMP packet buffer</dd>
-<dt>timeout</dt>
-<dd class="description">Timeout in seconds</dd>
-</dl>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">SNMP packet or <code>NULL</code> if none</p>
-<h4 class="discussion">Discussion</h4>
-<p class="discussion">If &quot;timeout&quot; is negative, <code>cupsSNMPRead</code> will wait for a response
-indefinitely.
-
-</p>
-<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSNMPSetDebug">cupsSNMPSetDebug</a></h3>
-<p class="description">Enable/disable debug logging to stderr.</p>
-<p class="code">
-void cupsSNMPSetDebug (<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int level<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>level</dt>
-<dd class="description">1 to enable debug output, 0 otherwise</dd>
-</dl>
-<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSNMPWalk">cupsSNMPWalk</a></h3>
-<p class="description">Enumerate a group of OIDs.</p>
-<p class="code">
-int cupsSNMPWalk (<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int fd,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;http_addr_t *address,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int version,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;const char *community,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;const int *prefix,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;double timeout,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_snmp_cb_t">cups_snmp_cb_t</a> cb,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;void *data<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>fd</dt>
-<dd class="description">SNMP socket</dd>
-<dt>address</dt>
-<dd class="description">Address to query</dd>
-<dt>version</dt>
-<dd class="description">SNMP version</dd>
-<dt>community</dt>
-<dd class="description">Community name</dd>
-<dt>prefix</dt>
-<dd class="description">OID prefix</dd>
-<dt>timeout</dt>
-<dd class="description">Timeout for each response in seconds</dd>
-<dt>cb</dt>
-<dd class="description">Function to call for each response</dd>
-<dt>data</dt>
-<dd class="description">User data pointer that is passed to the callback function</dd>
-</dl>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">Number of OIDs found or -1 on error</p>
-<h4 class="discussion">Discussion</h4>
-<p class="discussion">This function queries all of the OIDs with the specified OID prefix,
-calling the &quot;cb&quot; function for every response that is received.<br>
-<br>
-The array pointed to by &quot;prefix&quot; is terminated by the value -1.<br>
-<br>
-If &quot;timeout&quot; is negative, <code>cupsSNMPWalk</code> will wait for a response
-indefinitely.
-
-</p>
-<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSNMPWrite">cupsSNMPWrite</a></h3>
-<p class="description">Send an SNMP query packet.</p>
-<p class="code">
-int cupsSNMPWrite (<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int fd,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;http_addr_t *address,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int version,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;const char *community,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_asn1_t">cups_asn1_t</a> request_type,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;const unsigned request_id,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;const int *oid<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>fd</dt>
-<dd class="description">SNMP socket</dd>
-<dt>address</dt>
-<dd class="description">Address to send to</dd>
-<dt>version</dt>
-<dd class="description">SNMP version</dd>
-<dt>community</dt>
-<dd class="description">Community name</dd>
-<dt>request_type</dt>
-<dd class="description">Request type</dd>
-<dt>request_id</dt>
-<dd class="description">Request ID</dd>
-<dt>oid</dt>
-<dd class="description">OID</dd>
-</dl>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">1 on success, 0 on error</p>
-<h4 class="discussion">Discussion</h4>
-<p class="discussion">The array pointed to by &quot;oid&quot; is terminated by the value -1.
-
-</p>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.3&nbsp;</span><a name="cupsSideChannelDoRequest">cupsSideChannelDoRequest</a></h3>
 <p class="description">Send a side-channel command to a backend and wait for a response.</p>
 <p class="code">
@@ -1152,11 +920,6 @@ responses to a filter, driver, or port monitor program.
 
 </p>
 <h2 class="title"><a name="TYPES">Data Types</a></h2>
-<h3 class="typedef"><a name="cups_asn1_t">cups_asn1_t</a></h3>
-<p class="description">ASN1 request/object types</p>
-<p class="code">
-typedef enum <a href="#cups_asn1_e">cups_asn1_e</a> cups_asn1_t;
-</p>
 <h3 class="typedef"><a name="cups_backend_t">cups_backend_t</a></h3>
 <p class="description">Backend exit codes</p>
 <p class="code">
@@ -1182,138 +945,7 @@ typedef enum <a href="#cups_sc_state_e">cups_sc_state_e</a> cups_sc_state_t;
 <p class="code">
 typedef enum <a href="#cups_sc_status_e">cups_sc_status_e</a> cups_sc_status_t;
 </p>
-<h3 class="typedef"><a name="cups_snmp_cb_t">cups_snmp_cb_t</a></h3>
-<p class="description">Prototypes...</p>
-<p class="code">
-typedef void (*cups_snmp_cb_t)(<a href="#cups_snmp_t">cups_snmp_t</a> *packet, void *data);
-</p>
-<h3 class="typedef"><a name="cups_snmp_t">cups_snmp_t</a></h3>
-<p class="description">SNMP data packet</p>
-<p class="code">
-typedef struct <a href="#cups_snmp_s">cups_snmp_s</a> cups_snmp_t;
-</p>
-<h2 class="title"><a name="STRUCTURES">Structures</a></h2>
-<h3 class="struct"><a name="cups_snmp_hexstring_s">cups_snmp_hexstring_s</a></h3>
-<p class="description">Hex-STRING value</p>
-<p class="code">struct cups_snmp_hexstring_s {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;unsigned char bytes[CUPS_SNMP_MAX_STRING];<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int num_bytes;<br>
-};</p>
-<h4 class="members">Members</h4>
-<dl>
-<dt>bytes[CUPS_SNMP_MAX_STRING] </dt>
-<dd class="description">Bytes in string</dd>
-<dt>num_bytes </dt>
-<dd class="description">Number of bytes</dd>
-</dl>
-<h3 class="struct"><a name="cups_snmp_s">cups_snmp_s</a></h3>
-<p class="description">SNMP data packet</p>
-<p class="code">struct cups_snmp_s {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;http_addr_t address;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;char community[CUPS_SNMP_MAX_STRING];<br>
-&nbsp;&nbsp;&nbsp;&nbsp;const char *error;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int error_index;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int error_status;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int object_name[CUPS_SNMP_MAX_OID];<br>
-&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_asn1_t">cups_asn1_t</a> object_type;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;union <a href="#cups_snmp_value_u">cups_snmp_value_u</a> object_value;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int request_id;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_asn1_t">cups_asn1_t</a> request_type;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int version;<br>
-};</p>
-<h4 class="members">Members</h4>
-<dl>
-<dt>address </dt>
-<dd class="description">Source address</dd>
-<dt>community[CUPS_SNMP_MAX_STRING] </dt>
-<dd class="description">Community name</dd>
-<dt>error </dt>
-<dd class="description">Encode/decode error</dd>
-<dt>error_index </dt>
-<dd class="description">error-index value</dd>
-<dt>error_status </dt>
-<dd class="description">error-status value</dd>
-<dt>object_name[CUPS_SNMP_MAX_OID] </dt>
-<dd class="description">object-name value</dd>
-<dt>object_type </dt>
-<dd class="description">object-value type</dd>
-<dt>object_value </dt>
-<dd class="description">object-value value</dd>
-<dt>request_id </dt>
-<dd class="description">request-id value</dd>
-<dt>request_type </dt>
-<dd class="description">Request type</dd>
-<dt>version </dt>
-<dd class="description">Version number</dd>
-</dl>
-<h2 class="title"><a name="UNIONS">Unions</a></h2>
-<h3 class="union"><a name="cups_snmp_value_u">cups_snmp_value_u</a></h3>
-<p class="description">Object value</p>
-<p class="code">union cups_snmp_value_u {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int boolean;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;unsigned counter;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;unsigned gauge;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;struct <a href="#cups_snmp_hexstring_s">cups_snmp_hexstring_s</a> hex_string;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int integer;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;int oid[CUPS_SNMP_MAX_OID];<br>
-&nbsp;&nbsp;&nbsp;&nbsp;char string[CUPS_SNMP_MAX_STRING];<br>
-&nbsp;&nbsp;&nbsp;&nbsp;unsigned timeticks;<br>
-};</p>
-<h4 class="members">Members</h4>
-<dl>
-<dt>boolean </dt>
-<dd class="description">Boolean value</dd>
-<dt>counter </dt>
-<dd class="description">Counter value</dd>
-<dt>gauge </dt>
-<dd class="description">Gauge value</dd>
-<dt>hex_string </dt>
-<dd class="description">Hex string value</dd>
-<dt>integer </dt>
-<dd class="description">Integer value</dd>
-<dt>oid[CUPS_SNMP_MAX_OID] </dt>
-<dd class="description">OID value</dd>
-<dt>string[CUPS_SNMP_MAX_STRING] </dt>
-<dd class="description">String value</dd>
-<dt>timeticks </dt>
-<dd class="description">Timeticks  value</dd>
-</dl>
 <h2 class="title"><a name="ENUMERATIONS">Constants</a></h2>
-<h3 class="enumeration"><a name="cups_asn1_e">cups_asn1_e</a></h3>
-<p class="description">ASN1 request/object types</p>
-<h4 class="constants">Constants</h4>
-<dl>
-<dt>CUPS_ASN1_BIT_STRING </dt>
-<dd class="description">BIT STRING</dd>
-<dt>CUPS_ASN1_BOOLEAN </dt>
-<dd class="description">BOOLEAN</dd>
-<dt>CUPS_ASN1_COUNTER </dt>
-<dd class="description">32-bit unsigned aka Counter32</dd>
-<dt>CUPS_ASN1_END_OF_CONTENTS </dt>
-<dd class="description">End-of-contents</dd>
-<dt>CUPS_ASN1_GAUGE </dt>
-<dd class="description">32-bit unsigned aka Gauge32</dd>
-<dt>CUPS_ASN1_GET_NEXT_REQUEST </dt>
-<dd class="description">GetNextRequest-PDU</dd>
-<dt>CUPS_ASN1_GET_REQUEST </dt>
-<dd class="description">GetRequest-PDU</dd>
-<dt>CUPS_ASN1_GET_RESPONSE </dt>
-<dd class="description">GetResponse-PDU</dd>
-<dt>CUPS_ASN1_HEX_STRING </dt>
-<dd class="description">Binary string aka Hex-STRING</dd>
-<dt>CUPS_ASN1_INTEGER </dt>
-<dd class="description">INTEGER or ENUMERATION</dd>
-<dt>CUPS_ASN1_NULL_VALUE </dt>
-<dd class="description">NULL VALUE</dd>
-<dt>CUPS_ASN1_OCTET_STRING </dt>
-<dd class="description">OCTET STRING</dd>
-<dt>CUPS_ASN1_OID </dt>
-<dd class="description">OBJECT IDENTIFIER</dd>
-<dt>CUPS_ASN1_SEQUENCE </dt>
-<dd class="description">SEQUENCE</dd>
-<dt>CUPS_ASN1_TIMETICKS </dt>
-<dd class="description">32-bit unsigned aka Timeticks32</dd>
-</dl>
 <h3 class="enumeration"><a name="cups_backend_e">cups_backend_e</a></h3>
 <p class="description">Backend exit codes</p>
 <h4 class="constants">Constants</h4>
index 6bd1f556e6bfe7cf3e0d18389642363ddc86d43c..09df33085ec3e400dce7281d8dce1cbf1160cf2c 100644 (file)
@@ -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 (file)
index 0000000..ea7caf1
--- /dev/null
@@ -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 <cups/cups.h>
+#include <cups/string.h>
+#include <cups/sidechannel.h>
+
+
+/*
+ * 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$".
+ */
index 56ca4a937b2de4ef9d7f9692362f7c8690997873..ac535a2c7599c6263ca5823aa5a0f33ca72923dc 100644 (file)
@@ -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
index 401de885ac0c10c9e3374f5b50f7f24ba59fd027..8deff15b50d29e54b9c0ddf9806f61bec7f9df50 100644 (file)
@@ -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 
index 5bc61f68019ddf63c153857b97e150628d4bffa7..8af4571e83b60cf389851b2657af6a15eeec9832 100644 (file)
  *
  * 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 "<printer-info> @ <computer name>"...
+  */
 
-    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 "<printer-info> @ <computer name>"...
-  */
+      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;
index 5ff06c3eea2e36351df95ca44d7fbd39ee314cd6..16693c293c3a7d3d29b2dbfc24d9fb75d388ed5d 100644 (file)
@@ -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);
index 4c7c697e9cfb7f07d2f751c6bc0dacd0d8a47d57..f5d408e78ad90c76fc12d94ab17017af97bade8e 100644 (file)
@@ -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!",
index 11abd6b8d24d97d1f26a2ebb7b479e1c5000c366..8cd2e6e4a5a7c545027c1e9c05e2e97d1b8cbbc2 100644 (file)
@@ -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
index a7fecdad5f60b251917e876baaeda77cc3be31c0..d28789bf16c1a74b1ff3e1a01e7cef25b65c9451 100644 (file)
@@ -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;
 
index 636cc947552bbd984e0a61006c418bccba4eabf0..b6d1751423a741d2b17972ac6f1f0db418300dd1 100644 (file)
@@ -455,6 +455,12 @@ cupsdUpdateSystemMonitor(void)
             p = (cupsd_printer_t *)cupsArrayNext(Printers))
          cupsdDeregisterPrinter(p, 1);
 
+       /*
+        * Update the computer name...
+       */
+
+       cupsdUpdateDNSSDName();
+
        /*
        * Now re-register them...
        */
index 09b07fb244f7a34fb1fe77605fab65b91fab8b1d..b2135802c4177c8055fdcec47a1c6cc20bad1ce7 100644 (file)
@@ -21,7 +21,7 @@ include ../../Makedefs
 #
 
 PHPDIR =       $(BUILDROOT)`$(PHPCONFIG) --extension-dir`
-OPTIONS        =       -I../.. `$(PHPCONFIG) --includes`
+OPTIONS        =       $(PHPOPTIONS)
 
 
 #
index 6bbf63ada3b57d63b6bcbc2db226b64b0da8a340..ac4e67de52fd3c935c92a66d4177917f175093fe 100644 (file)
  *
  * 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 : "<NULL>");
@@ -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 : "<NULL>");
index 6288c47d6ced6eee4fdce643c0a5800577abb68d..2e054ea474aa1456696a35364ccf937b4760a4e5 100644 (file)
@@ -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
index 9676778602ac3e5943acbc3a6528d09a3c6cadce..b05c7ab8b2a0d155063f47698c24e7eed4d379f0 100755 (executable)
@@ -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
 <Policy default>
 <Limit All>
@@ -549,10 +555,11 @@ echo "Test Summary"
 echo ""
 echo "<H2>Summary</H2>" >>$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 "<P>FAIL: Printer 'Test1' produced $count page(s), expected $expected.</P>" >>$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 "<P>FAIL: $count debug2 messages, expected 0.</P>" >>$strfile
+if test $count = 0; then
+       echo "FAIL: $count debug2 messages, expected more than 0."
+       echo "<P>FAIL: $count debug2 messages, expected more than 0.</P>" >>$strfile
        fail=`expr $fail + 1`
 else
        echo "PASS: $count debug2 messages."
@@ -709,7 +716,7 @@ echo "</PRE>" >>$strfile
 
 echo "<H2>error_log</H2>" >>$strfile
 echo "<PRE>" >>$strfile
-sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' /tmp/cups-$user/log/error_log >>$strfile
+grep -v '^[dD]' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' >>$strfile
 echo "</PRE>" >>$strfile
 
 echo "<H2>page_log</H2>" >>$strfile