Beispiel #1
0
int					/* O - -1 on error, 0 on success */
backendNetworkSideCB(
    int         print_fd,		/* I - Print file or -1 */
    int         device_fd,		/* I - Device file or -1 */
    int         snmp_fd,		/* I - SNMP socket */
    http_addr_t *addr,			/* I - Address of device */
    int         use_bc)			/* I - Use back-channel data? */
{
  cups_sc_command_t	command;	/* Request command */
  cups_sc_status_t	status;		/* Request/response status */
  char			data[65536];	/* Request/response data */
  int			datalen;	/* Request/response data size */
  const char		*device_id;	/* 1284DEVICEID env var */


  datalen = sizeof(data);

  if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
    return (-1);

  switch (command)
  {
    case CUPS_SC_CMD_DRAIN_OUTPUT :
       /*
        * Our sockets disable the Nagle algorithm and data is sent immediately.
	*/

        if (device_fd < 0)
	  status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
	else if (backendDrainOutput(print_fd, device_fd))
	  status = CUPS_SC_STATUS_IO_ERROR;
	else
          status = CUPS_SC_STATUS_OK;

	datalen = 0;
        break;

    case CUPS_SC_CMD_GET_BIDI :
	status  = CUPS_SC_STATUS_OK;
        data[0] = (char)use_bc;
        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)
	{
	  char		*dataptr;	/* Pointer into data */
	  cups_snmp_t	packet;		/* Packet from printer */
          const char	*snmp_value;	/* CUPS_SNMP_VALUE env var */

          if ((snmp_value = getenv("CUPS_SNMP_VALUE")) != NULL)
          {
            const char	*snmp_count;	/* CUPS_SNMP_COUNT env var */
            int		count;		/* Repetition count */

            if ((snmp_count = getenv("CUPS_SNMP_COUNT")) != NULL)
            {
              if ((count = atoi(snmp_count)) <= 0)
                count = 1;
            }
            else
              count = 1;

	    for (dataptr = data + strlen(data) + 1;
	         count > 0 && dataptr < (data + sizeof(data) - 1);
	         count --, dataptr += strlen(dataptr))
	      strlcpy(dataptr, snmp_value, sizeof(data) - (size_t)(dataptr - data));

	    fprintf(stderr, "DEBUG: Returning %s %s\n", data,
	            data + strlen(data) + 1);

	    status  = CUPS_SC_STATUS_OK;
	    datalen = (int)(dataptr - data);
	    break;
          }

          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))
	    {
	      size_t	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) - (size_t)(dataptr - data), "%d", packet.object_value.boolean);
	            datalen += (int)strlen(dataptr);
		    break;

	        case CUPS_ASN1_INTEGER :
		    snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%d",
		             packet.object_value.integer);
	            datalen += (int)strlen(dataptr);
		    break;

	        case CUPS_ASN1_BIT_STRING :
	        case CUPS_ASN1_OCTET_STRING :
		    if (packet.object_value.string.num_bytes < (sizeof(data) - (size_t)(dataptr - data)))
		      i = packet.object_value.string.num_bytes;
		    else
		      i = sizeof(data) - (size_t)(dataptr - data);

		    memcpy(dataptr, packet.object_value.string.bytes, i);

                    datalen += (int)i;
		    break;

	        case CUPS_ASN1_OID :
		    _cupsSNMPOIDToString(packet.object_value.oid, dataptr,
		                         sizeof(data) - (size_t)(dataptr - data));
	            datalen += (int)strlen(dataptr);
		    break;

                case CUPS_ASN1_HEX_STRING :
		    for (i = 0;
		         i < packet.object_value.string.num_bytes &&
			     dataptr < (data + sizeof(data) - 3);
			 i ++, dataptr += 2)
		      sprintf(dataptr, "%02X", packet.object_value.string.bytes[i]);
	            datalen += (int)strlen(dataptr);
		    break;

                case CUPS_ASN1_COUNTER :
		    snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.counter);
	            datalen += (int)strlen(dataptr);
		    break;

                case CUPS_ASN1_GAUGE :
		    snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.gauge);
	            datalen += (int)strlen(dataptr);
		    break;

                case CUPS_ASN1_TIMETICKS :
		    snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.timeticks);
	            datalen += (int)strlen(dataptr);
		    break;

                default :
	            fprintf(stderr, "DEBUG: Unknown OID value type %02X.\n", packet.object_type);

		case CUPS_ASN1_NULL_VALUE :
		    dataptr[0] = '\0';
		    break;
              }

	      fprintf(stderr, "DEBUG: Returning %s %s\n", data, data + datalen);

	      status = CUPS_SC_STATUS_OK;
	    }
	    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_CONNECTED :
	status  = CUPS_SC_STATUS_OK;
        data[0] = device_fd != -1;
        datalen = 1;
        break;

    case CUPS_SC_CMD_GET_DEVICE_ID :
        if (snmp_fd >= 0)
	{
	  cups_snmp_t	packet;		/* Packet from printer */
	  static const int ppmPrinterIEEE1284DeviceId[] =
	  		{ CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 };


          status  = CUPS_SC_STATUS_IO_ERROR;
	  datalen = 0;

          if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
	                     _cupsSNMPDefaultCommunity(),
	                     CUPS_ASN1_GET_REQUEST, 1,
			     ppmPrinterIEEE1284DeviceId))
          {
	    if (_cupsSNMPRead(snmp_fd, &packet, 1.0) &&
	        packet.object_type == CUPS_ASN1_OCTET_STRING)
	    {
	      strlcpy(data, (char *)packet.object_value.string.bytes,
	              sizeof(data));
	      datalen = (int)strlen(data);
	      status  = CUPS_SC_STATUS_OK;
	    }
	  }

	  break;
        }

	if ((device_id = getenv("1284DEVICEID")) != NULL)
	{
	  strlcpy(data, device_id, sizeof(data));
	  datalen = (int)strlen(data);
	  status  = CUPS_SC_STATUS_OK;
	  break;
	}

    default :
        status  = CUPS_SC_STATUS_NOT_IMPLEMENTED;
	datalen = 0;
	break;
  }

  return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
}
Beispiel #2
0
static void
backend_init_supplies(
    int         snmp_fd,		/* I - SNMP socket */
    http_addr_t *addr)			/* I - Printer address */
{
  int		i,			/* Looping var */
		type;			/* Current marker type */
  cups_file_t	*cachefile;		/* Cache file */
  const char	*cachedir;		/* CUPS_CACHEDIR value */
  char		addrstr[1024],		/* Address string */
		cachefilename[1024],	/* Cache filename */
		description[CUPS_SNMP_MAX_STRING],
					/* Device description string */
		value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 4 + 3)],
					/* Value string */
		*ptr,			/* Pointer into value string */
		*name_ptr;		/* Pointer into name string */
  cups_snmp_t	packet;			/* SNMP response packet */
  ppd_file_t	*ppd;			/* PPD file for this queue */
  ppd_attr_t	*ppdattr;		/* cupsSNMPSupplies attribute */
  static const char * const types[] =	/* Supply types */
		{
		  "other",
		  "unknown",
		  "toner",
		  "waste-toner",
		  "ink",
		  "ink-cartridge",
		  "ink-ribbon",
		  "waste-ink",
		  "opc",
		  "developer",
		  "fuser-oil",
		  "solid-wax",
		  "ribbon-wax",
		  "waste-wax",
		  "fuser",
		  "corona-wire",
		  "fuser-oil-wick",
		  "cleaner-unit",
		  "fuser-cleaning-pad",
		  "transfer-unit",
		  "toner-cartridge",
		  "fuser-oiler",
		  "water",
		  "waste-water",
		  "glue-water-additive",
		  "waste-paper",
		  "binding-supply",
		  "banding-supply",
		  "stitching-wire",
		  "shrink-wrap",
		  "paper-wrap",
		  "staples",
		  "inserts",
		  "covers"
		};


 /*
  * Reset state information...
  */

  current_addr  = *addr;
  current_state = -1;
  num_supplies  = -1;
  charset       = -1;

  memset(supplies, 0, sizeof(supplies));

 /*
  * See if we should be getting supply levels via SNMP...
  */

  if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL ||
      ((ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL &&
       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);

 /*
  * Get the device description...
  */

  if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
		     _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
		     hrDeviceDescr))
    return;

  if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
      packet.object_type != CUPS_ASN1_OCTET_STRING)
  {
    strlcpy(description, "Unknown", sizeof(description));
    num_supplies = 0;
  }
  else
    strlcpy(description, (char *)packet.object_value.string.bytes,
            sizeof(description));

  fprintf(stderr, "DEBUG2: hrDeviceDesc=\"%s\"\n", description);

 /*
  * See if we have already queried this device...
  */

  httpAddrString(addr, addrstr, sizeof(addrstr));

  if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL)
    cachedir = CUPS_CACHEDIR;

  snprintf(cachefilename, sizeof(cachefilename), "%s/%s.snmp", cachedir,
           addrstr);

  if ((cachefile = cupsFileOpen(cachefilename, "r")) != NULL)
  {
   /*
    * Yes, read the cache file:
    *
    *     3 num_supplies charset
    *     device description
    *     supply structures...
    */

    if (cupsFileGets(cachefile, value, sizeof(value)))
    {
      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,
	               (size_t)num_supplies * sizeof(backend_supplies_t));
        else
	{
	  num_supplies = -1;
	  charset      = -1;
	}
      }
      else
      {
        num_supplies = -1;
	charset      = -1;
      }
    }

    cupsFileClose(cachefile);
  }

 /*
  * If the cache information isn't correct, scan for supplies...
  */

  if (charset < 0)
  {
   /*
    * Get the configured character set...
    */

    int	oid[CUPS_SNMP_MAX_OID];		/* OID for character set */


    if (!_cupsSNMPWrite(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
			_cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
			prtGeneralCurrentLocalization))
      return;

    if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
	packet.object_type != CUPS_ASN1_INTEGER)
    {
      fprintf(stderr,
              "DEBUG: prtGeneralCurrentLocalization type is %x, expected %x!\n",
	      packet.object_type, CUPS_ASN1_INTEGER);
      return;
    }

    fprintf(stderr, "DEBUG2: prtGeneralCurrentLocalization=%d\n",
            packet.object_value.integer);

    _cupsSNMPCopyOID(oid, prtLocalizationCharacterSet, CUPS_SNMP_MAX_OID);
    oid[prtLocalizationCharacterSetOffset - 2] = packet.object_value.integer;


    if (!_cupsSNMPWrite(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
			_cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
			oid))
      return;

    if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
	packet.object_type != CUPS_ASN1_INTEGER)
    {
      fprintf(stderr,
              "DEBUG: prtLocalizationCharacterSet type is %x, expected %x!\n",
	      packet.object_type, CUPS_ASN1_INTEGER);
      return;
    }

    fprintf(stderr, "DEBUG2: prtLocalizationCharacterSet=%d\n",
	    packet.object_value.integer);
    charset = packet.object_value.integer;
  }

  if (num_supplies < 0)
  {
   /*
    * Walk the printer configuration information...
    */

    _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
		  _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry,
		  CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
  }

 /*
  * Save the cached information...
  */

  if (num_supplies < 0)
    num_supplies = 0;

  if ((cachefile = cupsFileOpen(cachefilename, "w")) != NULL)
  {
    cupsFilePrintf(cachefile, "3 %d %d\n", num_supplies, charset);
    cupsFilePrintf(cachefile, "%s\n", description);

    if (num_supplies > 0)
      cupsFileWrite(cachefile, (char *)supplies,
                    (size_t)num_supplies * sizeof(backend_supplies_t));

    cupsFileClose(cachefile);
  }

  if (num_supplies <= 0)
    return;

 /*
  * Get the colors...
  */

  for (i = 0; i < num_supplies; i ++)
    strlcpy(supplies[i].color, "none", sizeof(supplies[i].color));

  _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
                _cupsSNMPDefaultCommunity(), prtMarkerColorantValue,
	        CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);

 /*
  * Output the marker-colors attribute...
  */

  for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
  {
    if (i)
      *ptr++ = ',';

    strlcpy(ptr, supplies[i].color, sizeof(value) - (size_t)(ptr - value));
  }

  fprintf(stderr, "ATTR: marker-colors=%s\n", value);

 /*
  * 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 ++)
  {
    if (i)
      *ptr++ = ',';

    *ptr++ = '\'';
    *ptr++ = '\"';
    for (name_ptr = supplies[i].name; *name_ptr;)
    {
      if (*name_ptr == '\\' || *name_ptr == '\"' || *name_ptr == '\'')
      {
        *ptr++ = '\\';
        *ptr++ = '\\';
        *ptr++ = '\\';
      }

      *ptr++ = *name_ptr++;
    }
    *ptr++ = '\"';
    *ptr++ = '\'';
  }

  *ptr = '\0';

  fprintf(stderr, "ATTR: marker-names=%s\n", value);

 /*
  * Output the marker-types attribute...
  */

  for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
  {
    if (i)
      *ptr++ = ',';

    type = supplies[i].type;

    if (type < CUPS_TC_other || type > CUPS_TC_covers)
      strlcpy(ptr, "unknown", sizeof(value) - (size_t)(ptr - value));
    else
      strlcpy(ptr, types[type - CUPS_TC_other], sizeof(value) - (size_t)(ptr - value));
  }

  fprintf(stderr, "ATTR: marker-types=%s\n", value);
}
Beispiel #3
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line arguments */
{
  int			i;		/* Looping var */
  int			fd = -1;	/* SNMP socket */
  http_addrlist_t	*host = NULL;	/* Address of host */
  int			walk = 0;	/* Walk OIDs? */
  char			*oid = NULL;	/* Last OID shown */
  const char		*community;	/* Community name */


  fputs("_cupsSNMPDefaultCommunity: ", stdout);

  if ((community = _cupsSNMPDefaultCommunity()) == NULL)
  {
    puts("FAIL (NULL community name)");
    return (1);
  }

  printf("PASS (%s)\n", community);

 /*
  * Query OIDs from the command-line...
  */

  for (i = 1; i < argc; i ++)
    if (!strcmp(argv[i], "-c"))
    {
      i ++;

      if (i >= argc)
        usage();
      else
        community = argv[i];
    }
    else if (!strcmp(argv[i], "-d"))
      _cupsSNMPSetDebug(10);
    else if (!strcmp(argv[i], "-w"))
      walk = 1;
    else if (!host)
    {
      if ((host = httpAddrGetList(argv[i], AF_UNSPEC, "161")) == NULL)
      {
	printf("testsnmp: Unable to find \"%s\"!\n", argv[1]);
	return (1);
      }

      if (fd < 0)
      {
	fputs("_cupsSNMPOpen: ", stdout);

	if ((fd = _cupsSNMPOpen(host->addr.addr.sa_family)) < 0)
	{
	  printf("FAIL (%s)\n", strerror(errno));
	  return (1);
	}

	puts("PASS");
      }
    }
    else if (!show_oid(fd, community, &(host->addr), argv[i], walk))
      return (1);
    else
      oid = argv[i];

  if (!host)
    usage();

  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))
      return (1);
  }

  return (0);
}
Beispiel #4
0
int					/* O - 0 on success, -1 on error */
backendSNMPSupplies(
    int         snmp_fd,		/* I - SNMP socket */
    http_addr_t *addr,			/* I - Printer address */
    int         *page_count,		/* O - Page count */
    int         *printer_state)		/* O - Printer state */
{
  if (!httpAddrEqual(addr, &current_addr))
    backend_init_supplies(snmp_fd, addr);
  else if (num_supplies > 0)
    _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
		  _cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel,
		  CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);

  if (page_count)
    *page_count = -1;

  if (printer_state)
    *printer_state = -1;

  if (num_supplies > 0)
  {
    int		i,			/* Looping var */
		percent,		/* Percent full */
		new_state,		/* New state value */
		change_state,		/* State change */
		new_supply_state = 0;	/* Supply state */
    char	value[CUPS_MAX_SUPPLIES * 4],
					/* marker-levels value string */
		*ptr;			/* Pointer into value string */
    cups_snmp_t	packet;			/* SNMP response packet */

   /*
    * Generate the marker-levels value string...
    */

    for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
    {
      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 (supplies[i].sclass == CUPS_TC_receptacleThatIsFilled)
        percent = 100 - percent;

      if (percent <= 5)
      {
        switch (supplies[i].type)
        {
          case CUPS_TC_toner :
          case CUPS_TC_tonerCartridge :
              if (percent <= 1)
                new_supply_state |= CUPS_TONER_EMPTY;
              else
                new_supply_state |= CUPS_TONER_LOW;
              break;
          case CUPS_TC_ink :
          case CUPS_TC_inkCartridge :
          case CUPS_TC_inkRibbon :
          case CUPS_TC_solidWax :
          case CUPS_TC_ribbonWax :
              if (percent <= 1)
                new_supply_state |= CUPS_MARKER_SUPPLY_EMPTY;
              else
                new_supply_state |= CUPS_MARKER_SUPPLY_LOW;
              break;
          case CUPS_TC_developer :
              if (percent <= 1)
                new_supply_state |= CUPS_DEVELOPER_EMPTY;
              else
                new_supply_state |= CUPS_DEVELOPER_LOW;
              break;
          case CUPS_TC_coronaWire :
          case CUPS_TC_fuser :
          case CUPS_TC_opc :
          case CUPS_TC_transferUnit :
              if (percent <= 1)
                new_supply_state |= CUPS_OPC_LIFE_OVER;
              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 || (quirks & CUPS_SNMP_CAPACITY)) &&
          supplies[i].level >= 0)
        snprintf(ptr, sizeof(value) - (size_t)(ptr - value), "%d", percent);
      else
        strlcpy(ptr, "-1", sizeof(value) - (size_t)(ptr - value));
    }

    fprintf(stderr, "ATTR: marker-levels=%s\n", value);

    if (supply_state < 0)
      change_state = 0xffff;
    else
      change_state = supply_state ^ new_supply_state;

    fprintf(stderr, "DEBUG: new_supply_state=%x, change_state=%x\n",
            new_supply_state, change_state);

    for (i = 0;
         i < (int)(sizeof(supply_states) / sizeof(supply_states[0]));
         i ++)
      if (change_state & supply_states[i].bit)
      {
	fprintf(stderr, "STATE: %c%s\n",
		(new_supply_state & supply_states[i].bit) ? '+' : '-',
		supply_states[i].keyword);
      }

    supply_state = new_supply_state;

   /*
    * Get the current printer status bits...
    */

    if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
                       _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
                       hrPrinterDetectedErrorState))
      return (-1);

    if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
        packet.object_type != CUPS_ASN1_OCTET_STRING)
      return (-1);

    if (packet.object_value.string.num_bytes == 2)
      new_state = (packet.object_value.string.bytes[0] << 8) |
		  packet.object_value.string.bytes[1];
    else if (packet.object_value.string.num_bytes == 1)
      new_state = (packet.object_value.string.bytes[0] << 8);
    else
      new_state = 0;

    if (current_state < 0)
      change_state = 0xffff;
    else
      change_state = current_state ^ new_state;

    fprintf(stderr, "DEBUG: new_state=%x, change_state=%x\n", new_state,
            change_state);

    for (i = 0;
         i < (int)(sizeof(printer_states) / sizeof(printer_states[0]));
         i ++)
      if (change_state & printer_states[i].bit)
      {
	fprintf(stderr, "STATE: %c%s\n",
		(new_state & printer_states[i].bit) ? '+' : '-',
		printer_states[i].keyword);
      }

    current_state = new_state;

   /*
    * Get the current printer state...
    */

    if (printer_state)
    {
      if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
			 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
			 hrPrinterStatus))
	return (-1);

      if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
	  packet.object_type != CUPS_ASN1_INTEGER)
	return (-1);

      *printer_state = packet.object_value.integer;
    }

   /*
    * Get the current page count...
    */

    if (page_count)
    {
      if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
			 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
			 prtMarkerLifeCount))
	return (-1);

      if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
	  packet.object_type != CUPS_ASN1_COUNTER)
	return (-1);

      *page_count = packet.object_value.counter;
    }

    return (0);
  }
  else
    return (-1);
}