-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
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@
# 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
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
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
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
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
#
# 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
# 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)
#
# 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>
* OID constants...
*/
+/* Host MIB */
#define CUPS_OID_mib2 1,3,6,1,2,1
#define CUPS_OID_host CUPS_OID_mib2,25
#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
#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...
* 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
}
*/
#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>
/*
*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 */
* 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)
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
do
{
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, http->hostaddr);
+
/*
* Build the IPP request...
*/
while (copies_remaining > 0)
{
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, http->hostaddr);
+
/*
* Build the IPP request...
*/
{
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;
for (delay = 1; !job_cancelled;)
{
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, http->hostaddr);
+
/*
* Build an IPP_GET_JOB_ATTRIBUTES request...
*/
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...
*/
* 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>
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 */
* 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));
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? */
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...
*/
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))
{
if (status == 0)
{
+ /*
+ * Check for side-channel requests...
+ */
+
+ backendCheckSideChannel(snmp_fd, &(addr->addr));
+
/*
* Send the print file...
*/
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))
{
_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...
*/
--- /dev/null
+/*
+ * "$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$".
+ */
--- /dev/null
+/*
+ * "$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$".
+ */
}
-/*
- * '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.
*/
if (!httpAddrEqual(addr, ¤t_addr))
backend_init_supplies(snmp_fd, addr);
else if (num_supplies > 0)
- cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1,
- cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel, 500,
+ _cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel, 500,
backend_walk_cb, NULL);
if (page_count)
* 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);
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);
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);
* 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));
* Walk the printer configuration information...
*/
- cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1,
- cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry, 500,
+ _cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry, 500,
backend_walk_cb, NULL);
}
for (i = 0; i < num_supplies; i ++)
strcpy(supplies[i].color, "none");
- cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1,
- cupsSNMPDefaultCommunity(), prtMarkerColorantValue, 500,
+ _cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1,
+ _cupsSNMPDefaultCommunity(), prtMarkerColorantValue, 500,
backend_walk_cb, NULL);
/*
(void)data;
- if (cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) &&
+ if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) &&
packet->object_type == CUPS_ASN1_OCTET_STRING)
{
/*
}
}
}
- else if (cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
+ else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
{
/*
* Get colorant index...
supplies[i - 1].colorant = packet->object_value.integer;
}
- else if (cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription))
+ else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription))
{
/*
* Get supply name/description...
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...
supplies[i - 1].level = packet->object_value.integer;
}
- else if (cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity))
+ else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity))
{
/*
* Get max capacity...
supplies[i - 1].max_capacity = packet->object_value.integer;
}
- else if (cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
+ else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
{
/*
* Get marker type...
#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
* print servers:
*
* Axis OfficeBasic, 5400, 5600
+ * Brother
* EPSON
* Genicom
* HP JetDirect
char *addrname, /* Name of device */
*uri, /* device-uri */
*id, /* device-id */
+ *info, /* device-info */
*make_and_model; /* device-make-and-model */
} snmp_cache_t;
* 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);
/*
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;
* Open the SNMP socket...
*/
- if ((fd = cupsSNMPOpen(AF_INET)) < 0)
+ if ((fd = _cupsSNMPOpen(AF_INET)) < 0)
return (1);
/*
read_snmp_conf(argv[1]);
- cupsSNMPSetDebug(DebugLevel);
+ _cupsSNMPSetDebug(DebugLevel);
Devices = cupsArrayNew((cups_array_func_t)compare_cache, NULL);
* Close, free, and return with no errors...
*/
- cupsSNMPClose(fd);
+ _cupsSNMPClose(fd);
free_array(Addresses);
free_array(Communities);
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);
}
}
* 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));
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)
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
{
*/
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);
}
}
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);
}
* 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));
* 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;
}
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);
fi)
AC_SUBST(LIBCUPSIMAGEORDER)
+PHPOPTIONS=""
+AC_SUBST(PHPOPTIONS)
+
if test -n "$GCC"; then
# Add GCC-specific compiler options...
if test -z "$OPTIM"; then
# Additional warning options for development testing...
if test -d .svn; then
OPTIM="-Wshadow -Wunused $OPTIM"
+ PHPOPTIONS="-Wno-shadow"
fi
fi
CPPFLAGS="-I$withval $CPPFLAGS",)
DNSSDLIBS=""
+MDNS=""
if test x$enable_dnssd != xno; then
AC_CHECK_HEADER(dns_sd.h, [
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")
;;
fi
AC_SUBST(DNSSDLIBS)
+AC_SUBST(MDNS)
dnl
dnl End of "$Id$".
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
ppd.h \
raster.h \
sidechannel.h \
- snmp.h \
transcode.h \
versioning.h
--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...
--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
#
<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
<a href="#cupsSNMPWalk">cupsSNMPWalk</a>(snmp, &(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
__cupsMessageLookup
__cupsSetError
__cupsSetLocale
+__cupsSNMPClose
+__cupsSNMPCopyOID
+__cupsSNMPDefaultCommunity
+__cupsSNMPIsOID
+__cupsSNMPIsOIDPrefixed
+__cupsSNMPOpen
+__cupsSNMPRead
+__cupsSNMPSetDebug
+__cupsSNMPWalk
+__cupsSNMPWrite
__cupsStrAlloc
__cupsStrFlush
__cupsStrFormatd
_cupsReadResponseData
_cupsRemoveDest
_cupsRemoveOption
-_cupsSNMPClose
-_cupsSNMPCopyOID
-_cupsSNMPDefaultCommunity
-_cupsSNMPIsOID
-_cupsSNMPIsOIDPrefixed
-_cupsSNMPOpen
-_cupsSNMPRead
-_cupsSNMPSetDebug
-_cupsSNMPWalk
-_cupsSNMPWrite
_cupsSendRequest
_cupsServer
_cupsSetDefaultDest
_cupsMessageLookup
_cupsSetError
_cupsSetLocale
+_cupsSNMPClose
+_cupsSNMPCopyOID
+_cupsSNMPDefaultCommunity
+_cupsSNMPIsOID
+_cupsSNMPIsOIDPrefixed
+_cupsSNMPOpen
+_cupsSNMPRead
+_cupsSNMPSetDebug
+_cupsSNMPWalk
+_cupsSNMPWrite
_cupsStrAlloc
_cupsStrFlush
_cupsStrFormatd
--- /dev/null
+/*
+ * "$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$".
+ */
*
* 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.
*/
/*
*/
#include "globals.h"
-#include "snmp.h"
+#include "snmp-private.h"
#include <errno.h>
#ifdef HAVE_POLL
# include <sys/poll.h>
/*
- * '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);
/*
- * 'cupsSNMPCopyOID()' - Copy an OID.
+ * '_cupsSNMPCopyOID()' - Copy an OID.
*
* The array pointed to by "src" is terminated by the value -1.
*
*/
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 */
/*
- * '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.
*/
const char * /* O - Default community name */
-cupsSNMPDefaultCommunity(void)
+_cupsSNMPDefaultCommunity(void)
{
cups_file_t *fp; /* snmp.conf file */
char line[1024], /* Line from file */
/*
- * '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.
*
*/
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 */
/*
- * '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.
*
*/
int /* O - 1 if prefixed, 0 if not prefixed */
-cupsSNMPIsOIDPrefixed(
+_cupsSNMPIsOIDPrefixed(
cups_snmp_t *packet, /* I - Response packet */
const int *prefix) /* I - OID prefix */
{
/*
- * '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 */
/*
- * '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 */
{
/*
- * '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 */
/*
- * '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 */
* 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)
/*
- * 'cupsSNMPWrite()' - Send an SNMP query packet.
+ * '_cupsSNMPWrite()' - Send an SNMP query packet.
*
* The array pointed to by "oid" is terminated by the value -1.
*
*/
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 */
+++ /dev/null
-/*
- * "$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$".
- */
* Contents:
*
* main() - Main entry.
+ * random_tests() - Do random access tests.
* read_write_tests() - Perform read/write tests.
*/
#ifdef HAVE_LIBZ
# include <zlib.h>
#endif /* HAVE_LIBZ */
+#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include "string.h"
-#include "snmp.h"
+#include "snmp-private.h"
/*
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);
community = argv[i];
}
else if (!strcmp(argv[i], "-d"))
- cupsSNMPSetDebug(10);
+ _cupsSNMPSetDebug(10);
else if (!strcmp(argv[i], "-w"))
walk = 1;
else if (!host)
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);
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));
}
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));
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 ++)
BODY {
- background: #e8e8e8;
- color: #000000;
+ background: white;
+ color: black;
font-family: lucida grande, geneva, helvetica, arial, sans-serif;
}
}
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;
}
A:link:hover IMG {
- background: #e0e0e0;
+ background: #f0f0f0;
border-radius: 10px;
-moz-border-radius: 10px;
}
}
TD.sel A, TD.sel A:hover {
- color: #ffffff;
+ color: white;
font-weight: normal;
text-decoration: none;
}
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;
}
DIV.table TABLE TH {
- background: #eeeeee;
+ background: #f0f0f0;
border: none;
border-bottom: solid thin #999999;
}
}
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;
}
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;
}
DIV.summary TABLE THEAD TH {
- background: #eeeeee;
+ background: #f0f0f0;
}
/* API documentation styles... */
existing file, "a" to append to an existing file or create a new file,
or "s" to open a socket connection.<br>
<br>
-When opening for writing ("w") or appending ("a"), an optional number from
-1 to 9 can be supplied which enables Flate compression of the file.<br>
+When opening for writing ("w"), an optional number from 1 to 9 can be
+supplied which enables Flate compression of the file. Compression is
+not supported for the "a" (append) mode.<br>
<br>
When opening a socket connection, the filename is a string of the form
"address:port" or "hostname:port". The socket will make an IPv4 or IPv6
<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 "mode" parameter can be "r" to read, "a" or "w" to write, or "s"
-to treat the file descriptor as a bidirectional socket connection.<br>
+<p class="discussion">The "mode" parameter can be "r" to read, "w" to write, "a" to append,
+or "s" to treat the file descriptor as a bidirectional socket connection.<br>
<br>
-When opening for writing ("w") or appending ("a"), an optional number from
-1 to 9 can be supplied which enables Flate compression of the file.
+When opening for writing ("w"), an optional number from 1 to 9 can be
+supplied which enables Flate compression of the file. Compression is
+not supported for the "a" (append) mode.
</p>
<h3 class="function"><span class="info"> CUPS 1.2 </span><a name="cupsFilePeekChar">cupsFilePeekChar</a></h3>
<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>
<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
<a href="#cupsSNMPWalk">cupsSNMPWalk</a>(snmp, &(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"> CUPS 1.2 </span><a name="cupsBackChannelRead">cupsBackChannelRead</a></h3>
<p class="description">Read data from the backchannel.</p>
<p class="code">
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"> CUPS 1.4 </span><a name="cupsSNMPClose">cupsSNMPClose</a></h3>
-<p class="description">Close a SNMP socket.</p>
-<p class="code">
-void cupsSNMPClose (<br>
- 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"> CUPS 1.4 </span><a name="cupsSNMPCopyOID">cupsSNMPCopyOID</a></h3>
-<p class="description">Copy an OID.</p>
-<p class="code">
-int *cupsSNMPCopyOID (<br>
- int *dst,<br>
- const int *src,<br>
- 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 "src" is terminated by the value -1.
-
-</p>
-<h3 class="function"><span class="info"> CUPS 1.4 </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, "public" is used.
-
-</p>
-<h3 class="function"><span class="info"> CUPS 1.4 </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>
- <a href="#cups_snmp_t">cups_snmp_t</a> *packet,<br>
- 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 "oid" is terminated by the value -1.
-
-</p>
-<h3 class="function"><span class="info"> CUPS 1.4 </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>
- <a href="#cups_snmp_t">cups_snmp_t</a> *packet,<br>
- 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 "prefix" is terminated by the value -1.
-
-</p>
-<h3 class="function"><span class="info"> CUPS 1.4 </span><a name="cupsSNMPOpen">cupsSNMPOpen</a></h3>
-<p class="description">Open a SNMP socket.</p>
-<p class="code">
-int cupsSNMPOpen (<br>
- 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"> CUPS 1.4 </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>
- int fd,<br>
- <a href="#cups_snmp_t">cups_snmp_t</a> *packet,<br>
- 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 "timeout" is negative, <code>cupsSNMPRead</code> will wait for a response
-indefinitely.
-
-</p>
-<h3 class="function"><span class="info"> CUPS 1.4 </span><a name="cupsSNMPSetDebug">cupsSNMPSetDebug</a></h3>
-<p class="description">Enable/disable debug logging to stderr.</p>
-<p class="code">
-void cupsSNMPSetDebug (<br>
- 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"> CUPS 1.4 </span><a name="cupsSNMPWalk">cupsSNMPWalk</a></h3>
-<p class="description">Enumerate a group of OIDs.</p>
-<p class="code">
-int cupsSNMPWalk (<br>
- int fd,<br>
- http_addr_t *address,<br>
- int version,<br>
- const char *community,<br>
- const int *prefix,<br>
- double timeout,<br>
- <a href="#cups_snmp_cb_t">cups_snmp_cb_t</a> cb,<br>
- 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 "cb" function for every response that is received.<br>
-<br>
-The array pointed to by "prefix" is terminated by the value -1.<br>
-<br>
-If "timeout" is negative, <code>cupsSNMPWalk</code> will wait for a response
-indefinitely.
-
-</p>
-<h3 class="function"><span class="info"> CUPS 1.4 </span><a name="cupsSNMPWrite">cupsSNMPWrite</a></h3>
-<p class="description">Send an SNMP query packet.</p>
-<p class="code">
-int cupsSNMPWrite (<br>
- int fd,<br>
- http_addr_t *address,<br>
- int version,<br>
- const char *community,<br>
- <a href="#cups_asn1_t">cups_asn1_t</a> request_type,<br>
- const unsigned request_id,<br>
- 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 "oid" is terminated by the value -1.
-
-</p>
<h3 class="function"><span class="info"> CUPS 1.3 </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">
</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">
<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>
- unsigned char bytes[CUPS_SNMP_MAX_STRING];<br>
- 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>
- http_addr_t address;<br>
- char community[CUPS_SNMP_MAX_STRING];<br>
- const char *error;<br>
- int error_index;<br>
- int error_status;<br>
- int object_name[CUPS_SNMP_MAX_OID];<br>
- <a href="#cups_asn1_t">cups_asn1_t</a> object_type;<br>
- union <a href="#cups_snmp_value_u">cups_snmp_value_u</a> object_value;<br>
- int request_id;<br>
- <a href="#cups_asn1_t">cups_asn1_t</a> request_type;<br>
- 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>
- int boolean;<br>
- unsigned counter;<br>
- unsigned gauge;<br>
- struct <a href="#cups_snmp_hexstring_s">cups_snmp_hexstring_s</a> hex_string;<br>
- int integer;<br>
- int oid[CUPS_SNMP_MAX_OID];<br>
- char string[CUPS_SNMP_MAX_STRING];<br>
- 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>
include ../Makedefs
-FILTERS = gziptoany hpgltops texttops pstops $(IMGFILTERS) \
+FILTERS = commandtops gziptoany hpgltops texttops pstops $(IMGFILTERS) \
$(PDFTOPS) rastertolabel rastertoepson rastertohp
TARGETS = $(FILTERS) \
$(LIBCUPSIMAGE) \
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
../cups/raster.h interpret.c raster.c
+#
+# commandtops
+#
+
+commandtops: commandtops.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ commandtops.o $(LIBS)
+
+
#
# formtops
#
--- /dev/null
+/*
+ * "$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$".
+ */
$LIB64DIR=@LIB64DIR@
$IMGFILTERS=@IMGFILTERS@
+$MDNS=@MDNS@
$PDFTOPS=@PDFTOPS@
$CUPS_USER=@CUPS_USER@
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
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
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
*
* 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.
*/
/*
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 */
{
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
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 ||
#endif /* HAVE_LIBSLP */
#ifdef HAVE_DNSSD
- if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD))
+ if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDPort)
dnssdDeregisterPrinter(p);
#endif /* HAVE_DNSSD */
}
/*
- * 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.");
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;
#endif /* HAVE_LIBSLP */
#ifdef HAVE_DNSSD
- if (BrowseLocalProtocols & BROWSE_DNSSD)
+ if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDPort)
dnssdRegisterPrinter(p);
#endif /* HAVE_DNSSD */
}
cupsArraySave(Printers);
cupsdDeletePrinter(p, 1);
cupsArrayRestore(Printers);
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
}
}
}
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)
{
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)
*/
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 */
}
-#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 */
/*
update = 1;
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
name);
{
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;
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 */
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);
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;
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)
else
job->backend = -pid;
- if (job->state_value == IPP_JOB_CANCELED)
- status = 0; /* Ignore errors when canceling jobs */
-
if (status && job->status >= 0)
{
/*
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!",
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;
}
/*
* 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
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;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
cupsdDeregisterPrinter(p, 1);
+ /*
+ * Update the computer name...
+ */
+
+ cupsdUpdateDNSSDName();
+
/*
* Now re-register them...
*/
#
PHPDIR = $(BUILDROOT)`$(PHPCONFIG) --extension-dir`
-OPTIONS = -I../.. `$(PHPCONFIG) --includes`
+OPTIONS = $(PHPOPTIONS)
#
*
* 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.
*/
/*
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 */
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>");
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>");
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
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
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
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
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
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>
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`
# 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."
echo "<H2>error_log</H2>" >>$strfile
echo "<PRE>" >>$strfile
-sed -e '1,$s/&/&/g' -e '1,$s/</</g' /tmp/cups-$user/log/error_log >>$strfile
+grep -v '^[dD]' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&/g' -e '1,$s/</</g' >>$strfile
echo "</PRE>" >>$strfile
echo "<H2>page_log</H2>" >>$strfile