]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - backend/snmp.c
Merge changes from CUPS 1.4svn-r7874.
[thirdparty/cups.git] / backend / snmp.c
index 4e0cd1d6f764d40f400d8e0d1584e6f4f4d82409..712981cfd48a235cbb385f6cc9eb9d279f10ab80 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: snmp.c 6649 2007-07-11 21:46:42Z mike $"
+ * "$Id: snmp.c 7506 2008-04-29 04:38:47Z mike $"
  *
  *   SNMP discovery backend for the Common UNIX Printing System (CUPS).
  *
@@ -48,7 +48,6 @@
 #include "backend-private.h"
 #include <cups/array.h>
 #include <cups/file.h>
-#include <cups/snmp.h>
 #include <cups/http-private.h>
 #include <regex.h>
 
 /*
  * This backend implements SNMP printer discovery.  It uses a broadcast-
  * based approach to get SNMP response packets from potential printers,
- * tries a mDNS lookup (Mac OS X only at present), a URI lookup based on
- * the device description string, and finally a probe of port 9100
- * (AppSocket) and 515 (LPD).
+ * requesting OIDs from the Host and Port Monitor MIBs, does a URI
+ * lookup based on the device description string, and finally a probe of
+ * port 9100 (AppSocket) and 515 (LPD).
  *
  * The current focus is on printers with internal network cards, although
- * the code also works with many external print servers as well.  Future
- * versions will support scanning for vendor-specific SNMP OIDs and the
- * new PWG Port Monitor MIB and not just the Host MIB OIDs.
+ * the code also works with many external print servers as well.
  *
  * The backend reads the snmp.conf file from the CUPS_SERVERROOT directory
  * which can contain comments, blank lines, or any number of the following
@@ -91,6 +88,7 @@
  * print servers:
  *
  *     Axis OfficeBasic, 5400, 5600
+ *     Brother
  *     EPSON
  *     Genicom
  *     HP JetDirect
  * Types...
  */
 
+enum                                   /**** Request IDs for each field ****/
+{
+  DEVICE_TYPE = 1,
+  DEVICE_DESCRIPTION,
+  DEVICE_LOCATION,
+  DEVICE_ID,
+  DEVICE_URI,
+  DEVICE_PRODUCT
+};
+
 typedef struct device_uri_s            /**** DeviceURI values ****/
 {
   regex_t      re;                     /* Regular expression to match */
@@ -125,7 +133,10 @@ typedef struct snmp_cache_s                /**** SNMP scan cache ****/
   char         *addrname,              /* Name of device */
                *uri,                   /* device-uri */
                *id,                    /* device-id */
+               *info,                  /* device-info */
+               *location,              /* device-location */
                *make_and_model;        /* device-make-and-model */
+  int          sent;                   /* Has this device been listed? */
 } snmp_cache_t;
 
 
@@ -133,7 +144,7 @@ typedef struct snmp_cache_s         /**** SNMP scan cache ****/
  * Private CUPS API to set the last error...
  */
 
-extern void    _cupsSetError(ipp_status_t status, const char *message);
+extern void            _cupsSetError(ipp_status_t status, const char *message);
 
 
 /*
@@ -175,10 +186,15 @@ static cups_array_t       *Addresses = NULL;
 static cups_array_t    *Communities = NULL;
 static cups_array_t    *Devices = NULL;
 static int             DebugLevel = 0;
-static int             DeviceDescOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 };
-static unsigned                DeviceDescRequest;
-static int             DeviceTypeOID[] = { CUPS_OID_hrDeviceType, 1, -1 };
-static unsigned                DeviceTypeRequest;
+static const int       DescriptionOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 };
+static const int       LocationOID[] = { CUPS_OID_sysLocation, 0, -1 };
+static const int       DeviceTypeOID[] = { CUPS_OID_hrDeviceType, 1, -1 };
+static const int       DeviceIdOID[] = { CUPS_OID_ppmPrinterIEEE1284DeviceId, 1, -1 };
+static const int       UriOID[] = { CUPS_OID_ppmPortServiceNameOrURI, 1, 1, -1 };
+static const int       LexmarkProductOID[] = { 1,3,6,1,4,1,641,2,1,2,1,2,1,-1 };
+static const int       LexmarkProductOID2[] = { 1,3,6,1,4,1,674,10898,100,2,1,2,1,2,1,-1 };
+static const int       LexmarkDeviceIdOID[] = { 1,3,6,1,4,1,641,2,1,2,1,3,1,-1 };
+static const int       XeroxProductOID[] = { 1,3,6,1,4,1,128,2,1,3,1,2,0,-1 };
 static cups_array_t    *DeviceURIs = NULL;
 static int             HostNameLookups = 0;
 static int             MaxRunTime = 120;
@@ -236,7 +252,7 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
   * Open the SNMP socket...
   */
 
-  if ((fd = cupsSNMPOpen(AF_INET)) < 0)
+  if ((fd = _cupsSNMPOpen(AF_INET)) < 0)
     return (1);
 
  /*
@@ -245,7 +261,7 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
 
   read_snmp_conf(argv[1]);
 
-  cupsSNMPSetDebug(DebugLevel);
+  _cupsSNMPSetDebug(DebugLevel);
 
   Devices = cupsArrayNew((cups_array_func_t)compare_cache, NULL);
 
@@ -259,7 +275,7 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
   * Close, free, and return with no errors...
   */
 
-  cupsSNMPClose(fd);
+  _cupsSNMPClose(fd);
 
   free_array(Addresses);
   free_array(Communities);
@@ -657,14 +673,8 @@ static void
 list_device(snmp_cache_t *cache)       /* I - Cached device */
 {
   if (cache->uri)
-  {
-    printf("network %s \"%s\" \"%s %s\" \"%s\"\n",
-           cache->uri,
-          cache->make_and_model ? cache->make_and_model : "Unknown",
-          cache->make_and_model ? cache->make_and_model : "Unknown",
-          cache->addrname, cache->id ? cache->id : "");
-    fflush(stdout);
-  }
+    cupsBackendReport("network", cache->uri, cache->make_and_model,
+                      cache->info, cache->id, cache->location);
 }
 
 
@@ -905,7 +915,7 @@ read_snmp_response(int fd)          /* I - SNMP socket file descriptor */
   * Read the response data...
   */
 
-  if (!cupsSNMPRead(fd, &packet, -1.0))
+  if (!_cupsSNMPRead(fd, &packet, -1.0))
   {
     fprintf(stderr, "ERROR: Unable to read data from socket: %s\n",
             strerror(errno));
@@ -949,75 +959,172 @@ read_snmp_response(int fd)               /* I - SNMP socket file descriptor */
   * Process the message...
   */
 
-  if (packet.request_id == DeviceTypeRequest)
+  switch (packet.request_id)
   {
-   /*
-    * Got the device type response...
-    */
+    case DEVICE_TYPE :
+       /*
+       * Got the device type response...
+       */
+
+       if (device)
+       {
+         debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
+                      addrname);
+         return;
+       }
+
+       /*
+       * Add the device and request the device data...
+       */
+
+       add_cache(&(packet.address), addrname, NULL, NULL, NULL);
+
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_DESCRIPTION, DescriptionOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_ID, DeviceIdOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_URI, UriOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_LOCATION, LocationOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_PRODUCT, LexmarkProductOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_PRODUCT, LexmarkProductOID2);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_URI, LexmarkDeviceIdOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_PRODUCT, XeroxProductOID);
+        break;
+
+    case DEVICE_DESCRIPTION :
+       if (device && packet.object_type == CUPS_ASN1_OCTET_STRING)
+       {
+        /*
+         * Update an existing cache entry...
+         */
+
+         char  make_model[256];        /* Make and model */
+
+
+         if (strchr(packet.object_value.string, ':') &&
+             strchr(packet.object_value.string, ';'))
+         {
+          /*
+           * Description is the IEEE-1284 device ID...
+           */
 
-    if (device)
-    {
-      debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
-                  addrname);
-      return;
-    }
+           if (!device->id)
+             device->id = strdup(packet.object_value.string);
 
-   /*
-    * Add the device and request the device description...
-    */
+           backendGetMakeModel(packet.object_value.string, make_model,
+                               sizeof(make_model));
 
-    add_cache(&(packet.address), addrname, NULL, NULL, NULL);
+            if (device->info)
+             free(device->info);
 
-    cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community,
-                  CUPS_ASN1_GET_REQUEST, DeviceDescRequest, DeviceDescOID);
-  }
-  else if (packet.request_id == DeviceDescRequest &&
-           packet.object_type == CUPS_ASN1_OCTET_STRING)
-  {
-   /*
-    * Update an existing cache entry...
-    */
+           device->info = strdup(make_model);
+         }
+         else
+         {
+          /*
+           * Description is plain text...
+           */
 
-    char       make_model[256];        /* Make and model */
+           fix_make_model(make_model, packet.object_value.string,
+                          sizeof(make_model));
 
+            if (device->info)
+             free(device->info);
 
-    if (!device)
-    {
-      debug_printf("DEBUG: Discarding device description for \"%s\"...\n",
-                  addrname);
-      return;
-    }
+           device->info = strdup(packet.object_value.string);
+         }
 
-   /*
-    * Convert the description to a make and model string...
-    */
+         if (!device->make_and_model)
+           device->make_and_model = strdup(make_model);
+        }
+       break;
 
-    if (strchr(packet.object_value.string, ':') &&
-        strchr(packet.object_value.string, ';'))
-    {
-     /*
-      * Description is the IEEE-1284 device ID...
-      */
+    case DEVICE_ID :
+       if (device && packet.object_type == CUPS_ASN1_OCTET_STRING)
+       {
+        /*
+         * Update an existing cache entry...
+         */
 
-      backendGetMakeModel(packet.object_value.string, make_model,
-                         sizeof(make_model));
-    }
-    else
-    {
-     /*
-      * Description is plain text...
-      */
+         char  make_model[256];        /* Make and model */
 
-      fix_make_model(make_model, packet.object_value.string,
-                     sizeof(make_model));
-    }
 
-    if (device->make_and_model)
-      free(device->make_and_model);
+         if (device->id)
+           free(device->id);
 
-    device->make_and_model = strdup(make_model);
+         device->id = strdup(packet.object_value.string);
+
+        /*
+         * Convert the ID to a make and model string...
+         */
+
+         backendGetMakeModel(packet.object_value.string, make_model,
+                             sizeof(make_model));
+         if (device->make_and_model)
+           free(device->make_and_model);
+
+         device->make_and_model = strdup(make_model);
+       }
+       break;
+
+    case DEVICE_LOCATION :
+       if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+           !device->location)
+         device->location = strdup(packet.object_value.string);
+       break;
+
+    case DEVICE_PRODUCT :
+       if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+           !device->id)
+       {
+        /*
+         * Update an existing cache entry...
+         */
+
+          if (!device->info)
+           device->info = strdup(packet.object_value.string);
+
+          if (device->make_and_model)
+           free(device->make_and_model);
+
+         device->make_and_model = strdup(packet.object_value.string);
+       }
+       break;
+
+    case DEVICE_URI :
+       if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+           !device->uri)
+       {
+        /*
+         * Update an existing cache entry...
+         */
+
+         if (!strncmp(packet.object_value.string, "lpr:", 4))
+         {
+          /*
+           * We want "lpd://..." for the URI...
+           */
+
+           packet.object_value.string[2] = 'd';
+         }
 
-    probe_device(device);
+         device->uri = strdup(packet.object_value.string);
+       }
+       break;
   }
 }
 
@@ -1056,15 +1163,8 @@ scan_devices(int fd)                     /* I - SNMP socket */
   snmp_cache_t         *device;        /* Current device */
 
 
- /*
-  * Setup the request IDs...
-  */
-
   gettimeofday(&StartTime, NULL);
 
-  DeviceTypeRequest = StartTime.tv_sec;
-  DeviceDescRequest = StartTime.tv_sec + 1;
-
  /*
   * First send all of the broadcast queries...
   */
@@ -1103,8 +1203,8 @@ scan_devices(int fd)                      /* I - SNMP socket */
                   community, address);
 
       for (addr = addrs; addr; addr = addr->next)
-        cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community,
-                     CUPS_ASN1_GET_REQUEST, DeviceTypeRequest, DeviceTypeOID);
+        _cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community,
+                      CUPS_ASN1_GET_REQUEST, DEVICE_TYPE, DeviceTypeOID);
     }
 
     httpAddrFreeList(addrs);
@@ -1134,21 +1234,30 @@ scan_devices(int fd)                    /* I - SNMP socket */
     if (FD_ISSET(fd, &input))
       read_snmp_response(fd);
     else
-      break;
-  }
+    {
+     /*
+      * List devices with complete information...
+      */
 
- /*
-  * Finally, probe all of the printers we discovered to see how they are
-  * connected...
-  */
+      int sent_something = 0;
 
-  for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
-       device;
-       device = (snmp_cache_t *)cupsArrayNext(Devices))
-    if (MaxRunTime > 0 && run_time() >= MaxRunTime)
-      break;
-    else if (!device->uri)
-      probe_device(device);
+      for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
+           device;
+          device = (snmp_cache_t *)cupsArrayNext(Devices))
+        if (!device->sent && device->info && device->make_and_model)
+       {
+         if (device->uri)
+           list_device(device);
+         else
+           probe_device(device);
+
+         device->sent = sent_something = 1;
+       }
+
+      if (!sent_something)
+        break;
+    }
+  }
 
   debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
 }
@@ -1226,5 +1335,5 @@ update_cache(snmp_cache_t *device,        /* I - Device */
 
 
 /*
- * End of "$Id: snmp.c 6649 2007-07-11 21:46:42Z mike $".
+ * End of "$Id: snmp.c 7506 2008-04-29 04:38:47Z mike $".
  */