asn1_decode_snmp(unsigned char *buffer,	/* I - Buffer */
                 size_t        len,	/* I - Size of buffer */
                 cups_snmp_t   *packet)	/* I - SNMP packet */
{
  unsigned char	*bufptr,		/* Pointer into the data */
		*bufend;		/* End of data */
  unsigned	length;			/* Length of value */


 /*
  * Initialize the decoding...
  */

  memset(packet, 0, sizeof(cups_snmp_t));
  packet->object_name[0] = -1;

  bufptr = buffer;
  bufend = buffer + len;

  if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE)
    snmp_set_error(packet, _("Packet does not start with SEQUENCE"));
  else if (asn1_get_length(&bufptr, bufend) == 0)
    snmp_set_error(packet, _("SEQUENCE uses indefinite length"));
  else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
    snmp_set_error(packet, _("No version number"));
  else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
    snmp_set_error(packet, _("Version uses indefinite length"));
  else if ((packet->version = asn1_get_integer(&bufptr, bufend, length))
               != CUPS_SNMP_VERSION_1)
    snmp_set_error(packet, _("Bad SNMP version number"));
  else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_OCTET_STRING)
    snmp_set_error(packet, _("No community name"));
  else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
    snmp_set_error(packet, _("Community name uses indefinite length"));
  else
  {
    asn1_get_string(&bufptr, bufend, length, packet->community,
                    sizeof(packet->community));

    if ((packet->request_type = (cups_asn1_t)asn1_get_type(&bufptr, bufend))
            != CUPS_ASN1_GET_RESPONSE)
      snmp_set_error(packet, _("Packet does not contain a Get-Response-PDU"));
    else if (asn1_get_length(&bufptr, bufend) == 0)
      snmp_set_error(packet, _("Get-Response-PDU uses indefinite length"));
    else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
      snmp_set_error(packet, _("No request-id"));
    else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
      snmp_set_error(packet, _("request-id uses indefinite length"));
    else
    {
      packet->request_id = (unsigned)asn1_get_integer(&bufptr, bufend, length);

      if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
	snmp_set_error(packet, _("No error-status"));
      else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
	snmp_set_error(packet, _("error-status uses indefinite length"));
      else
      {
	packet->error_status = asn1_get_integer(&bufptr, bufend, length);

	if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_INTEGER)
	  snmp_set_error(packet, _("No error-index"));
	else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
	  snmp_set_error(packet, _("error-index uses indefinite length"));
	else
	{
	  packet->error_index = asn1_get_integer(&bufptr, bufend, length);

          if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE)
	    snmp_set_error(packet, _("No variable-bindings SEQUENCE"));
	  else if (asn1_get_length(&bufptr, bufend) == 0)
	    snmp_set_error(packet,
	                   _("variable-bindings uses indefinite length"));
	  else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_SEQUENCE)
	    snmp_set_error(packet, _("No VarBind SEQUENCE"));
	  else if (asn1_get_length(&bufptr, bufend) == 0)
	    snmp_set_error(packet, _("VarBind uses indefinite length"));
	  else if (asn1_get_type(&bufptr, bufend) != CUPS_ASN1_OID)
	    snmp_set_error(packet, _("No name OID"));
	  else if ((length = asn1_get_length(&bufptr, bufend)) == 0)
	    snmp_set_error(packet, _("Name OID uses indefinite length"));
          else
	  {
	    asn1_get_oid(&bufptr, bufend, length, packet->object_name,
	                 CUPS_SNMP_MAX_OID);

            packet->object_type = (cups_asn1_t)asn1_get_type(&bufptr, bufend);

	    if ((length = asn1_get_length(&bufptr, bufend)) == 0 &&
	        packet->object_type != CUPS_ASN1_NULL_VALUE &&
	        packet->object_type != CUPS_ASN1_OCTET_STRING)
	      snmp_set_error(packet, _("Value uses indefinite length"));
	    else
	    {
	      switch (packet->object_type)
	      {
	        case CUPS_ASN1_BOOLEAN :
		    packet->object_value.boolean =
		        asn1_get_integer(&bufptr, bufend, length);
	            break;

	        case CUPS_ASN1_INTEGER :
		    packet->object_value.integer =
		        asn1_get_integer(&bufptr, bufend, length);
	            break;

		case CUPS_ASN1_NULL_VALUE :
		    break;

	        case CUPS_ASN1_OCTET_STRING :
	        case CUPS_ASN1_BIT_STRING :
	        case CUPS_ASN1_HEX_STRING :
		    packet->object_value.string.num_bytes = length;
		    asn1_get_string(&bufptr, bufend, length,
		                    (char *)packet->object_value.string.bytes,
				    sizeof(packet->object_value.string.bytes));
	            break;

	        case CUPS_ASN1_OID :
		    asn1_get_oid(&bufptr, bufend, length,
		                 packet->object_value.oid, CUPS_SNMP_MAX_OID);
	            break;

	        case CUPS_ASN1_COUNTER :
		    packet->object_value.counter =
		        asn1_get_integer(&bufptr, bufend, length);
	            break;

	        case CUPS_ASN1_GAUGE :
		    packet->object_value.gauge =
		        (unsigned)asn1_get_integer(&bufptr, bufend, length);
	            break;

	        case CUPS_ASN1_TIMETICKS :
		    packet->object_value.timeticks =
		        (unsigned)asn1_get_integer(&bufptr, bufend, length);
	            break;

                default :
		    snmp_set_error(packet, _("Unsupported value type"));
		    break;
	      }
	    }
          }
	}
      }
    }
  }

  return (packet->error ? -1 : 0);
}