]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Merge changes from CUPS 1.4svn-r7594.
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Mon, 19 May 2008 23:16:59 +0000 (23:16 +0000)
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Mon, 19 May 2008 23:16:59 +0000 (23:16 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@779 a1ca3aef-8c08-0410-bb20-df032aa958be

17 files changed:
CHANGES.txt
backend/network.c
backend/testbackend.c
cups/Dependencies
cups/Makefile
cups/api-filter.shtml
cups/libcups.exp
cups/libcups_s.exp
cups/options.c
cups/sidechannel.c
cups/sidechannel.h
cups/snmp-private.h
cups/snmp.c
cups/testoptions.c [new file with mode: 0644]
cups/testsnmp.c
doc/help/api-filter.html
scheduler/printers.c

index 575442955d4f6bd9fcff086047096e7a23a62e08..99155aed702f82b21ea62264c5e46a642f9b32a4 100644 (file)
@@ -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
index 46832a3d1f3a086fdbcab183244c6e878c74218f..daf05cda501be5b2d835f992c666a9e7998f4f03 100644 (file)
 #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)
index 4868beee1f791d42399e883b5a1d5bd3a45176cf..363572a7690cc9b260e0c1538e02f6048f8d6fef 100644 (file)
@@ -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);
 }
index 733948c3a4d9150b08d75fb6acb96ba48a48eb87..deb6a77eabdfca6d60cb55ad1c5d11d4fd499555 100644 (file)
@@ -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
index 48e6cedfa1011acb1a90d248cc81a7486a0441ea..3bf135002d007c877c98c10b0fe638d7174fbdf9 100644 (file)
@@ -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)
 #
index 60f28d32f127b8e0763bc119dea3ade5ef48132d..d4583b13c641d4764f3707c0d814374012a80123 100644 (file)
@@ -218,6 +218,11 @@ prefix strings:</p>
        #-copies to the job-media-sheets-completed attribute. The second
        form sets the job-media-sheets-completed attribute to #-pages.</dd>
 
+       <dt>PPD: keyword=value [keyword=value ...]</dt>
+       <dd>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.</dd>
+
        <dt>STATE: printer-state-reason [printer-state-reason ...]</dt>
        <dt>STATE: + printer-state-reason [printer-state-reason ...]</dt>
        <dt>STATE: - printer-state-reason [printer-state-reason ...]</dt>
@@ -235,7 +240,7 @@ prefix strings:</p>
 <p>Messages without one of these prefixes are treated as if they began with
 the "DEBUG:" prefix string.</p>
 
-<h3><a name="COMMUNICATING">Communicating with the Backend</a></h3>
+<h3><a name="COMMUNICATING_BACKEND">Communicating with the Backend</a></h3>
 
 <p>Filters can communicate with the backend via the
 <a href="#cupsBackChannelRead"><code>cupsBackChannelRead</code></a> and
@@ -282,6 +287,8 @@ else
   data[0] = '\0';
 </pre>
 
+<h3><a name="COMMUNICATING_FILTER">Communicating with Filters</a></h3>
+
 <p>Backends communicate with filters using the reciprocal functions
 <a href="#cupsBackChannelWrite"><code>cupsBackChannelWrite</code></a>,
 <a href="#cupsSideChannelRead"><code>cupsSideChannelRead</code></a>, and
@@ -304,10 +311,7 @@ Backends can either poll for commands using a <code>timeout</code> of 0.0, wait
 indefinitely for commands using a <code>timeout</code> of -1.0 (probably in a
 separate thread for that purpose), or use <code>select</code> or
 <code>poll</code> on the <code>CUPS_SC_FD</code> file descriptor (4) to handle
-input and output on several file descriptors at the same time. Backends can pass
-<code>NULL</code> for the <code>data</code> and <code>datalen</code> parameters
-since none of the commands sent by upstream filters contain any data at this
-time.</p>
+input and output on several file descriptors at the same time.</p>
 
 <p>Once a command is processed, the backend uses the
 <a href="#cupsSideChannelWrite"><code>cupsSideChannelWrite</code></a> function
@@ -319,16 +323,15 @@ side-channel command and respond to it:</p>
 
 <a href="#cups_sc_command_t">cups_sc_command_t</a> command;
 <a href="#cups_sc_status_t">cups_sc_status_t</a> status;
+char data[2048];
+int datalen = sizeof(data);
 
 /* Poll for a command... */
-if (!<a href="#cupsSideChannelRead">cupsSideChannelRead</a>(&amp;command, &amp;status, NULL, NULL, 0.0))
+if (!<a href="#cupsSideChannelRead">cupsSideChannelRead</a>(&amp;command, &amp;status, data, &amp;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 (!<a href="#cupsSideChannelRead">cupsSideChannelRead</a>(&amp;command, &amp;s
 
 <h3><a name="SNMP">Doing SNMP Queries with Network Printers</a></h3>
 
-<p>Re-write for side-channel-based SNMP queries.</p>
-
-<!--
 <p>The Simple Network Management Protocol (SNMP) allows you to get the current
 status, page counter, and supply levels from most network printers. Every
 piece of information is associated with an Object Identifier (OID), and
 every printer has a <em>community</em> name associated with it. OIDs can be
 queried directly or by "walking" over a range of OIDs with a common prefix.</p>
 
-<p>The CUPS SNMP functions provide a simple API for querying network printers.
-Queries are made using a datagram socket that is created using
-<a href="#cupsSNMPOpen"><code>cupsSNMPOpen</code></a> and destroyed using
-<a href="#cupsSNMPClose"><code>cupsSNMPClose</code></a>:</p>
-
-<pre class="example">
-#include &lt;cups/snmp.h&gt;
-
-int snmp = <a href="#cupsSNMPOpen">cupsSNMPOpen</a>(AF_INET);
-
-/* do some queries */
+<p>The two CUPS SNMP functions provide a simple API for querying network
+printers through the side-channel interface. Each accepts a string containing
+an OID like ".1.3.6.1.2.1.43.10.2.1.4.1.1" (the standard page counter OID)
+along with a timeout for the query.</p>
 
-<a href="#cupsSNMPClose">cupsSNMPClose</a>(snmp);
-</pre>
-
-<p>OIDs are simple C arrays of integers, terminated by a value of -1. For
-example, the page counter OID .1.3.6.1.2.1.43.10.2.1.4.1.1 would be:</p>
+<p>The <a href="#cupsSideChannelSNMPGet"><code>cupsSideChannelSNMPGet</code></a>
+function queries a single OID and returns the value as a string in a buffer
+you supply:</p>
 
 <pre class="example">
-int page_counter_oid[] = { 1, 3, 6, 1, 2, 1, 43, 10, 2, 1, 4, 1, 1, -1 };
-</pre>
-
-<p>You send a query using
-<a href="#cupsSNMPWrite"><code>cupsSNMPWrite</code></a> and read the value back
-using <a href="#cupsSNMPRead"><code>cupsSNMPRead</code></a>. The value is read
-into a structure called <a href="#cups_snmp_t"><code>cups_snmp_t</code></a>:</p>
-
-<pre class="example">
-#include &lt;cups/snmp.h&gt;
+#include &lt;cups/sidechannel.h&gt;
 
-int page_counter_oid[] = { 1, 3, 6, 1, 2, 1, 43, 10, 2, 1, 4, 1, 1, -1 };
-http_addrlist_t *host = httpAddrGetList("myprinter", AF_UNSPEC, "161");
-int snmp = <a href="#cupsSNMPOpen">cupsSNMPOpen</a>(host->addr.addr.sa_family);
-<a href="#cups_snmp_t">cups_snmp_t</a> packet;
+char data[512];
+int datalen = sizeof(data);
 
-<a href="#cupsSNMPWrite">cupsSNMPWrite</a>(snmp, &amp;(host->addr), CUPS_SNMP_VERSION_1,
-                <a href="#cupsSNMPDefaultCommunity">cupsSNMPDefaultCommunity</a>(), CUPS_ASN1_GET_REQUEST, 1,
-                page_counter_oid);
-if (<a href="#cupsSNMPRead">cupsSNMPRead</a>(snmp, &amp;packet, 5000))
+if (<a href="#cupsSideChannelSNMPGet">cupsSideChannelSNMPGet</a>(".1.3.6.1.2.1.43.10.2.1.4.1.1", data, &amp;datalen, 5.0)
+        == CUPS_SC_STATUS_OK)
 {
   /* Do something with the value */
-  printf("Page counter is: %d\n", packet.object_value.integer);
+  printf("Page counter is: %s\n", data);
 }
 </pre>
 
-<p>The <a href="#cupsSNMPWalk"><code>cupsSNMPWalk</code></a> function allows you
-to query a whole group of OIDs, calling a function of your choice for each OID
-that is found:</p>
+<p>The
+<a href="#cupsSideChannelSNMPWalk"><code>cupsSideChannelSNMPWalk</code></a>
+function allows you to query a whole group of OIDs, calling a function of your
+choice for each OID that is found:</p>
 
 <pre class="example">
-#include &lt;cups/snmp.h&gt;
+#include &lt;cups/sidechannel.h&gt;
 
 void
-my_callback(<a href="#cups_snmp_t">cups_snmp_t</a> *packet, void *data)
+my_callback(const char *oid, const char *data, int datalen, void *context)
 {
   /* Do something with the value */
+  printf("%s=%s\n", oid, data);
 }
 
-int printer_mib_oid[] = { 1, 3, 6, 1, 2, 1, 43, -1 };
-http_addrlist_t *host = httpAddrGetList("myprinter", AF_UNSPEC, "161");
-int snmp = <a href="#cupsSNMPOpen">cupsSNMPOpen</a>(host->addr.addr.sa_family);
+...
+
 void *my_data;
 
-<a href="#cupsSNMPWalk">cupsSNMPWalk</a>(snmp, &amp;(host->addr), CUPS_SNMP_VERSION_1,
-               <a href="#cupsSNMPDefaultCommunity">cupsSNMPDefaultCommunity</a>(), printer_mib_oid, my_callback, my_data);
+<a href="#cupsSideChannelSNMPWalk">cupsSNMPSideChannelWalk</a>(".1.3.6.1.2.1.43", 5.0, my_callback, my_data);
 </pre>
--->
\ No newline at end of file
index ed50f7a4fe877f3a1b48a510939aac8058bbe48a..ff0dd054212bd74d5a56a74187fb016b36819e07 100644 (file)
@@ -27,9 +27,11 @@ __cupsSNMPCopyOID
 __cupsSNMPDefaultCommunity
 __cupsSNMPIsOID
 __cupsSNMPIsOIDPrefixed
+__cupsSNMPOIDToString
 __cupsSNMPOpen
 __cupsSNMPRead
 __cupsSNMPSetDebug
+__cupsSNMPStringToOID
 __cupsSNMPWalk
 __cupsSNMPWrite
 __cupsStrAlloc
index 9872350936bebfd317cae5907138f4bda84247ef..129ad39a1c61e10a595eb9b68be617d126b6c8ef 100644 (file)
@@ -22,9 +22,11 @@ _cupsSNMPCopyOID
 _cupsSNMPDefaultCommunity
 _cupsSNMPIsOID
 _cupsSNMPIsOIDPrefixed
+_cupsSNMPOIDToString
 _cupsSNMPOpen
 _cupsSNMPRead
 _cupsSNMPSetDebug
+_cupsSNMPStringToOID
 _cupsSNMPWalk
 _cupsSNMPWrite
 _cupsStrAlloc
index 4ffb39f8244aa05359fb4b0078b9cf18df6c1278..3e4db23bef1a7c6d3ab0824a6901c73010d6f033 100644 (file)
@@ -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);
 }
 
index 9f1a64fa8da8797e7409baea5178c21f829c1114..9a009e9690fd7e83dcfec5e19dc68dae6d4ddf18 100644 (file)
@@ -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
  *
  * 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 <unistd.h>
 #include <errno.h>
 #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);
 
index e2eae6eb78c842be5e6e04c06eccbe9acb8fb6b0..741dca9469015c20cfa0e638376a0184f0b06e5f 100644 (file)
@@ -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
 }
index ae03ca684f932915de7ac7cd5b4b39b381d87529..de6d0f6f3e39f97de78c6c9a1a1fd095027142a3 100644 (file)
@@ -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,
index f7843a10a04dd23360e409c67fbfb333b2c9c1f4..34e7e2a57dd4b9110776df00651bc4b1aa68a5e8 100644 (file)
  *                                 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 (file)
index 0000000..39aa008
--- /dev/null
@@ -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$".
+ */
index 2e0ef0d3d93751f4c73ad03d562525f6f08de9bf..fbbc309293c2bff76d35ceeed65ceef27ba58e25 100644 (file)
@@ -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))
index 5febe8a868524322ba0cd7aea84ff82dc9834aa4..279d180140712e8d00f7f63371f33522cd430edb 100644 (file)
@@ -302,7 +302,8 @@ div.contents ul.subcontents li {
 <li><a href="#EXITCODES">Exit Codes</a></li>
 <li><a href="#ENVIRONMENT">Environment Variables</a></li>
 <li><a href="#MESSAGES">Communicating with the Scheduler</a></li>
-<li><a href="#COMMUNICATING">Communicating with the Backend</a></li>
+<li><a href="#COMMUNICATING_BACKEND">Communicating with the Backend</a></li>
+<li><a href="#COMMUNICATING_FILTER">Communicating with Filters</a></li>
 <li><a href="#SNMP">Doing SNMP Queries with Network Printers</a></li>
 </ul></li>
 <li><a href="#FUNCTIONS">Functions</a><ul class="code">
@@ -311,6 +312,8 @@ div.contents ul.subcontents li {
 <li><a href="#cupsBackendDeviceURI" title="Get the device URI for a backend.">cupsBackendDeviceURI</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="#cupsSideChannelSNMPGet" title="Query a SNMP OID's value.">cupsSideChannelSNMPGet</a></li>
+<li><a href="#cupsSideChannelSNMPWalk" title="Query multiple SNMP OID values.">cupsSideChannelSNMPWalk</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">
@@ -319,6 +322,7 @@ div.contents ul.subcontents 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_sc_walk_func_t" title="SNMP walk callback">cups_sc_walk_func_t</a></li>
 </ul></li>
 <li><a href="#ENUMERATIONS">Constants</a><ul class="code">
        <li><a href="#cups_backend_e" title="Backend exit codes">cups_backend_e</a></li>
@@ -329,7 +333,7 @@ div.contents ul.subcontents li {
 </ul></li>
 </ul>
 <!--
-  "$Id: api-filter.shtml 7288 2008-02-06 01:39:05Z mike $"
+  "$Id: api-filter.shtml 7502 2008-04-28 21:30:12Z mike $"
 
   Filter and backend programming introduction for the Common UNIX Printing
   System (CUPS).
@@ -548,6 +552,11 @@ prefix strings:</p>
        #-copies to the job-media-sheets-completed attribute. The second
        form sets the job-media-sheets-completed attribute to #-pages.</dd>
 
+       <dt>PPD: keyword=value [keyword=value ...]</dt>
+       <dd>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.</dd>
+
        <dt>STATE: printer-state-reason [printer-state-reason ...]</dt>
        <dt>STATE: + printer-state-reason [printer-state-reason ...]</dt>
        <dt>STATE: - printer-state-reason [printer-state-reason ...]</dt>
@@ -565,7 +574,7 @@ prefix strings:</p>
 <p>Messages without one of these prefixes are treated as if they began with
 the "DEBUG:" prefix string.</p>
 
-<h3><a name="COMMUNICATING">Communicating with the Backend</a></h3>
+<h3><a name="COMMUNICATING_BACKEND">Communicating with the Backend</a></h3>
 
 <p>Filters can communicate with the backend via the
 <a href="#cupsBackChannelRead"><code>cupsBackChannelRead</code></a> and
@@ -612,6 +621,8 @@ else
   data[0] = '\0';
 </pre>
 
+<h3><a name="COMMUNICATING_FILTER">Communicating with Filters</a></h3>
+
 <p>Backends communicate with filters using the reciprocal functions
 <a href="#cupsBackChannelWrite"><code>cupsBackChannelWrite</code></a>,
 <a href="#cupsSideChannelRead"><code>cupsSideChannelRead</code></a>, and
@@ -634,10 +645,7 @@ Backends can either poll for commands using a <code>timeout</code> of 0.0, wait
 indefinitely for commands using a <code>timeout</code> of -1.0 (probably in a
 separate thread for that purpose), or use <code>select</code> or
 <code>poll</code> on the <code>CUPS_SC_FD</code> file descriptor (4) to handle
-input and output on several file descriptors at the same time. Backends can pass
-<code>NULL</code> for the <code>data</code> and <code>datalen</code> parameters
-since none of the commands sent by upstream filters contain any data at this
-time.</p>
+input and output on several file descriptors at the same time.</p>
 
 <p>Once a command is processed, the backend uses the
 <a href="#cupsSideChannelWrite"><code>cupsSideChannelWrite</code></a> function
@@ -649,16 +657,15 @@ side-channel command and respond to it:</p>
 
 <a href="#cups_sc_command_t">cups_sc_command_t</a> command;
 <a href="#cups_sc_status_t">cups_sc_status_t</a> status;
+char data[2048];
+int datalen = sizeof(data);
 
 /* Poll for a command... */
-if (!<a href="#cupsSideChannelRead">cupsSideChannelRead</a>(&amp;command, &amp;status, NULL, NULL, 0.0))
+if (!<a href="#cupsSideChannelRead">cupsSideChannelRead</a>(&amp;command, &amp;status, data, &amp;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;
@@ -673,82 +680,57 @@ if (!<a href="#cupsSideChannelRead">cupsSideChannelRead</a>(&amp;command, &amp;s
 
 <h3><a name="SNMP">Doing SNMP Queries with Network Printers</a></h3>
 
-<p>Re-write for side-channel-based SNMP queries.</p>
-
-<!--
 <p>The Simple Network Management Protocol (SNMP) allows you to get the current
 status, page counter, and supply levels from most network printers. Every
 piece of information is associated with an Object Identifier (OID), and
 every printer has a <em>community</em> name associated with it. OIDs can be
 queried directly or by "walking" over a range of OIDs with a common prefix.</p>
 
-<p>The CUPS SNMP functions provide a simple API for querying network printers.
-Queries are made using a datagram socket that is created using
-<a href="#cupsSNMPOpen"><code>cupsSNMPOpen</code></a> and destroyed using
-<a href="#cupsSNMPClose"><code>cupsSNMPClose</code></a>:</p>
-
-<pre class="example">
-#include &lt;cups/snmp.h&gt;
-
-int snmp = <a href="#cupsSNMPOpen">cupsSNMPOpen</a>(AF_INET);
-
-/* do some queries */
-
-<a href="#cupsSNMPClose">cupsSNMPClose</a>(snmp);
-</pre>
+<p>The two CUPS SNMP functions provide a simple API for querying network
+printers through the side-channel interface. Each accepts a string containing
+an OID like ".1.3.6.1.2.1.43.10.2.1.4.1.1" (the standard page counter OID)
+along with a timeout for the query.</p>
 
-<p>OIDs are simple C arrays of integers, terminated by a value of -1. For
-example, the page counter OID .1.3.6.1.2.1.43.10.2.1.4.1.1 would be:</p>
+<p>The <a href="#cupsSideChannelSNMPGet"><code>cupsSideChannelSNMPGet</code></a>
+function queries a single OID and returns the value as a string in a buffer
+you supply:</p>
 
 <pre class="example">
-int page_counter_oid[] = { 1, 3, 6, 1, 2, 1, 43, 10, 2, 1, 4, 1, 1, -1 };
-</pre>
-
-<p>You send a query using
-<a href="#cupsSNMPWrite"><code>cupsSNMPWrite</code></a> and read the value back
-using <a href="#cupsSNMPRead"><code>cupsSNMPRead</code></a>. The value is read
-into a structure called <a href="#cups_snmp_t"><code>cups_snmp_t</code></a>:</p>
-
-<pre class="example">
-#include &lt;cups/snmp.h&gt;
+#include &lt;cups/sidechannel.h&gt;
 
-int page_counter_oid[] = { 1, 3, 6, 1, 2, 1, 43, 10, 2, 1, 4, 1, 1, -1 };
-http_addrlist_t *host = httpAddrGetList("myprinter", AF_UNSPEC, "161");
-int snmp = <a href="#cupsSNMPOpen">cupsSNMPOpen</a>(host->addr.addr.sa_family);
-<a href="#cups_snmp_t">cups_snmp_t</a> packet;
+char data[512];
+int datalen = sizeof(data);
 
-<a href="#cupsSNMPWrite">cupsSNMPWrite</a>(snmp, &amp;(host->addr), CUPS_SNMP_VERSION_1,
-                <a href="#cupsSNMPDefaultCommunity">cupsSNMPDefaultCommunity</a>(), CUPS_ASN1_GET_REQUEST, 1,
-                page_counter_oid);
-if (<a href="#cupsSNMPRead">cupsSNMPRead</a>(snmp, &amp;packet, 5000))
+if (<a href="#cupsSideChannelSNMPGet">cupsSideChannelSNMPGet</a>(".1.3.6.1.2.1.43.10.2.1.4.1.1", data, &amp;datalen, 5.0)
+        == CUPS_SC_STATUS_OK)
 {
   /* Do something with the value */
-  printf("Page counter is: %d\n", packet.object_value.integer);
+  printf("Page counter is: %s\n", data);
 }
 </pre>
 
-<p>The <a href="#cupsSNMPWalk"><code>cupsSNMPWalk</code></a> function allows you
-to query a whole group of OIDs, calling a function of your choice for each OID
-that is found:</p>
+<p>The
+<a href="#cupsSideChannelSNMPWalk"><code>cupsSideChannelSNMPWalk</code></a>
+function allows you to query a whole group of OIDs, calling a function of your
+choice for each OID that is found:</p>
 
 <pre class="example">
-#include &lt;cups/snmp.h&gt;
+#include &lt;cups/sidechannel.h&gt;
 
 void
-my_callback(<a href="#cups_snmp_t">cups_snmp_t</a> *packet, void *data)
+my_callback(const char *oid, const char *data, int datalen, void *context)
 {
   /* Do something with the value */
+  printf("%s=%s\n", oid, data);
 }
 
-int printer_mib_oid[] = { 1, 3, 6, 1, 2, 1, 43, -1 };
-http_addrlist_t *host = httpAddrGetList("myprinter", AF_UNSPEC, "161");
-int snmp = <a href="#cupsSNMPOpen">cupsSNMPOpen</a>(host->addr.addr.sa_family);
+...
+
 void *my_data;
 
-<a href="#cupsSNMPWalk">cupsSNMPWalk</a>(snmp, &amp;(host->addr), CUPS_SNMP_VERSION_1,
-               <a href="#cupsSNMPDefaultCommunity">cupsSNMPDefaultCommunity</a>(), printer_mib_oid, my_callback, my_data);
+<a href="#cupsSideChannelSNMPWalk">cupsSNMPSideChannelWalk</a>(".1.3.6.1.2.1.43", 5.0, my_callback, my_data);
 </pre>
---><h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
+<h2 class="title"><a name="FUNCTIONS">Functions</a></h2>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.2&nbsp;</span><a name="cupsBackChannelRead">cupsBackChannelRead</a></h3>
 <p class="description">Read data from the backchannel.</p>
 <p class="code">
@@ -888,6 +870,93 @@ The &quot;datalen&quot; parameter must be initialized to the size of the buffer
 pointed to by the &quot;data&quot; parameter.  cupsSideChannelDoRequest() will
 update the value to contain the number of data bytes in the buffer.
 
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSideChannelSNMPGet">cupsSideChannelSNMPGet</a></h3>
+<p class="description">Query a SNMP OID's value.</p>
+<p class="code">
+<a href="#cups_sc_status_t">cups_sc_status_t</a> cupsSideChannelSNMPGet (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *oid,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;char *data,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int *datalen,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;double timeout<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>oid</dt>
+<dd class="description">OID to query</dd>
+<dt>data</dt>
+<dd class="description">Buffer for OID value</dd>
+<dt>datalen</dt>
+<dd class="description">Size of OID buffer on entry, size of value on return</dd>
+<dt>timeout</dt>
+<dd class="description">Timeout in seconds</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Query status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="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.<br>
+<br>
+&quot;oid&quot; contains a numeric OID consisting of integers separated by periods,
+for example &quot;.1.3.6.1.2.1.43&quot;.  Symbolic names from SNMP MIBs are not
+supported and must be converted to their numeric forms.<br>
+<br>
+On input, &quot;data&quot; and &quot;datalen&quot; 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 &quot;datalen&quot; does not include the trailing nul.
+
+<code>CUPS_SC_STATUS_NOT_IMPLEMENTED</code> is returned by backends that do not
+support SNMP queries.  <code>CUPS_SC_STATUS_NO_RESPONSE</code> is returned when
+the printer does not respond to the SNMP query.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="cupsSideChannelSNMPWalk">cupsSideChannelSNMPWalk</a></h3>
+<p class="description">Query multiple SNMP OID values.</p>
+<p class="code">
+<a href="#cups_sc_status_t">cups_sc_status_t</a> cupsSideChannelSNMPWalk (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const char *oid,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;double timeout,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_sc_walk_func_t">cups_sc_walk_func_t</a> cb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *context<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>oid</dt>
+<dd class="description">First numeric OID to query</dd>
+<dt>timeout</dt>
+<dd class="description">Timeout for each query in seconds</dd>
+<dt>cb</dt>
+<dd class="description">Function to call with each value</dd>
+<dt>context</dt>
+<dd class="description">Application-defined pointer to send to callback</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of first query of <code>CUPS_SC_STATUS_OK</code> on success</p>
+<h4 class="discussion">Discussion</h4>
+<p class="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 &quot;parent&quot; OID are queried and the results are sent to
+the callback function you provide.<br>
+<br>
+&quot;oid&quot; contains a numeric OID consisting of integers separated by periods,
+for example &quot;.1.3.6.1.2.1.43&quot;.  Symbolic names from SNMP MIBs are not
+supported and must be converted to their numeric forms.<br>
+<br>
+&quot;timeout&quot; 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.<br>
+<br>
+&quot;cb&quot; provides a function to call for every value that is found. &quot;context&quot;
+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 <a href="#cupsSideChannelSNMPGet"><code>cupsSideChannelSNMPGet</code></a>.
+
+<code>CUPS_SC_STATUS_NOT_IMPLEMENTED</code> is returned by backends that do not
+support SNMP queries.  <code>CUPS_SC_STATUS_NO_RESPONSE</code> is returned when
+the printer does not respond to the first SNMP query.
+
 </p>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.3&nbsp;</span><a name="cupsSideChannelWrite">cupsSideChannelWrite</a></h3>
 <p class="description">Write a side-channel message.</p>
@@ -945,6 +1014,11 @@ typedef enum <a href="#cups_sc_state_e">cups_sc_state_e</a> cups_sc_state_t;
 <p class="code">
 typedef enum <a href="#cups_sc_status_e">cups_sc_status_e</a> cups_sc_status_t;
 </p>
+<h3 class="typedef"><a name="cups_sc_walk_func_t">cups_sc_walk_func_t</a></h3>
+<p class="description">SNMP walk callback</p>
+<p class="code">
+typedef void (*cups_sc_walk_func_t)(const char *oid, const char *data, int datalen, void *context);
+</p>
 <h2 class="title"><a name="ENUMERATIONS">Constants</a></h2>
 <h3 class="enumeration"><a name="cups_backend_e">cups_backend_e</a></h3>
 <p class="description">Backend exit codes</p>
@@ -984,6 +1058,10 @@ typedef enum <a href="#cups_sc_status_e">cups_sc_status_e</a> cups_sc_status_t;
 <dd class="description">Return the IEEE-1284 device ID</dd>
 <dt>CUPS_SC_CMD_GET_STATE </dt>
 <dd class="description">Return the device state</dd>
+<dt>CUPS_SC_CMD_SNMP_GET <span class="info">&nbsp;CUPS 1.4&nbsp;</span></dt>
+<dd class="description">Query an SNMP OID </dd>
+<dt>CUPS_SC_CMD_SNMP_GET_NEXT <span class="info">&nbsp;CUPS 1.4&nbsp;</span></dt>
+<dd class="description">Query the next SNMP OID </dd>
 <dt>CUPS_SC_CMD_SOFT_RESET </dt>
 <dd class="description">Do a soft reset</dd>
 </dl>
index ce03647b4885d980ac7dcdfbcf23474962b6e52d..a2e71fb931bc698d363f0065f5a17464c5d7db4b 100644 (file)
@@ -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, "</Printer>\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)
        {