]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - backend/snmp-supplies.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / backend / snmp-supplies.c
index 1d550e6e66afa489f967e76b8724f8549131b9bd..515933bd25066f452213d73db31ae6570c1ef47b 100644 (file)
@@ -1,24 +1,13 @@
 /*
- * "$Id$"
+ * SNMP supplies functions for CUPS.
  *
- *   SNMP supplies functions for CUPS.
+ * Copyright 2008-2015 by Apple Inc.
  *
- *   Copyright 2008-2011 by Apple Inc.
- *
- *   These coded instructions, statements, and computer programs are the
- *   property of Apple Inc. and are protected by Federal copyright
- *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
- *   "LICENSE" which should have been included with this file.  If this
- *   file is missing or damaged, see the license at "http://www.cups.org/".
- *
- *   This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- *   backendSNMPSupplies()   - Get the current supplies for a device.
- *   backend_init_supplies() - Initialize the supplies list.
- *   backend_walk_cb()       - Interpret the supply value responses.
- *   utf16_to_utf8()         - Convert UTF-16 text to UTF-8.
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file.  If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
  */
 
 /*
@@ -26,6 +15,7 @@
  */
 
 #include "backend-private.h"
+#include <cups/ppd-private.h>
 #include <cups/array.h>
 
 
 #define CUPS_MAX_SUPPLIES      32      /* Maximum number of supplies for a printer */
 #define CUPS_SUPPLY_TIMEOUT    2.0     /* Timeout for SNMP lookups */
 
-#define CUPS_DEVELOPER_LOW             1
-#define CUPS_DEVELOPER_EMPTY           2
-#define CUPS_MARKER_SUPPLY_LOW         4
-#define CUPS_MARKER_SUPPLY_EMPTY       8
-#define CUPS_OPC_NEAR_EOL              16
-#define CUPS_OPC_LIFE_OVER             32
-#define CUPS_TONER_LOW                 64
-#define CUPS_TONER_EMPTY               128
+#define CUPS_DEVELOPER_LOW     0x0001
+#define CUPS_DEVELOPER_EMPTY   0x0002
+#define CUPS_MARKER_SUPPLY_LOW 0x0004
+#define CUPS_MARKER_SUPPLY_EMPTY 0x0008
+#define CUPS_OPC_NEAR_EOL      0x0010
+#define CUPS_OPC_LIFE_OVER     0x0020
+#define CUPS_TONER_LOW         0x0040
+#define CUPS_TONER_EMPTY       0x0080
+#define CUPS_WASTE_ALMOST_FULL 0x0100
+#define CUPS_WASTE_FULL                0x0200
+#define CUPS_CLEANER_NEAR_EOL  0x0400  /* Proposed JPS3 */
+#define CUPS_CLEANER_LIFE_OVER 0x0800  /* Proposed JPS3 */
+
+#define CUPS_SNMP_NONE         0x0000
+#define CUPS_SNMP_CAPACITY     0x0001  /* Supply levels reported as percentages */
 
 
 /*
@@ -55,6 +52,7 @@ typedef struct                                /**** Printer supply data ****/
   char name[CUPS_SNMP_MAX_STRING],     /* Name of supply */
        color[8];                       /* Color: "#RRGGBB" or "none" */
   int  colorant,                       /* Colorant index */
+       sclass,                         /* Supply class */
        type,                           /* Supply type */
        max_capacity,                   /* Maximum capacity */
        level;                          /* Current level value */
@@ -75,6 +73,8 @@ static http_addr_t    current_addr;   /* Current address */
 static int             current_state = -1;
                                        /* Current device state bits */
 static int             charset = -1;   /* Character set for supply names */
+static unsigned                quirks = CUPS_SNMP_NONE;
+                                       /* Quirks we have to work around */
 static int             num_supplies = 0;
                                        /* Number of supplies found */
 static backend_supplies_t supplies[CUPS_MAX_SUPPLIES];
@@ -139,6 +139,13 @@ static const int   prtMarkerSuppliesMaxCapacity[] =
                        (sizeof(prtMarkerSuppliesMaxCapacity) /
                         sizeof(prtMarkerSuppliesMaxCapacity[0]));
                                        /* Offset to supply index */
+static const int       prtMarkerSuppliesClass[] =
+                       { CUPS_OID_prtMarkerSuppliesClass, -1 },
+                                       /* Class OID */
+                       prtMarkerSuppliesClassOffset =
+                       (sizeof(prtMarkerSuppliesClass) /
+                        sizeof(prtMarkerSuppliesClass[0]));
+                                       /* Offset to supply index */
 static const int       prtMarkerSuppliesType[] =
                        { CUPS_OID_prtMarkerSuppliesType, -1 },
                                        /* Type OID */
@@ -146,10 +153,17 @@ static const int  prtMarkerSuppliesType[] =
                        (sizeof(prtMarkerSuppliesType) /
                         sizeof(prtMarkerSuppliesType[0]));
                                        /* Offset to supply index */
-
-static const backend_state_t const printer_states[] =
+static const int       prtMarkerSuppliesSupplyUnit[] =
+                       { CUPS_OID_prtMarkerSuppliesSupplyUnit, -1 },
+                                       /* Units OID */
+                       prtMarkerSuppliesSupplyUnitOffset =
+                       (sizeof(prtMarkerSuppliesSupplyUnit) /
+                        sizeof(prtMarkerSuppliesSupplyUnit[0]));
+                                       /* Offset to supply index */
+
+static const backend_state_t printer_states[] =
                        {
-                         { CUPS_TC_lowPaper, "media-low-report" },
+                         /* { CUPS_TC_lowPaper, "media-low-report" }, */
                          { CUPS_TC_noPaper | CUPS_TC_inputTrayEmpty, "media-empty-warning" },
                          /* { CUPS_TC_lowToner, "toner-low-report" }, */ /* now use prtMarkerSupplies */
                          /* { CUPS_TC_noToner, "toner-empty-warning" }, */ /* now use prtMarkerSupplies */
@@ -164,7 +178,7 @@ static const backend_state_t const printer_states[] =
                          { CUPS_TC_outputFull, "output-area-full-warning" }
                        };
 
-static const backend_state_t const supply_states[] =
+static const backend_state_t supply_states[] =
                        {
                          { CUPS_DEVELOPER_LOW, "developer-low-report" },
                          { CUPS_DEVELOPER_EMPTY, "developer-empty-warning" },
@@ -173,7 +187,11 @@ static const backend_state_t const supply_states[] =
                          { CUPS_OPC_NEAR_EOL, "opc-near-eol-report" },
                          { CUPS_OPC_LIFE_OVER, "opc-life-over-warning" },
                          { CUPS_TONER_LOW, "toner-low-report" },
-                         { CUPS_TONER_EMPTY, "toner-empty-warning" }
+                         { CUPS_TONER_EMPTY, "toner-empty-warning" },
+                         { CUPS_WASTE_ALMOST_FULL, "waste-receptacle-almost-full-report" },
+                         { CUPS_WASTE_FULL, "waste-receptacle-full-warning" },
+                         { CUPS_CLEANER_NEAR_EOL, "cleaner-life-almost-over-report" },
+                         { CUPS_CLEANER_LIFE_OVER, "cleaner-life-over-warning" },
                        };
 
 
@@ -229,12 +247,18 @@ backendSNMPSupplies(
 
     for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
     {
-      if (supplies[i].max_capacity > 0)
+      if (supplies[i].max_capacity > 0 && supplies[i].level >= 0)
        percent = 100 * supplies[i].level / supplies[i].max_capacity;
+      else if (supplies[i].level >= 0 && supplies[i].level <= 100 &&
+               (quirks & CUPS_SNMP_CAPACITY))
+        percent = supplies[i].level;
       else
         percent = 50;
 
-      if (percent <= 10)
+      if (supplies[i].sclass == CUPS_TC_receptacleThatIsFilled)
+        percent = 100 - percent;
+
+      if (percent <= 5)
       {
         switch (supplies[i].type)
         {
@@ -245,9 +269,6 @@ backendSNMPSupplies(
               else
                 new_supply_state |= CUPS_TONER_LOW;
               break;
-          case CUPS_TC_wasteToner :
-          case CUPS_TC_wasteInk :
-              break;
           case CUPS_TC_ink :
           case CUPS_TC_inkCartridge :
           case CUPS_TC_inkRibbon :
@@ -273,16 +294,36 @@ backendSNMPSupplies(
               else
                 new_supply_state |= CUPS_OPC_NEAR_EOL;
               break;
+#if 0 /* Because no two vendors report waste containers the same, disable SNMP reporting of same */
+          case CUPS_TC_wasteInk :
+          case CUPS_TC_wastePaper :
+          case CUPS_TC_wasteToner :
+          case CUPS_TC_wasteWater :
+          case CUPS_TC_wasteWax :
+              if (percent <= 1)
+                new_supply_state |= CUPS_WASTE_FULL;
+              else
+                new_supply_state |= CUPS_WASTE_ALMOST_FULL;
+              break;
+#endif /* 0 */
+          case CUPS_TC_cleanerUnit :
+          case CUPS_TC_fuserCleaningPad :
+              if (percent <= 1)
+                new_supply_state |= CUPS_CLEANER_LIFE_OVER;
+              else
+                new_supply_state |= CUPS_CLEANER_NEAR_EOL;
+              break;
         }
       }
 
       if (i)
         *ptr++ = ',';
 
-      if (supplies[i].max_capacity > 0)
-        sprintf(ptr, "%d", percent);
+      if ((supplies[i].max_capacity > 0 || (quirks & CUPS_SNMP_CAPACITY)) &&
+          supplies[i].level >= 0)
+        snprintf(ptr, sizeof(value) - (size_t)(ptr - value), "%d", percent);
       else
-        strcpy(ptr, "-1");
+        strlcpy(ptr, "-1", sizeof(value) - (size_t)(ptr - value));
     }
 
     fprintf(stderr, "ATTR: marker-levels=%s\n", value);
@@ -408,7 +449,7 @@ backend_init_supplies(
                cachefilename[1024],    /* Cache filename */
                description[CUPS_SNMP_MAX_STRING],
                                        /* Device description string */
-               value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 2 + 3)],
+               value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 4 + 3)],
                                        /* Value string */
                *ptr,                   /* Pointer into value string */
                *name_ptr;              /* Pointer into name string */
@@ -420,34 +461,34 @@ backend_init_supplies(
                  "other",
                  "unknown",
                  "toner",
-                 "wasteToner",
+                 "waste-toner",
                  "ink",
-                 "inkCartridge",
-                 "inkRibbon",
-                 "wasteInk",
+                 "ink-cartridge",
+                 "ink-ribbon",
+                 "waste-ink",
                  "opc",
                  "developer",
-                 "fuserOil",
-                 "solidWax",
-                 "ribbonWax",
-                 "wasteWax",
+                 "fuser-oil",
+                 "solid-wax",
+                 "ribbon-wax",
+                 "waste-wax",
                  "fuser",
-                 "coronaWire",
-                 "fuserOilWick",
-                 "cleanerUnit",
-                 "fuserCleaningPad",
-                 "transferUnit",
-                 "tonerCartridge",
-                 "fuserOiler",
+                 "corona-wire",
+                 "fuser-oil-wick",
+                 "cleaner-unit",
+                 "fuser-cleaning-pad",
+                 "transfer-unit",
+                 "toner-cartridge",
+                 "fuser-oiler",
                  "water",
-                 "wasteWater",
-                 "glueWaterAdditive",
-                 "wastePaper",
-                 "bindingSupply",
-                 "bandingSupply",
-                 "stitchingWire",
-                 "shrinkWrap",
-                 "paperWrap",
+                 "waste-water",
+                 "glue-water-additive",
+                 "waste-paper",
+                 "binding-supply",
+                 "banding-supply",
+                 "stitching-wire",
+                 "shrink-wrap",
+                 "paper-wrap",
                  "staples",
                  "inserts",
                  "covers"
@@ -471,12 +512,18 @@ backend_init_supplies(
 
   if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL ||
       ((ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL &&
-       ppdattr->value && strcasecmp(ppdattr->value, "true")))
+       ppdattr->value && _cups_strcasecmp(ppdattr->value, "true")))
   {
     ppdClose(ppd);
     return;
   }
 
+  if ((ppdattr = ppdFindAttr(ppd, "cupsSNMPQuirks", NULL)) != NULL)
+  {
+    if (!_cups_strcasecmp(ppdattr->value, "capacity"))
+      quirks |= CUPS_SNMP_CAPACITY;
+  }
+
   ppdClose(ppd);
 
  /*
@@ -517,20 +564,20 @@ backend_init_supplies(
    /*
     * Yes, read the cache file:
     *
-    *     2 num_supplies charset
+    *     3 num_supplies charset
     *     device description
     *     supply structures...
     */
 
     if (cupsFileGets(cachefile, value, sizeof(value)))
     {
-      if (sscanf(value, "2 %d%d", &num_supplies, &charset) == 2 &&
+      if (sscanf(value, "3 %d%d", &num_supplies, &charset) == 2 &&
           num_supplies <= CUPS_MAX_SUPPLIES &&
           cupsFileGets(cachefile, value, sizeof(value)))
       {
         if (!strcmp(description, value))
          cupsFileRead(cachefile, (char *)supplies,
-                      num_supplies * sizeof(backend_supplies_t));
+                      (size_t)num_supplies * sizeof(backend_supplies_t));
         else
        {
          num_supplies = -1;
@@ -620,12 +667,12 @@ backend_init_supplies(
 
   if ((cachefile = cupsFileOpen(cachefilename, "w")) != NULL)
   {
-    cupsFilePrintf(cachefile, "2 %d %d\n", num_supplies, charset);
+    cupsFilePrintf(cachefile, "3 %d %d\n", num_supplies, charset);
     cupsFilePrintf(cachefile, "%s\n", description);
 
     if (num_supplies > 0)
       cupsFileWrite(cachefile, (char *)supplies,
-                    num_supplies * sizeof(backend_supplies_t));
+                    (size_t)num_supplies * sizeof(backend_supplies_t));
 
     cupsFileClose(cachefile);
   }
@@ -638,7 +685,7 @@ backend_init_supplies(
   */
 
   for (i = 0; i < num_supplies; i ++)
-    strcpy(supplies[i].color, "none");
+    strlcpy(supplies[i].color, "none", sizeof(supplies[i].color));
 
   _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
                 _cupsSNMPDefaultCommunity(), prtMarkerColorantValue,
@@ -653,13 +700,14 @@ backend_init_supplies(
     if (i)
       *ptr++ = ',';
 
-    strcpy(ptr, supplies[i].color);
+    strlcpy(ptr, supplies[i].color, sizeof(value) - (size_t)(ptr - value));
   }
 
   fprintf(stderr, "ATTR: marker-colors=%s\n", value);
 
  /*
-  * Output the marker-names attribute...
+  * Output the marker-names attribute (the double quoting is necessary to deal
+  * with embedded quotes and commas in the marker names...)
   */
 
   for (i = 0, ptr = value; i < num_supplies; i ++)
@@ -667,15 +715,21 @@ backend_init_supplies(
     if (i)
       *ptr++ = ',';
 
+    *ptr++ = '\'';
     *ptr++ = '\"';
     for (name_ptr = supplies[i].name; *name_ptr;)
     {
-      if (*name_ptr == '\\' || *name_ptr == '\"')
+      if (*name_ptr == '\\' || *name_ptr == '\"' || *name_ptr == '\'')
+      {
         *ptr++ = '\\';
+        *ptr++ = '\\';
+        *ptr++ = '\\';
+      }
 
       *ptr++ = *name_ptr++;
     }
     *ptr++ = '\"';
+    *ptr++ = '\'';
   }
 
   *ptr = '\0';
@@ -694,9 +748,9 @@ backend_init_supplies(
     type = supplies[i].type;
 
     if (type < CUPS_TC_other || type > CUPS_TC_covers)
-      strcpy(ptr, "unknown");
+      strlcpy(ptr, "unknown", sizeof(value) - (size_t)(ptr - value));
     else
-      strcpy(ptr, types[type - CUPS_TC_other]);
+      strlcpy(ptr, types[type - CUPS_TC_other], sizeof(value) - (size_t)(ptr - value));
   }
 
   fprintf(stderr, "ATTR: marker-types=%s\n", value);
@@ -712,16 +766,33 @@ backend_walk_cb(cups_snmp_t *packet,      /* I - SNMP packet */
                 void        *data)     /* I - User data (unused) */
 {
   int  i, j, k;                        /* Looping vars */
-  static const char * const colors[8][2] =
+  static const char * const colors[][2] =
   {                                    /* Standard color names */
-    { "black",   "#000000" },
-    { "blue",    "#0000FF" },
-    { "cyan",    "#00FFFF" },
-    { "green",   "#00FF00" },
-    { "magenta", "#FF00FF" },
-    { "red",     "#FF0000" },
-    { "white",   "#FFFFFF" },
-    { "yellow",  "#FFFF00" }
+    { "black",         "#000000" },
+    { "blue",          "#0000FF" },
+    { "brown",         "#A52A2A" },
+    { "cyan",          "#00FFFF" },
+    { "dark-gray",     "#404040" },
+    { "dark gray",     "#404040" },
+    { "dark-yellow",   "#FFCC00" },
+    { "dark yellow",   "#FFCC00" },
+    { "gold",          "#FFD700" },
+    { "gray",          "#808080" },
+    { "green",         "#00FF00" },
+    { "light-black",   "#606060" },
+    { "light black",   "#606060" },
+    { "light-cyan",    "#E0FFFF" },
+    { "light cyan",    "#E0FFFF" },
+    { "light-gray",    "#D3D3D3" },
+    { "light gray",    "#D3D3D3" },
+    { "light-magenta", "#FF77FF" },
+    { "light magenta", "#FF77FF" },
+    { "magenta",       "#FF00FF" },
+    { "orange",        "#FFA500" },
+    { "red",           "#FF0000" },
+    { "silver",        "#C0C0C0" },
+    { "white",         "#FFFFFF" },
+    { "yellow",        "#FFFF00" }
   };
 
 
@@ -743,9 +814,10 @@ backend_walk_cb(cups_snmp_t *packet,       /* I - SNMP packet */
       if (supplies[j].colorant == i)
       {
        for (k = 0; k < (int)(sizeof(colors) / sizeof(colors[0])); k ++)
-         if (!strcmp(colors[k][0], (char *)packet->object_value.string.bytes))
+         if (!_cups_strcasecmp(colors[k][0],
+                               (char *)packet->object_value.string.bytes))
          {
-           strcpy(supplies[j].color, colors[k][1]);
+           strlcpy(supplies[j].color, colors[k][1], sizeof(supplies[j].color));
            break;
          }
       }
@@ -801,6 +873,7 @@ backend_walk_cb(cups_snmp_t *packet,        /* I - SNMP packet */
           break;
 
       case CUPS_TC_csShiftJIS :
+      case CUPS_TC_csWindows31J : /* Close enough for our purposes */
          cupsCharsetToUTF8((cups_utf8_t *)supplies[i - 1].name,
                            (char *)packet->object_value.string.bytes,
                            sizeof(supplies[0].name), CUPS_JIS_X0213);
@@ -833,7 +906,6 @@ backend_walk_cb(cups_snmp_t *packet,        /* I - SNMP packet */
           {
            char        *src, *dst;     /* Pointers into strings */
 
-
            /*
            * Loop safe because both the object_value and supplies char arrays
            * are CUPS_SNMP_MAX_STRING elements long.
@@ -878,7 +950,8 @@ backend_walk_cb(cups_snmp_t *packet,        /* I - SNMP packet */
 
     supplies[i - 1].level = packet->object_value.integer;
   }
-  else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity))
+  else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity) &&
+           !(quirks & CUPS_SNMP_CAPACITY))
   {
    /*
     * Get max capacity...
@@ -895,7 +968,28 @@ backend_walk_cb(cups_snmp_t *packet,       /* I - SNMP packet */
     if (i > num_supplies)
       num_supplies = i;
 
-    supplies[i - 1].max_capacity = packet->object_value.integer;
+    if (supplies[i - 1].max_capacity == 0 &&
+        packet->object_value.integer > 0)
+      supplies[i - 1].max_capacity = packet->object_value.integer;
+  }
+  else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesClass))
+  {
+   /*
+    * Get marker class...
+    */
+
+    i = packet->object_name[prtMarkerSuppliesClassOffset];
+    if (i < 1 || i > CUPS_MAX_SUPPLIES ||
+        packet->object_type != CUPS_ASN1_INTEGER)
+      return;
+
+    fprintf(stderr, "DEBUG2: prtMarkerSuppliesClass.1.%d = %d\n", i,
+            packet->object_value.integer);
+
+    if (i > num_supplies)
+      num_supplies = i;
+
+    supplies[i - 1].sclass = packet->object_value.integer;
   }
   else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
   {
@@ -916,6 +1010,26 @@ backend_walk_cb(cups_snmp_t *packet,      /* I - SNMP packet */
 
     supplies[i - 1].type = packet->object_value.integer;
   }
+  else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesSupplyUnit))
+  {
+   /*
+    * Get units for capacity...
+    */
+
+    i = packet->object_name[prtMarkerSuppliesSupplyUnitOffset];
+    if (i < 1 || i > CUPS_MAX_SUPPLIES ||
+        packet->object_type != CUPS_ASN1_INTEGER)
+      return;
+
+    fprintf(stderr, "DEBUG2: prtMarkerSuppliesSupplyUnit.1.%d = %d\n", i,
+            packet->object_value.integer);
+
+    if (i > num_supplies)
+      num_supplies = i;
+
+    if (packet->object_value.integer == CUPS_TC_percent)
+      supplies[i - 1].max_capacity = 100;
+  }
 }
 
 
@@ -940,9 +1054,9 @@ utf16_to_utf8(
   for (ptr = temp; srcsize >= 2;)
   {
     if (le)
-      ch = src[0] | (src[1] << 8);
+      ch = (cups_utf32_t)(src[0] | (src[1] << 8));
     else
-      ch = (src[0] << 8) | src[1];
+      ch = (cups_utf32_t)((src[0] << 8) | src[1]);
 
     src += 2;
     srcsize -= 2;
@@ -953,13 +1067,13 @@ utf16_to_utf8(
       * Multi-word UTF-16 char...
       */
 
-      int lch;                 /* Lower word */
+      cups_utf32_t lch;                        /* Lower word */
 
 
       if (le)
-       lch = src[0] | (src[1] << 8);
+       lch = (cups_utf32_t)(src[0] | (src[1] << 8));
       else
-       lch = (src[0] << 8) | src[1];
+       lch = (cups_utf32_t)((src[0] << 8) | src[1]);
 
       if (lch >= 0xdc00 && lch <= 0xdfff)
       {
@@ -976,10 +1090,5 @@ utf16_to_utf8(
 
   *ptr = '\0';
 
-  cupsUTF32ToUTF8(dst, temp, dstsize);
+  cupsUTF32ToUTF8(dst, temp, (int)dstsize);
 }
-
-
-/*
- * End of "$Id$".
- */