From: msweet Date: Mon, 19 May 2008 23:16:59 +0000 (+0000) Subject: Merge changes from CUPS 1.4svn-r7594. X-Git-Tag: release-1.6.3~166 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=20fbc9034781e607f8063453c8a52ec73fc5c293;p=thirdparty%2Fcups.git Merge changes from CUPS 1.4svn-r7594. git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@779 a1ca3aef-8c08-0410-bb20-df032aa958be --- diff --git a/CHANGES.txt b/CHANGES.txt index 575442955d..99155aed70 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,8 +1,10 @@ -CHANGES.txt - 2008-05-15 +CHANGES.txt - 2008-05-19 ------------------------ CHANGES IN CUPS V1.4b1 + - The side-channel API now supports SNMP queries for the + standard network backends. - Added a PageLogFormat directive to the cupsd.conf file to control the format of lines in the page_log file. - Filters can now send PPD: messages to stderr to set PPD diff --git a/backend/network.c b/backend/network.c index 46832a3d1f..daf05cda50 100644 --- a/backend/network.c +++ b/backend/network.c @@ -33,12 +33,6 @@ #endif /* __hpux */ -/* - * Local functions... - */ - - - /* * 'backendCheckSideChannel()' - Check the side-channel for pending requests. */ @@ -112,6 +106,126 @@ backendNetworkSideCB( datalen = 1; break; + case CUPS_SC_CMD_SNMP_GET : + case CUPS_SC_CMD_SNMP_GET_NEXT : + fprintf(stderr, "DEBUG: CUPS_SC_CMD_SNMP_%s: %d (%s)\n", + command == CUPS_SC_CMD_SNMP_GET ? "GET" : "GET_NEXT", datalen, + data); + + if (datalen < 2) + { + status = CUPS_SC_STATUS_BAD_MESSAGE; + datalen = 0; + break; + } + + if (snmp_fd >= 0) + { + cups_snmp_t packet; /* Packet from printer */ + + + if (!_cupsSNMPStringToOID(data, packet.object_name, CUPS_SNMP_MAX_OID)) + { + status = CUPS_SC_STATUS_BAD_MESSAGE; + datalen = 0; + break; + } + + status = CUPS_SC_STATUS_IO_ERROR; + datalen = 0; + + if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, + _cupsSNMPDefaultCommunity(), + command == CUPS_SC_CMD_SNMP_GET ? + CUPS_ASN1_GET_REQUEST : + CUPS_ASN1_GET_NEXT_REQUEST, 1, + packet.object_name)) + { + if (_cupsSNMPRead(snmp_fd, &packet, 1.0)) + { + char *dataptr; /* Pointer into data */ + int i; /* Looping var */ + + + if (!_cupsSNMPOIDToString(packet.object_name, data, sizeof(data))) + { + fputs("DEBUG: Bad OID returned!\n", stderr); + break; + } + + datalen = (int)strlen(data) + 1; + dataptr = data + datalen; + + switch (packet.object_type) + { + case CUPS_ASN1_BOOLEAN : + snprintf(dataptr, sizeof(data) - (dataptr - data), "%d", + packet.object_value.boolean); + break; + + case CUPS_ASN1_INTEGER : + snprintf(dataptr, sizeof(data) - (dataptr - data), "%d", + packet.object_value.integer); + break; + + case CUPS_ASN1_BIT_STRING : + case CUPS_ASN1_OCTET_STRING : + strlcpy(dataptr, packet.object_value.string, + sizeof(data) - (dataptr - data)); + break; + + case CUPS_ASN1_OID : + _cupsSNMPOIDToString(packet.object_value.oid, dataptr, + sizeof(data) - (dataptr - data)); + break; + + case CUPS_ASN1_HEX_STRING : + for (i = 0; + i < packet.object_value.hex_string.num_bytes && + dataptr < (data + sizeof(data) - 3); + i ++, dataptr += 2) + sprintf(dataptr, "%02X", + packet.object_value.hex_string.bytes[i]); + break; + + case CUPS_ASN1_COUNTER : + snprintf(dataptr, sizeof(data) - (dataptr - data), "%d", + packet.object_value.counter); + break; + + case CUPS_ASN1_GAUGE : + snprintf(dataptr, sizeof(data) - (dataptr - data), "%u", + packet.object_value.gauge); + break; + + case CUPS_ASN1_TIMETICKS : + snprintf(dataptr, sizeof(data) - (dataptr - data), "%u", + packet.object_value.timeticks); + break; + + default : + fprintf(stderr, "DEBUG: Unknown OID value type %02X!\n", + packet.object_type); + break; + } + + fprintf(stderr, "DEBUG: Returning %s %s\n", data, data + datalen); + + status = CUPS_SC_STATUS_OK; + datalen += (int)strlen(data + datalen); + } + else + fputs("DEBUG: SNMP read error...\n", stderr); + } + else + fputs("DEBUG: SNMP write error...\n", stderr); + break; + } + + status = CUPS_SC_STATUS_NOT_IMPLEMENTED; + datalen = 0; + break; + case CUPS_SC_CMD_GET_DEVICE_ID : if (snmp_fd >= 0) { @@ -119,7 +233,12 @@ backendNetworkSideCB( static const int ppmPrinterIEEE1284DeviceId[] = { CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 }; - if (_cupsSNMPWrite(snmp_fd, addr, 1, _cupsSNMPDefaultCommunity(), + + status = CUPS_SC_STATUS_IO_ERROR; + datalen = 0; + + if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, + _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, ppmPrinterIEEE1284DeviceId)) { @@ -128,9 +247,11 @@ backendNetworkSideCB( { strlcpy(data, packet.object_value.string, sizeof(data)); datalen = (int)strlen(data); - break; + status = CUPS_SC_STATUS_OK; } } + + break; } if ((device_id = getenv("1284DEVICEID")) != NULL) diff --git a/backend/testbackend.c b/backend/testbackend.c index 4868beee1f..363572a769 100644 --- a/backend/testbackend.c +++ b/backend/testbackend.c @@ -318,6 +318,8 @@ main(int argc, /* I - Number of command-line args */ }; + sleep(2); + length = 0; scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer, &length, 5.0); @@ -341,6 +343,12 @@ main(int argc, /* I - Number of command-line args */ printf("CUPS_SC_CMD_GET_STATE returned %s, %02X\n", statuses[scstatus], buffer[0] & 255); + length = sizeof(buffer); + scstatus = cupsSideChannelSNMPGet(".1.3.6.1.2.1.43.10.2.1.4.1.1", buffer, + &length, 5.0); + printf("CUPS_SC_CMD_SNMP_GET returned %s, %s\n", statuses[scstatus], + buffer); + length = 0; scstatus = cupsSideChannelDoRequest(CUPS_SC_CMD_SOFT_RESET, buffer, &length, 5.0); @@ -372,7 +380,7 @@ main(int argc, /* I - Number of command-line args */ static void usage(void) { - fputs("Usage: betest [-ps] [-s] [-t] device-uri job-id user title copies " + fputs("Usage: testbackend [-ps] [-s] [-t] device-uri job-id user title copies " "options [file]\n", stderr); exit(1); } diff --git a/cups/Dependencies b/cups/Dependencies index 733948c3a4..deb6a77eab 100644 --- a/cups/Dependencies +++ b/cups/Dependencies @@ -114,6 +114,8 @@ testi18n.o: i18n.h transcode.h language.h array.h versioning.h string.h testi18n.o: ../config.h testipp.o: ../cups/string.h ../config.h string.h ipp-private.h ipp.h http.h testipp.o: versioning.h +testoptions.o: string.h ../config.h cups.h ipp.h http.h versioning.h ppd.h +testoptions.o: array.h file.h language.h testlang.o: i18n.h transcode.h language.h array.h versioning.h string.h testlang.o: ../config.h testppd.o: ../cups/string.h ../config.h string.h ppd.h array.h versioning.h @@ -235,6 +237,8 @@ testi18n.32.o: testi18n.c i18n.h transcode.h language.h array.h versioning.h st testi18n.32.o: testi18n.c ../config.h testipp.32.o: testipp.c ../cups/string.h ../config.h string.h ipp-private.h ipp.h http.h testipp.32.o: testipp.c versioning.h +testoptions.32.o: testoptions.c string.h ../config.h cups.h ipp.h http.h versioning.h ppd.h +testoptions.32.o: testoptions.c array.h file.h language.h testlang.32.o: testlang.c i18n.h transcode.h language.h array.h versioning.h string.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 @@ -356,6 +360,8 @@ testi18n.64.o: testi18n.c i18n.h transcode.h language.h array.h versioning.h st testi18n.64.o: testi18n.c ../config.h testipp.64.o: testipp.c ../cups/string.h ../config.h string.h ipp-private.h ipp.h http.h testipp.64.o: testipp.c versioning.h +testoptions.64.o: testoptions.c string.h ../config.h cups.h ipp.h http.h versioning.h ppd.h +testoptions.64.o: testoptions.c array.h file.h language.h testlang.64.o: testlang.c i18n.h transcode.h language.h array.h versioning.h string.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 diff --git a/cups/Makefile b/cups/Makefile index 48e6cedfa1..3bf135002d 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -77,6 +77,7 @@ OBJS = \ testhttp.o \ testi18n.o \ testipp.o \ + testoptions.o \ testlang.o \ testppd.o \ testsnmp.o \ @@ -119,6 +120,7 @@ LIBTARGETS = \ testi18n \ testipp \ testlang \ + testoptions \ testppd TARGETS = \ @@ -468,6 +470,18 @@ testlang: testlang.o libcups.a ./testlang +# +# testoptions (dependency on static CUPS library is intentional) +# + +testoptions: testoptions.o libcups.a + echo Linking $@... + $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testoptions.o libcups.a \ + $(LIBGSSAPI) $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + echo Running option API tests... + ./testoptions + + # # testppd (dependency on static CUPS library is intentional) # diff --git a/cups/api-filter.shtml b/cups/api-filter.shtml index 60f28d32f1..d4583b13c6 100644 --- a/cups/api-filter.shtml +++ b/cups/api-filter.shtml @@ -218,6 +218,11 @@ prefix strings:

#-copies to the job-media-sheets-completed attribute. The second form sets the job-media-sheets-completed attribute to #-pages. +
PPD: keyword=value [keyword=value ...]
+
Changes or adds keywords to the printer's PPD file. Typically + this is used to update installable options or default media settings + based on the printer configuration.
+
STATE: printer-state-reason [printer-state-reason ...]
STATE: + printer-state-reason [printer-state-reason ...]
STATE: - printer-state-reason [printer-state-reason ...]
@@ -235,7 +240,7 @@ prefix strings:

Messages without one of these prefixes are treated as if they began with the "DEBUG:" prefix string.

-

Communicating with the Backend

+

Communicating with the Backend

Filters can communicate with the backend via the cupsBackChannelRead and @@ -282,6 +287,8 @@ else data[0] = '\0'; +

Communicating with Filters

+

Backends communicate with filters using the reciprocal functions cupsBackChannelWrite, cupsSideChannelRead, and @@ -304,10 +311,7 @@ Backends can either poll for commands using a timeout of 0.0, wait indefinitely for commands using a timeout of -1.0 (probably in a separate thread for that purpose), or use select or poll on the CUPS_SC_FD file descriptor (4) to handle -input and output on several file descriptors at the same time. Backends can pass -NULL for the data and datalen parameters -since none of the commands sent by upstream filters contain any data at this -time.

+input and output on several file descriptors at the same time.

Once a command is processed, the backend uses the cupsSideChannelWrite function @@ -319,16 +323,15 @@ side-channel command and respond to it:

cups_sc_command_t command; cups_sc_status_t status; +char data[2048]; +int datalen = sizeof(data); /* Poll for a command... */ -if (!cupsSideChannelRead(&command, &status, NULL, NULL, 0.0)) +if (!cupsSideChannelRead(&command, &status, data, &datalen, 0.0)) { - char data[2048]; - int datalen; - switch (command) { - /* handle supported commands, file data/datalen/status with values as needed */ + /* handle supported commands, fill data/datalen/status with values as needed */ default : status = CUPS_SC_STATUS_NOT_IMPLEMENTED; @@ -343,79 +346,53 @@ if (!cupsSideChannelRead(&command, &s

Doing SNMP Queries with Network Printers

-

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

- - \ No newline at end of file diff --git a/cups/libcups.exp b/cups/libcups.exp index ed50f7a4fe..ff0dd05421 100644 --- a/cups/libcups.exp +++ b/cups/libcups.exp @@ -27,9 +27,11 @@ __cupsSNMPCopyOID __cupsSNMPDefaultCommunity __cupsSNMPIsOID __cupsSNMPIsOIDPrefixed +__cupsSNMPOIDToString __cupsSNMPOpen __cupsSNMPRead __cupsSNMPSetDebug +__cupsSNMPStringToOID __cupsSNMPWalk __cupsSNMPWrite __cupsStrAlloc diff --git a/cups/libcups_s.exp b/cups/libcups_s.exp index 9872350936..129ad39a1c 100644 --- a/cups/libcups_s.exp +++ b/cups/libcups_s.exp @@ -22,9 +22,11 @@ _cupsSNMPCopyOID _cupsSNMPDefaultCommunity _cupsSNMPIsOID _cupsSNMPIsOIDPrefixed +_cupsSNMPOIDToString _cupsSNMPOpen _cupsSNMPRead _cupsSNMPSetDebug +_cupsSNMPStringToOID _cupsSNMPWalk _cupsSNMPWrite _cupsStrAlloc diff --git a/cups/options.c b/cups/options.c index 4ffb39f824..3e4db23bef 100644 --- a/cups/options.c +++ b/cups/options.c @@ -51,9 +51,14 @@ cupsAddOption(const char *name, /* I - Name of option */ cups_option_t *temp; /* Pointer to new option */ - if (name == NULL || !name[0] || value == NULL || - options == NULL || num_options < 0) + DEBUG_printf(("cupsAddOption(name=\"%s\", value=\"%s\", num_options=%d, " + "options=%p)\n", name, value, num_options, options)); + + if (!name || !name[0] || !value || !options || num_options < 0) + { + DEBUG_printf(("cupsAddOption: Returning %d\n", num_options)); return (num_options); + } /* * Look for an existing option with the same name... @@ -69,6 +74,8 @@ cupsAddOption(const char *name, /* I - Name of option */ * No matching option name... */ + DEBUG_puts("cupsAddOption: New option..."); + if (num_options == 0) temp = (cups_option_t *)malloc(sizeof(cups_option_t)); else @@ -76,7 +83,10 @@ cupsAddOption(const char *name, /* I - Name of option */ (num_options + 1)); if (temp == NULL) + { + DEBUG_puts("cupsAddOption: Unable to expand option array, returning 0"); return (0); + } *options = temp; temp += num_options; @@ -89,11 +99,14 @@ cupsAddOption(const char *name, /* I - Name of option */ * Match found; free the old value... */ + DEBUG_puts("cupsAddOption: Option already exists..."); _cupsStrFree(temp->value); } temp->value = _cupsStrAlloc(value); + DEBUG_printf(("cupsAddOption: Returning %d\n", num_options)); + return (num_options); } @@ -110,7 +123,10 @@ cupsFreeOptions( int i; /* Looping var */ - if (num_options <= 0 || options == NULL) + DEBUG_printf(("cupsFreeOptions(num_options=%d, options=%p)\n", num_options, + options)); + + if (num_options <= 0 || !options) return; for (i = 0; i < num_options; i ++) @@ -135,13 +151,23 @@ cupsGetOption(const char *name, /* I - Name of option */ int i; /* Looping var */ - if (name == NULL || num_options <= 0 || options == NULL) + DEBUG_printf(("cupsGetOption(name=\"%s\", num_options=%d, options=%p)\n", + name, num_options, options)); + + if (!name || num_options <= 0 || !options) + { + DEBUG_puts("cupsGetOption: Returning NULL"); return (NULL); + } for (i = 0; i < num_options; i ++) - if (strcasecmp(options[i].name, name) == 0) + if (!strcasecmp(options[i].name, name)) + { + DEBUG_printf(("cupsGetOption: Returning \"%s\"\n", options[i].value)); return (options[i].value); + } + DEBUG_puts("cupsGetOption: Returning NULL"); return (NULL); } @@ -169,22 +195,35 @@ cupsParseOptions( quote; /* Quote character */ + DEBUG_printf(("cupsParseOptions(arg=\"%s\", num_options=%d, options=%p)\n", + arg, num_options, options)); + /* * Range check input... */ if (!arg) + { + DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options)); return (num_options); + } if (!options || num_options < 0) + { + DEBUG_puts("cupsParseOptions: Returning 0"); return (0); + } /* * Make a copy of the argument string and then divide it up... */ if ((copyarg = strdup(arg)) == NULL) + { + DEBUG_puts("cupsParseOptions: Unable to copy arg string"); + DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options)); return (num_options); + } ptr = copyarg; @@ -223,6 +262,8 @@ cupsParseOptions( while (isspace(*ptr & 255)) *ptr++ = '\0'; + DEBUG_printf(("cupsParseOptions: name=\"%s\"\n", name)); + if (*ptr != '=') { /* @@ -243,80 +284,84 @@ cupsParseOptions( */ *ptr++ = '\0'; + value = ptr; - if (*ptr == '\'' || *ptr == '\"') + while (*ptr && !isspace(*ptr & 255)) { - /* - * Quoted string constant... - */ - - quote = *ptr++; - value = ptr; - - while (*ptr != quote && *ptr) + if (*ptr == ',') + ptr ++; + else if (*ptr == '\'' || *ptr == '\"') { - if (*ptr == '\\' && ptr[1]) - _cups_strcpy(ptr, ptr + 1); + /* + * Quoted string constant... + */ - ptr ++; - } + quote = *ptr; + _cups_strcpy(ptr, ptr + 1); - if (*ptr != '\0') - *ptr++ = '\0'; - } - else if (*ptr == '{') - { - /* - * Collection value... - */ + while (*ptr != quote && *ptr) + { + if (*ptr == '\\' && ptr[1]) + _cups_strcpy(ptr, ptr + 1); + + ptr ++; + } - int depth; + if (*ptr) + _cups_strcpy(ptr, ptr + 1); + } + else if (*ptr == '{') + { + /* + * Collection value... + */ - value = ptr; + int depth; - for (depth = 1; *ptr; ptr ++) - if (*ptr == '{') - depth ++; - else if (*ptr == '}') + for (depth = 0; *ptr; ptr ++) { - depth --; - if (!depth) + if (*ptr == '{') + depth ++; + else if (*ptr == '}') { - ptr ++; - - if (*ptr != ',') + depth --; + if (!depth) + { + ptr ++; break; + } } - } - else if (*ptr == '\\' && ptr[1]) - _cups_strcpy(ptr, ptr + 1); - - if (*ptr != '\0') - *ptr++ = '\0'; - } - else - { - /* - * Normal space-delimited string... - */ - - value = ptr; - - while (!isspace(*ptr & 255) && *ptr) + else if (*ptr == '\\' && ptr[1]) + _cups_strcpy(ptr, ptr + 1); + } + } + else { - if (*ptr == '\\' && ptr[1]) - _cups_strcpy(ptr, ptr + 1); + /* + * Normal space-delimited string... + */ - ptr ++; + while (!isspace(*ptr & 255) && *ptr) + { + if (*ptr == '\\' && ptr[1]) + _cups_strcpy(ptr, ptr + 1); + + ptr ++; + } } } + if (*ptr != '\0') + *ptr++ = '\0'; + + DEBUG_printf(("cupsParseOptions: value=\"%s\"\n", value)); + /* * Skip trailing whitespace... */ while (isspace(*ptr & 255)) - *ptr++ = '\0'; + ptr ++; /* * Add the string value... @@ -332,6 +377,8 @@ cupsParseOptions( free(copyarg); + DEBUG_printf(("cupsParseOptions: Returning %d\n", num_options)); + return (num_options); } @@ -352,12 +399,18 @@ cupsRemoveOption( cups_option_t *option; /* Current option */ + DEBUG_printf(("cupsRemoveOption(name=\"%s\", num_options=%d, options=%p)\n", + name, num_options, options)); + /* * Range check input... */ if (!name || num_options < 1 || !options) + { + DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options)); return (num_options); + } /* * Loop for the option... @@ -373,6 +426,8 @@ cupsRemoveOption( * Remove this option from the array... */ + DEBUG_puts("cupsRemoveOption: Found option, removing it..."); + num_options --; i --; @@ -387,6 +442,7 @@ cupsRemoveOption( * Return the new number of options... */ + DEBUG_printf(("cupsRemoveOption: Returning %d\n", num_options)); return (num_options); } diff --git a/cups/sidechannel.c b/cups/sidechannel.c index 9f1a64fa8d..9a009e9690 100644 --- a/cups/sidechannel.c +++ b/cups/sidechannel.c @@ -3,7 +3,7 @@ * * Side-channel API code for the Common UNIX Printing System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -16,9 +16,11 @@ * * Contents: * - * cupsSideChannelDoRequest() - Send a side-channel command to a backend - * and wait for a response. + * cupsSideChannelDoRequest() - Send a side-channel command to a backend and + * wait for a response. * cupsSideChannelRead() - Read a side-channel message. + * cupsSideChannelSNMPGet() - Query a SNMP OID's value. + * cupsSideChannelSNMPWalk() - Query multiple SNMP OID values. * cupsSideChannelWrite() - Write a side-channel message. */ @@ -28,6 +30,7 @@ #include "sidechannel.h" #include "string.h" +#include "debug.h" #include #include #ifdef __hpux @@ -117,6 +120,10 @@ cupsSideChannelRead( #endif /* HAVE_POLL */ + DEBUG_printf(("cupsSideChannelRead(command=%p, status=%p, data=%p, " + "datalen=%p(%d), timeout=%.3f)\n", command, status, data, + datalen, datalen ? *datalen : -1, timeout)); + /* * Range check input... */ @@ -147,7 +154,10 @@ cupsSideChannelRead( if (timeout < 0.0) { if (select(CUPS_SC_FD + 1, &input_set, NULL, NULL, NULL) < 1) + { + DEBUG_printf(("cupsSideChannelRead: Select error: %s\n", strerror(errno))); return (-1); + } } else { @@ -155,7 +165,10 @@ cupsSideChannelRead( stimeout.tv_usec = (int)(timeout * 1000000) % 1000000; if (select(CUPS_SC_FD + 1, &input_set, NULL, NULL, &stimeout) < 1) + { + DEBUG_puts("cupsSideChannelRead: Select timeout"); return (-1); + } } #endif /* HAVE_POLL */ @@ -172,14 +185,21 @@ cupsSideChannelRead( while ((bytes = read(CUPS_SC_FD, buffer, sizeof(buffer))) < 0) if (errno != EINTR && errno != EAGAIN) + { + DEBUG_printf(("cupsSideChannelRead: Read error: %s\n", strerror(errno))); return (-1); + } /* * Validate the command code in the message... */ - if (buffer[0] < CUPS_SC_CMD_SOFT_RESET || buffer[0] > CUPS_SC_CMD_GET_STATE) + if (buffer[0] < CUPS_SC_CMD_SOFT_RESET || + buffer[0] > CUPS_SC_CMD_SNMP_GET_NEXT) + { + DEBUG_printf(("cupsSideChannelRead: Bad command %d!\n", buffer[0])); return (-1); + } *command = (cups_sc_command_t)buffer[0]; @@ -220,10 +240,215 @@ cupsSideChannelRead( memcpy(data, buffer + 4, templen); } + DEBUG_printf(("cupsSideChannelRead: Returning status=%d\n", *status)); + return (0); } +/* + * 'cupsSideChannelSNMPGet()' - Query a SNMP OID's value. + * + * This function asks the backend to do a SNMP OID query on behalf of the + * filter, port monitor, or backend using the default community name. + * + * "oid" contains a numeric OID consisting of integers separated by periods, + * for example ".1.3.6.1.2.1.43". Symbolic names from SNMP MIBs are not + * supported and must be converted to their numeric forms. + * + * On input, "data" and "datalen" provide the location and size of the + * buffer to hold the OID value as a string. HEX-String (binary) values are + * converted to hexadecimal strings representing the binary data, while + * NULL-Value and unknown OID types are returned as the empty string. + * The returned "datalen" does not include the trailing nul. + * + * @code CUPS_SC_STATUS_NOT_IMPLEMENTED@ is returned by backends that do not + * support SNMP queries. @code CUPS_SC_STATUS_NO_RESPONSE@ is returned when + * the printer does not respond to the SNMP query. + * + * @since CUPS 1.4@ + */ + +cups_sc_status_t /* O - Query status */ +cupsSideChannelSNMPGet( + const char *oid, /* I - OID to query */ + char *data, /* I - Buffer for OID value */ + int *datalen, /* IO - Size of OID buffer on entry, size of value on return */ + double timeout) /* I - Timeout in seconds */ +{ + cups_sc_status_t status; /* Status of command */ + cups_sc_command_t rcommand; /* Response command */ + char real_data[2048];/* Real data buffer for response */ + int real_datalen, /* Real length of data buffer */ + real_oidlen; /* Length of returned OID string */ + + + DEBUG_printf(("cupsSideChannelSNMPGet(oid=\"%s\", data=%p, datalen=%p(%d), " + "timeout=%.3f)\n", oid, data, datalen, datalen ? *datalen : -1, + timeout)); + + /* + * Range check input... + */ + + if (!oid || !*oid || !data || !datalen || *datalen < 2) + return (CUPS_SC_STATUS_BAD_MESSAGE); + + *data = '\0'; + + /* + * Send the request to the backend and wait for a response... + */ + + if (cupsSideChannelWrite(CUPS_SC_CMD_SNMP_GET, CUPS_SC_STATUS_NONE, oid, + (int)strlen(oid), timeout)) + return (CUPS_SC_STATUS_TIMEOUT); + + real_datalen = sizeof(real_data); + if (cupsSideChannelRead(&rcommand, &status, real_data, &real_datalen, timeout)) + return (CUPS_SC_STATUS_TIMEOUT); + + if (rcommand != CUPS_SC_CMD_SNMP_GET) + return (CUPS_SC_STATUS_BAD_MESSAGE); + + if (status == CUPS_SC_STATUS_OK) + { + /* + * Parse the response of the form "oid\0value"... + */ + + real_oidlen = strlen(real_data) + 1; + real_datalen -= real_oidlen; + + if ((real_datalen + 1) > *datalen) + return (CUPS_SC_STATUS_TOO_BIG); + + memcpy(data, real_data + real_oidlen, real_datalen); + data[real_datalen] = '\0'; + + *datalen = real_datalen; + } + + return (status); +} + + +/* + * 'cupsSideChannelSNMPWalk()' - Query multiple SNMP OID values. + * + * This function asks the backend to do multiple SNMP OID queries on behalf + * of the filter, port monitor, or backend using the default community name. + * All OIDs under the "parent" OID are queried and the results are sent to + * the callback function you provide. + * + * "oid" contains a numeric OID consisting of integers separated by periods, + * for example ".1.3.6.1.2.1.43". Symbolic names from SNMP MIBs are not + * supported and must be converted to their numeric forms. + * + * "timeout" specifies the timeout for each OID query. The total amount of + * time will depend on the number of OID values found and the time required + * for each query. + * + * "cb" provides a function to call for every value that is found. "context" + * is an application-defined pointer that is sent to the callback function + * along with the OID and current data. The data passed to the callback is the + * same as returned by @link cupsSideChannelSNMPGet@. + * + * @code CUPS_SC_STATUS_NOT_IMPLEMENTED@ is returned by backends that do not + * support SNMP queries. @code CUPS_SC_STATUS_NO_RESPONSE@ is returned when + * the printer does not respond to the first SNMP query. + * + * @since CUPS 1.4@ + */ + +cups_sc_status_t /* O - Status of first query of @code CUPS_SC_STATUS_OK@ on success */ +cupsSideChannelSNMPWalk( + const char *oid, /* I - First numeric OID to query */ + double timeout, /* I - Timeout for each query in seconds */ + cups_sc_walk_func_t cb, /* I - Function to call with each value */ + void *context) /* I - Application-defined pointer to send to callback */ +{ + cups_sc_status_t status; /* Status of command */ + cups_sc_command_t rcommand; /* Response command */ + char real_data[2048];/* Real data buffer for response */ + int real_datalen, /* Real length of data buffer */ + real_oidlen, /* Length of returned OID string */ + oidlen; /* Length of first OID */ + const char *current_oid; /* Current OID */ + + + DEBUG_printf(("cupsSideChannelSNMPWalk(oid=\"%s\", timeout=%.3f, cb=%p, " + "context=%p)\n", oid, timeout, cb, context)); + + /* + * Range check input... + */ + + if (!oid || !*oid || !cb) + return (CUPS_SC_STATUS_BAD_MESSAGE); + + /* + * Loop until the OIDs don't match... + */ + + current_oid = oid; + oidlen = (int)strlen(oid); + + do + { + /* + * Send the request to the backend and wait for a response... + */ + + if (cupsSideChannelWrite(CUPS_SC_CMD_SNMP_GET_NEXT, CUPS_SC_STATUS_NONE, + current_oid, (int)strlen(current_oid), timeout)) + return (CUPS_SC_STATUS_TIMEOUT); + + real_datalen = sizeof(real_data); + if (cupsSideChannelRead(&rcommand, &status, real_data, &real_datalen, + timeout)) + return (CUPS_SC_STATUS_TIMEOUT); + + if (rcommand != CUPS_SC_CMD_SNMP_GET_NEXT) + return (CUPS_SC_STATUS_BAD_MESSAGE); + + if (status == CUPS_SC_STATUS_OK) + { + /* + * Parse the response of the form "oid\0value"... + */ + + if (strncmp(real_data, oid, oidlen) || real_data[oidlen] != '.') + { + /* + * Done with this set of OIDs... + */ + + return (CUPS_SC_STATUS_OK); + } + + real_oidlen = strlen(real_data) + 1; + real_datalen -= real_oidlen; + + /* + * Call the callback with the OID and data... + */ + + (*cb)(real_data, real_data + real_oidlen, real_datalen, context); + + /* + * Update the current OID... + */ + + current_oid = real_data; + } + } + while (status == CUPS_SC_STATUS_OK); + + return (status); +} + + /* * 'cupsSideChannelWrite()' - Write a side-channel message. * @@ -255,7 +480,7 @@ cupsSideChannelWrite( * Range check input... */ - if (command < CUPS_SC_CMD_SOFT_RESET || command > CUPS_SC_CMD_GET_STATE || + if (command < CUPS_SC_CMD_SOFT_RESET || command > CUPS_SC_CMD_SNMP_GET_NEXT || datalen < 0 || datalen > 16384 || (datalen > 0 && !data)) return (-1); diff --git a/cups/sidechannel.h b/cups/sidechannel.h index e2eae6eb78..741dca9469 100644 --- a/cups/sidechannel.h +++ b/cups/sidechannel.h @@ -59,7 +59,9 @@ enum cups_sc_command_e /**** Request command codes ****/ CUPS_SC_CMD_DRAIN_OUTPUT = 2, /* Drain all pending output */ CUPS_SC_CMD_GET_BIDI = 3, /* Return bidirectional capabilities */ CUPS_SC_CMD_GET_DEVICE_ID = 4, /* Return the IEEE-1284 device ID */ - CUPS_SC_CMD_GET_STATE = 5 /* Return the device state */ + CUPS_SC_CMD_GET_STATE = 5, /* Return the device state */ + CUPS_SC_CMD_SNMP_GET = 6, /* Query an SNMP OID @since CUPS 1.4@ */ + CUPS_SC_CMD_SNMP_GET_NEXT = 7 /* Query the next SNMP OID @since CUPS 1.4@ */ }; typedef enum cups_sc_command_e cups_sc_command_t; /**** Request command codes ****/ @@ -92,6 +94,10 @@ enum cups_sc_status_e /**** Response status codes ****/ typedef enum cups_sc_status_e cups_sc_status_t; /**** Response status codes ****/ +typedef void (*cups_sc_walk_func_t)(const char *oid, const char *data, + int datalen, void *context); + /**** SNMP walk callback ****/ + /* * Prototypes... @@ -109,6 +115,14 @@ extern int cupsSideChannelWrite(cups_sc_command_t command, const char *data, int datalen, double timeout) _CUPS_API_1_3; +/**** New in CUPS 1.4 ****/ +extern cups_sc_status_t cupsSideChannelSNMPGet(const char *oid, char *data, + int *datalen, double timeout) + _CUPS_API_1_4; +extern cups_sc_status_t cupsSideChannelSNMPWalk(const char *oid, double timeout, + cups_sc_walk_func_t cb, + void *context) _CUPS_API_1_4; + # ifdef __cplusplus } diff --git a/cups/snmp-private.h b/cups/snmp-private.h index ae03ca684f..de6d0f6f3e 100644 --- a/cups/snmp-private.h +++ b/cups/snmp-private.h @@ -121,10 +121,15 @@ 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 char *_cupsSNMPOIDToString(const int *src, char *dst, + size_t dstsize) _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 *_cupsSNMPStringToOID(const char *src, + int *dst, int dstsize) + _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, diff --git a/cups/snmp.c b/cups/snmp.c index f7843a10a0..34e7e2a57d 100644 --- a/cups/snmp.c +++ b/cups/snmp.c @@ -23,9 +23,11 @@ * specified OID. * _cupsSNMPIsOIDPrefixed() - Test whether a SNMP response uses the * specified OID prefix. + * _cupsSNMPOIDToString() - Convert an OID to a string. * _cupsSNMPOpen() - Open a SNMP socket. * _cupsSNMPRead() - Read and parse a SNMP response. * _cupsSNMPSetDebug() - Enable/disable debug logging to stderr. + * _cupsSNMPStringToOID() - Convert a numeric OID string to an OID array. * _cupsSNMPWalk() - Enumerate a group of OIDs. * _cupsSNMPWrite() - Send an SNMP query packet. * asn1_debug() - Decode an ASN1-encoded message. @@ -302,6 +304,48 @@ _cupsSNMPIsOIDPrefixed( } +/* + * '_cupsSNMPOIDToString()' - Convert an OID to a string. + * + * @since CUPS 1.4@ + */ + + +char * /* O - New string or @code NULL@ on error */ +_cupsSNMPOIDToString(const int *src, /* I - OID */ + char *dst, /* I - String buffer */ + size_t dstsize) /* I - Size of string buffer */ +{ + char *dstptr, /* Pointer into string buffer */ + *dstend; /* End of string buffer */ + + + DEBUG_printf(("_cupsSNMPOIDToString(src=%p, dst=%p, dstsize=" CUPS_LLFMT ")\n", + src, dst, CUPS_LLCAST dstsize)); + + /* + * Range check input... + */ + + if (!src || !dst || dstsize < 4) + return (NULL); + + /* + * Loop through the OID array and build a string... + */ + + for (dstptr = dst, dstend = dstptr + dstsize - 1; + *src >= 0 && dstptr < dstend; + src ++, dstptr += strlen(dstptr)) + snprintf(dstptr, dstend - dstptr + 1, ".%d", *src); + + if (*src >= 0) + return (NULL); + else + return (dst); +} + + /* * '_cupsSNMPOpen()' - Open a SNMP socket. * @@ -485,6 +529,76 @@ _cupsSNMPSetDebug(int level) /* I - 1 to enable debug output, 0 otherwise */ } +/* + * '_cupsSNMPStringToOID()' - Convert a numeric OID string to an OID array. + * + * This function converts a string of the form ".N.N.N.N.N" to the + * corresponding OID array terminated by -1. + * + * @code NULL@ is returned if the array is not large enough or the string is + * not a valid OID number. + * + * @since CUPS 1.4@ + */ + +int * /* O - Pointer to OID array or @code NULL@ on error */ +_cupsSNMPStringToOID(const char *src, /* I - OID string */ + int *dst, /* I - OID array */ + int dstsize)/* I - Number of integers in OID array */ +{ + int *dstptr, /* Pointer into OID array */ + *dstend; /* End of OID array */ + + + DEBUG_printf(("_cupsSNMPStringToOID(src=\"%s\", dst=%p, dstsize=%d)\n", + src, dst, dstsize)); + + /* + * Range check input... + */ + + if (!src || !dst || dstsize < 2) + return (NULL); + + /* + * Skip leading "."... + */ + + if (*src == '.') + src ++; + + /* + * Loop to the end of the string... + */ + + for (dstend = dst + dstsize - 1, dstptr = dst, *dstptr = 0; + *src && dstptr < dstend; + src ++) + { + if (*src == '.') + { + dstptr ++; + *dstptr = 0; + } + else if (isdigit(*src & 255)) + *dstptr = *dstptr * 10 + *src - '0'; + else + break; + } + + if (*src) + return (NULL); + + /* + * Terminate the end of the OID array and return... + */ + + dstptr[1] = -1; + + return (dst); +} + + /* * '_cupsSNMPWalk()' - Enumerate a group of OIDs. * diff --git a/cups/testoptions.c b/cups/testoptions.c new file mode 100644 index 0000000000..39aa0089f4 --- /dev/null +++ b/cups/testoptions.c @@ -0,0 +1,117 @@ +/* + * "$Id$" + * + * Option test program 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" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Test option processing functions. + */ + +/* + * Include necessary headers... + */ + +#include "string.h" +#include "cups.h" + + +/* + * 'main()' - Test option processing functions. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int status = 0, /* Exit status */ + num_options; /* Number of options */ + cups_option_t *options; /* Options */ + const char *value; /* Value of an option */ + + + if (argc == 1) + { + /* + * cupsParseOptions() + */ + + fputs("cupsParseOptions: ", stdout); + + num_options = cupsParseOptions("foo=1234 " + "bar=\"One Fish\",\"Two Fish\",\"Red Fish\"," + "\"Blue Fish\" " + "baz={param1=1 param2=2} " + "foobar=FOO\\ BAR " + "barfoo=barfoo " + "barfoo=\"\'BAR FOO\'\"", 0, &options); + + if (num_options != 5) + { + printf("FAIL (num_options=%d, expected 5)\n", num_options); + status ++; + } + else if ((value = cupsGetOption("foo", num_options, options)) == NULL || + strcmp(value, "1234")) + { + printf("FAIL (foo=\"%s\", expected \"1234\")\n", value); + status ++; + } + else if ((value = cupsGetOption("bar", num_options, options)) == NULL || + strcmp(value, "One Fish,Two Fish,Red Fish,Blue Fish")) + { + printf("FAIL (bar=\"%s\", expected \"One Fish,Two Fish,Red Fish,Blue " + "Fish\")\n", value); + status ++; + } + else if ((value = cupsGetOption("baz", num_options, options)) == NULL || + strcmp(value, "{param1=1 param2=2}")) + { + printf("FAIL (baz=\"%s\", expected \"{param1=1 param2=2}\")\n", value); + status ++; + } + else if ((value = cupsGetOption("foobar", num_options, options)) == NULL || + strcmp(value, "FOO BAR")) + { + printf("FAIL (foobar=\"%s\", expected \"FOO BAR\")\n", value); + status ++; + } + else if ((value = cupsGetOption("barfoo", num_options, options)) == NULL || + strcmp(value, "\'BAR FOO\'")) + { + printf("FAIL (barfoo=\"%s\", expected \"\'BAR FOO\'\")\n", value); + status ++; + } + else + puts("PASS"); + } + else + { + int i; /* Looping var */ + cups_option_t *option; /* Current option */ + + + num_options = cupsParseOptions(argv[1], 0, &options); + + for (i = 0, option = options; i < num_options; i ++, option ++) + printf("options[%d].name=\"%s\", value=\"%s\"\n", i, option->name, + option->value); + } + + exit (status); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/testsnmp.c b/cups/testsnmp.c index 2e0ef0d3d9..fbbc309293 100644 --- a/cups/testsnmp.c +++ b/cups/testsnmp.c @@ -37,7 +37,6 @@ */ static void print_packet(cups_snmp_t *packet, void *data); -static int *scan_oid(const char *s, int *oid, int oidsize); static int show_oid(int fd, const char *community, http_addr_t *addr, const char *s, int walk); static void usage(void); @@ -119,8 +118,8 @@ main(int argc, /* I - Number of command-line args */ if (!oid) { if (!show_oid(fd, community, &(host->addr), - walk ? "1.3.6.1.2.1.43" : - "1.3.6.1.2.1.43.10.2.1.4.1.1", walk)) + walk ? ".1.3.6.1.2.1.43" : + ".1.3.6.1.2.1.43.10.2.1.4.1.1", walk)) return (1); } @@ -137,14 +136,12 @@ print_packet(cups_snmp_t *packet, /* I - SNMP response packet */ void *data) /* I - User data pointer (not used) */ { int i; /* Looping var */ + char temp[1024]; /* Temporary OID string */ (void)data; - printf("%d", packet->object_name[0]); - for (i = 1; packet->object_name[i] >= 0; i ++) - printf(".%d", packet->object_name[i]); - fputs(" = ", stdout); + printf("%s = ", _cupsSNMPOIDToString(packet->object_name, temp, sizeof(temp))); switch (packet->object_type) { @@ -170,10 +167,8 @@ print_packet(cups_snmp_t *packet, /* I - SNMP response packet */ break; case CUPS_ASN1_OID : - printf("OID %d", packet->object_value.oid[0]); - for (i = 1; packet->object_value.oid[i] >= 0; i ++) - printf(".%d", packet->object_value.oid[i]); - putchar('\n'); + printf("OID %s\n", _cupsSNMPOIDToString(packet->object_value.oid, + temp, sizeof(temp))); break; case CUPS_ASN1_HEX_STRING : @@ -207,38 +202,6 @@ print_packet(cups_snmp_t *packet, /* I - SNMP response packet */ } -/* - * 'scan_oid()' - Scan an OID value. - */ - -static int * /* O - OID or NULL on error */ -scan_oid(const char *s, /* I - OID string */ - int *oid, /* I - OID array */ - int oidsize) /* I - Size of OID array in integers */ -{ - int i; /* Index into OID array */ - char *ptr; /* Pointer into string */ - - - for (ptr = (char *)s, i = 0, oidsize --; ptr && *ptr && i < oidsize; i ++) - { - if (!isdigit(*ptr & 255)) - return (NULL); - - oid[i] = strtol(ptr, &ptr, 10); - if (ptr && *ptr == '.') - ptr ++; - } - - if (i >= oidsize) - return (NULL); - - oid[i] = -1; - - return (oid); -} - - /* * 'show_oid()' - Show the specified OID. */ @@ -253,9 +216,10 @@ show_oid(int fd, /* I - SNMP socket */ int i; /* Looping var */ int oid[CUPS_SNMP_MAX_OID]; /* OID */ cups_snmp_t packet; /* SNMP packet */ + char temp[1024]; /* Temporary OID string */ - if (!scan_oid(s, oid, sizeof(oid) / sizeof(oid[0]))) + if (!_cupsSNMPStringToOID(s, oid, sizeof(oid) / sizeof(oid[0]))) { puts("testsnmp: Bad OID"); return (0); @@ -263,10 +227,7 @@ show_oid(int fd, /* I - SNMP socket */ if (walk) { - printf("_cupsSNMPWalk(%d", oid[0]); - for (i = 1; oid[i] >= 0; i ++) - printf(".%d", oid[i]); - puts("):"); + printf("_cupsSNMPWalk(%s): ", _cupsSNMPOIDToString(oid, temp, sizeof(temp))); if (_cupsSNMPWalk(fd, addr, CUPS_SNMP_VERSION_1, community, oid, 5.0, print_packet, NULL) < 0) @@ -277,10 +238,7 @@ show_oid(int fd, /* I - SNMP socket */ } else { - printf("_cupsSNMPWrite(%d", oid[0]); - for (i = 1; oid[i] >= 0; i ++) - printf(".%d", oid[i]); - fputs("): ", stdout); + printf("_cupsSNMPWrite(%s): ", _cupsSNMPOIDToString(oid, temp, sizeof(temp))); if (!_cupsSNMPWrite(fd, addr, CUPS_SNMP_VERSION_1, community, CUPS_ASN1_GET_REQUEST, 1, oid)) diff --git a/doc/help/api-filter.html b/doc/help/api-filter.html index 5febe8a868..279d180140 100644 --- a/doc/help/api-filter.html +++ b/doc/help/api-filter.html @@ -302,7 +302,8 @@ div.contents ul.subcontents li {
  • Exit Codes
  • Environment Variables
  • Communicating with the Scheduler
  • -
  • Communicating with the Backend
  • +
  • Communicating with the Backend
  • +
  • Communicating with Filters
  • Doing SNMP Queries with Network Printers
  • Functions
  • Data Types
  • Constants
  • Functions

    +

    Functions

     CUPS 1.2 cupsBackChannelRead

    Read data from the backchannel.

    @@ -888,6 +870,93 @@ The "datalen" parameter must be initialized to the size of the buffer pointed to by the "data" parameter. cupsSideChannelDoRequest() will update the value to contain the number of data bytes in the buffer. +

    +

     CUPS 1.4 cupsSideChannelSNMPGet

    +

    Query a SNMP OID's value.

    +

    +cups_sc_status_t cupsSideChannelSNMPGet (
    +    const char *oid,
    +    char *data,
    +    int *datalen,
    +    double timeout
    +);

    +

    Parameters

    +
    +
    oid
    +
    OID to query
    +
    data
    +
    Buffer for OID value
    +
    datalen
    +
    Size of OID buffer on entry, size of value on return
    +
    timeout
    +
    Timeout in seconds
    +
    +

    Return Value

    +

    Query status

    +

    Discussion

    +

    This function asks the backend to do a SNMP OID query on behalf of the +filter, port monitor, or backend using the default community name.
    +
    +"oid" contains a numeric OID consisting of integers separated by periods, +for example ".1.3.6.1.2.1.43". Symbolic names from SNMP MIBs are not +supported and must be converted to their numeric forms.
    +
    +On input, "data" and "datalen" provide the location and size of the +buffer to hold the OID value as a string. HEX-String (binary) values are +converted to hexadecimal strings representing the binary data, while +NULL-Value and unknown OID types are returned as the empty string. +The returned "datalen" does not include the trailing nul. + +CUPS_SC_STATUS_NOT_IMPLEMENTED is returned by backends that do not +support SNMP queries. CUPS_SC_STATUS_NO_RESPONSE is returned when +the printer does not respond to the SNMP query. + +

    +

     CUPS 1.4 cupsSideChannelSNMPWalk

    +

    Query multiple SNMP OID values.

    +

    +cups_sc_status_t cupsSideChannelSNMPWalk (
    +    const char *oid,
    +    double timeout,
    +    cups_sc_walk_func_t cb,
    +    void *context
    +);

    +

    Parameters

    +
    +
    oid
    +
    First numeric OID to query
    +
    timeout
    +
    Timeout for each query in seconds
    +
    cb
    +
    Function to call with each value
    +
    context
    +
    Application-defined pointer to send to callback
    +
    +

    Return Value

    +

    Status of first query of CUPS_SC_STATUS_OK on success

    +

    Discussion

    +

    This function asks the backend to do multiple SNMP OID queries on behalf +of the filter, port monitor, or backend using the default community name. +All OIDs under the "parent" OID are queried and the results are sent to +the callback function you provide.
    +
    +"oid" contains a numeric OID consisting of integers separated by periods, +for example ".1.3.6.1.2.1.43". Symbolic names from SNMP MIBs are not +supported and must be converted to their numeric forms.
    +
    +"timeout" specifies the timeout for each OID query. The total amount of +time will depend on the number of OID values found and the time required +for each query.
    +
    +"cb" provides a function to call for every value that is found. "context" +is an application-defined pointer that is sent to the callback function +along with the OID and current data. The data passed to the callback is the +same as returned by cupsSideChannelSNMPGet. + +CUPS_SC_STATUS_NOT_IMPLEMENTED is returned by backends that do not +support SNMP queries. CUPS_SC_STATUS_NO_RESPONSE is returned when +the printer does not respond to the first SNMP query. +

     CUPS 1.3 cupsSideChannelWrite

    Write a side-channel message.

    @@ -945,6 +1014,11 @@ typedef enum cups_sc_state_e cups_sc_state_t;

    typedef enum cups_sc_status_e cups_sc_status_t;

    +

    cups_sc_walk_func_t

    +

    SNMP walk callback

    +

    +typedef void (*cups_sc_walk_func_t)(const char *oid, const char *data, int datalen, void *context); +

    Constants

    cups_backend_e

    Backend exit codes

    @@ -984,6 +1058,10 @@ typedef enum cups_sc_status_e cups_sc_status_t;
    Return the IEEE-1284 device ID
    CUPS_SC_CMD_GET_STATE
    Return the device state
    +
    CUPS_SC_CMD_SNMP_GET  CUPS 1.4 
    +
    Query an SNMP OID
    +
    CUPS_SC_CMD_SNMP_GET_NEXT  CUPS 1.4 
    +
    Query the next SNMP OID
    CUPS_SC_CMD_SOFT_RESET
    Do a soft reset
    diff --git a/scheduler/printers.c b/scheduler/printers.c index ce03647b48..a2e71fb931 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -1236,6 +1236,23 @@ cupsdLoadAllPrinters(void) break; } } + else if (!strcasecmp(line, "Attribute") && value) + { + for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); + + if (!*valueptr) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + else + { + for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0'); + + cupsdSetPrinterAttr(p, value, valueptr); + + if (!strncmp(value, "marker-", 7)) + p->marker_time = time(NULL); + } + } else { /* @@ -1320,6 +1337,7 @@ cupsdSaveAllPrinters(void) struct tm *curdate; /* Current date */ cups_option_t *option; /* Current option */ const char *ptr; /* Pointer into info/location */ + ipp_attribute_t *marker; /* Current marker attribute */ /* @@ -1483,6 +1501,46 @@ cupsdSaveAllPrinters(void) i --, option ++) cupsFilePrintf(fp, "Option %s %s\n", option->name, option->value); + if ((marker = ippFindAttribute(printer->attrs, "marker-colors", + IPP_TAG_NAME)) != NULL) + { + cupsFilePrintf(fp, "Attribute %s %s", marker->name, + marker->values[0].string.text); + for (i = 1; i < marker->num_values; i ++) + cupsFilePrintf(fp, ",%s", marker->values[i].string.text); + cupsFilePuts(fp, "\n"); + } + + if ((marker = ippFindAttribute(printer->attrs, "marker-levels", + IPP_TAG_INTEGER)) != NULL) + { + cupsFilePrintf(fp, "Attribute %s %d", marker->name, + marker->values[0].integer); + for (i = 1; i < marker->num_values; i ++) + cupsFilePrintf(fp, ",%d", marker->values[i].integer); + cupsFilePuts(fp, "\n"); + } + + if ((marker = ippFindAttribute(printer->attrs, "marker-names", + IPP_TAG_NAME)) != NULL) + { + cupsFilePrintf(fp, "Attribute %s %s", marker->name, + marker->values[0].string.text); + for (i = 1; i < marker->num_values; i ++) + cupsFilePrintf(fp, ",%s", marker->values[i].string.text); + cupsFilePuts(fp, "\n"); + } + + if ((marker = ippFindAttribute(printer->attrs, "marker-types", + IPP_TAG_KEYWORD)) != NULL) + { + cupsFilePrintf(fp, "Attribute %s %s", marker->name, + marker->values[0].string.text); + for (i = 1; i < marker->num_values; i ++) + cupsFilePrintf(fp, ",%s", marker->values[i].string.text); + cupsFilePuts(fp, "\n"); + } + cupsFilePuts(fp, "\n"); #ifdef __sgi @@ -1762,6 +1820,8 @@ cupsdSetPrinterAttr( value = ptr; } } + + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } @@ -2314,6 +2374,28 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ p->type |= CUPS_PRINTER_COMMANDS; } + else if (!(p->type & CUPS_PRINTER_COMMANDS)) + { + /* + * See if this is a PostScript device without a command filter... + */ + + for (i = 0; i < ppd->num_filters; i ++) + if (!strncasecmp(ppd->filters[i], + "application/vnd.cups-postscript", 31)) + break; + + if (i < ppd->num_filters) + { + /* + * Add the generic PostScript command filter... + */ + + add_printer_filter(p, p->filetype, + "application/vnd.cups-command 0 commandtops"); + p->type |= CUPS_PRINTER_COMMANDS; + } + } if (p->type & CUPS_PRINTER_COMMANDS) {