mirror of https://gitee.com/openkylin/cups.git
1097 lines
30 KiB
C
1097 lines
30 KiB
C
|
/*
|
|||
|
* SNMP supplies functions for CUPS.
|
|||
|
*
|
|||
|
* Copyright © 2008-2015 by Apple Inc.
|
|||
|
*
|
|||
|
* Licensed under Apache License v2.0. See the file "LICENSE" for more
|
|||
|
* information.
|
|||
|
*/
|
|||
|
|
|||
|
/*
|
|||
|
* Include necessary headers.
|
|||
|
*/
|
|||
|
|
|||
|
#include "backend-private.h"
|
|||
|
#include <cups/ppd-private.h>
|
|||
|
#include <cups/array.h>
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Local constants...
|
|||
|
*/
|
|||
|
|
|||
|
#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 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 */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Local structures...
|
|||
|
*/
|
|||
|
|
|||
|
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 */
|
|||
|
} backend_supplies_t;
|
|||
|
|
|||
|
typedef struct /**** Printer state table ****/
|
|||
|
{
|
|||
|
int bit; /* State bit */
|
|||
|
const char *keyword; /* IPP printer-state-reasons keyword */
|
|||
|
} backend_state_t;
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Local globals...
|
|||
|
*/
|
|||
|
|
|||
|
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];
|
|||
|
/* Supply information */
|
|||
|
static int supply_state = -1;
|
|||
|
/* Supply state info */
|
|||
|
|
|||
|
static const int hrDeviceDescr[] =
|
|||
|
{ CUPS_OID_hrDeviceDescr, 1, -1 };
|
|||
|
/* Device description OID */
|
|||
|
static const int hrPrinterStatus[] =
|
|||
|
{ CUPS_OID_hrPrinterStatus, 1, -1 };
|
|||
|
/* Current state OID */
|
|||
|
static const int hrPrinterDetectedErrorState[] =
|
|||
|
{ CUPS_OID_hrPrinterDetectedErrorState, 1, -1 };
|
|||
|
/* Current printer state bits OID */
|
|||
|
static const int prtGeneralCurrentLocalization[] =
|
|||
|
{ CUPS_OID_prtGeneralCurrentLocalization, 1, -1 };
|
|||
|
static const int prtLocalizationCharacterSet[] =
|
|||
|
{ CUPS_OID_prtLocalizationCharacterSet, 1, 1, -1 },
|
|||
|
prtLocalizationCharacterSetOffset =
|
|||
|
(sizeof(prtLocalizationCharacterSet) /
|
|||
|
sizeof(prtLocalizationCharacterSet[0]));
|
|||
|
static const int prtMarkerColorantValue[] =
|
|||
|
{ CUPS_OID_prtMarkerColorantValue, -1 },
|
|||
|
/* Colorant OID */
|
|||
|
prtMarkerColorantValueOffset =
|
|||
|
(sizeof(prtMarkerColorantValue) /
|
|||
|
sizeof(prtMarkerColorantValue[0]));
|
|||
|
/* Offset to colorant index */
|
|||
|
static const int prtMarkerLifeCount[] =
|
|||
|
{ CUPS_OID_prtMarkerLifeCount, 1, 1, -1 };
|
|||
|
/* Page counter OID */
|
|||
|
static const int prtMarkerSuppliesEntry[] =
|
|||
|
{ CUPS_OID_prtMarkerSuppliesEntry, -1 };
|
|||
|
/* Supplies OID */
|
|||
|
static const int prtMarkerSuppliesColorantIndex[] =
|
|||
|
{ CUPS_OID_prtMarkerSuppliesColorantIndex, -1 },
|
|||
|
/* Colorant index OID */
|
|||
|
prtMarkerSuppliesColorantIndexOffset =
|
|||
|
(sizeof(prtMarkerSuppliesColorantIndex) /
|
|||
|
sizeof(prtMarkerSuppliesColorantIndex[0]));
|
|||
|
/* Offset to supply index */
|
|||
|
static const int prtMarkerSuppliesDescription[] =
|
|||
|
{ CUPS_OID_prtMarkerSuppliesDescription, -1 },
|
|||
|
/* Description OID */
|
|||
|
prtMarkerSuppliesDescriptionOffset =
|
|||
|
(sizeof(prtMarkerSuppliesDescription) /
|
|||
|
sizeof(prtMarkerSuppliesDescription[0]));
|
|||
|
/* Offset to supply index */
|
|||
|
static const int prtMarkerSuppliesLevel[] =
|
|||
|
{ CUPS_OID_prtMarkerSuppliesLevel, -1 },
|
|||
|
/* Level OID */
|
|||
|
prtMarkerSuppliesLevelOffset =
|
|||
|
(sizeof(prtMarkerSuppliesLevel) /
|
|||
|
sizeof(prtMarkerSuppliesLevel[0]));
|
|||
|
/* Offset to supply index */
|
|||
|
static const int prtMarkerSuppliesMaxCapacity[] =
|
|||
|
{ CUPS_OID_prtMarkerSuppliesMaxCapacity, -1 },
|
|||
|
/* Max capacity OID */
|
|||
|
prtMarkerSuppliesMaxCapacityOffset =
|
|||
|
(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 */
|
|||
|
prtMarkerSuppliesTypeOffset =
|
|||
|
(sizeof(prtMarkerSuppliesType) /
|
|||
|
sizeof(prtMarkerSuppliesType[0]));
|
|||
|
/* Offset to supply index */
|
|||
|
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_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 */
|
|||
|
{ CUPS_TC_doorOpen, "door-open-report" },
|
|||
|
{ CUPS_TC_jammed, "media-jam-warning" },
|
|||
|
/* { CUPS_TC_offline, "offline-report" }, */ /* unreliable */
|
|||
|
/* { CUPS_TC_serviceRequested | CUPS_TC_overduePreventMaint, "service-needed-warning" }, */ /* unreliable */
|
|||
|
{ CUPS_TC_inputTrayMissing, "input-tray-missing-warning" },
|
|||
|
{ CUPS_TC_outputTrayMissing, "output-tray-missing-warning" },
|
|||
|
{ CUPS_TC_markerSupplyMissing, "marker-supply-missing-warning" },
|
|||
|
{ CUPS_TC_outputNearFull, "output-area-almost-full-report" },
|
|||
|
{ CUPS_TC_outputFull, "output-area-full-warning" }
|
|||
|
};
|
|||
|
|
|||
|
static const backend_state_t supply_states[] =
|
|||
|
{
|
|||
|
{ CUPS_DEVELOPER_LOW, "developer-low-report" },
|
|||
|
{ CUPS_DEVELOPER_EMPTY, "developer-empty-warning" },
|
|||
|
{ CUPS_MARKER_SUPPLY_LOW, "marker-supply-low-report" },
|
|||
|
{ CUPS_MARKER_SUPPLY_EMPTY, "marker-supply-empty-warning" },
|
|||
|
{ 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_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" },
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Local functions...
|
|||
|
*/
|
|||
|
|
|||
|
static void backend_init_supplies(int snmp_fd, http_addr_t *addr);
|
|||
|
static void backend_walk_cb(cups_snmp_t *packet, void *data);
|
|||
|
static void utf16_to_utf8(cups_utf8_t *dst, const unsigned char *src,
|
|||
|
size_t srcsize, size_t dstsize, int le);
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'backendSNMPSupplies()' - Get the current supplies for a device.
|
|||
|
*/
|
|||
|
|
|||
|
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, ¤t_addr))
|
|||
|
backend_init_supplies(snmp_fd, addr);
|
|||
|
else if (num_supplies > 0)
|
|||
|
_cupsSNMPWalk(snmp_fd, ¤t_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);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'backend_init_supplies()' - Initialize the supplies list.
|
|||
|
*/
|
|||
|
|
|||
|
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 */
|
|||
|
const char *community; /* SNMP community name */
|
|||
|
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...
|
|||
|
*/
|
|||
|
|
|||
|
community = _cupsSNMPDefaultCommunity();
|
|||
|
if (!*community)
|
|||
|
return;
|
|||
|
|
|||
|
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,
|
|||
|
community, 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, ¤t_addr, CUPS_SNMP_VERSION_1,
|
|||
|
community, 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, ¤t_addr, CUPS_SNMP_VERSION_1,
|
|||
|
community, 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, ¤t_addr, CUPS_SNMP_VERSION_1,
|
|||
|
community, 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, ¤t_addr, CUPS_SNMP_VERSION_1,
|
|||
|
community, 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);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'backend_walk_cb()' - Interpret the supply value responses.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
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[][2] =
|
|||
|
{ /* Standard color names */
|
|||
|
{ "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" }
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
(void)data;
|
|||
|
|
|||
|
if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) &&
|
|||
|
packet->object_type == CUPS_ASN1_OCTET_STRING)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get colorant...
|
|||
|
*/
|
|||
|
|
|||
|
i = packet->object_name[prtMarkerColorantValueOffset];
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG2: prtMarkerColorantValue.1.%d = \"%s\"\n", i,
|
|||
|
(char *)packet->object_value.string.bytes);
|
|||
|
|
|||
|
for (j = 0; j < num_supplies; j ++)
|
|||
|
if (supplies[j].colorant == i)
|
|||
|
{
|
|||
|
for (k = 0; k < (int)(sizeof(colors) / sizeof(colors[0])); k ++)
|
|||
|
if (!_cups_strcasecmp(colors[k][0],
|
|||
|
(char *)packet->object_value.string.bytes))
|
|||
|
{
|
|||
|
strlcpy(supplies[j].color, colors[k][1], sizeof(supplies[j].color));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get colorant index...
|
|||
|
*/
|
|||
|
|
|||
|
i = packet->object_name[prtMarkerSuppliesColorantIndexOffset];
|
|||
|
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
|
|||
|
packet->object_type != CUPS_ASN1_INTEGER)
|
|||
|
return;
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG2: prtMarkerSuppliesColorantIndex.1.%d = %d\n", i,
|
|||
|
packet->object_value.integer);
|
|||
|
|
|||
|
if (i > num_supplies)
|
|||
|
num_supplies = i;
|
|||
|
|
|||
|
supplies[i - 1].colorant = packet->object_value.integer;
|
|||
|
}
|
|||
|
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get supply name/description...
|
|||
|
*/
|
|||
|
|
|||
|
i = packet->object_name[prtMarkerSuppliesDescriptionOffset];
|
|||
|
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
|
|||
|
packet->object_type != CUPS_ASN1_OCTET_STRING)
|
|||
|
return;
|
|||
|
|
|||
|
if (i > num_supplies)
|
|||
|
num_supplies = i;
|
|||
|
|
|||
|
switch (charset)
|
|||
|
{
|
|||
|
case CUPS_TC_csASCII :
|
|||
|
case CUPS_TC_csUTF8 :
|
|||
|
case CUPS_TC_csUnicodeASCII :
|
|||
|
strlcpy(supplies[i - 1].name,
|
|||
|
(char *)packet->object_value.string.bytes,
|
|||
|
sizeof(supplies[0].name));
|
|||
|
break;
|
|||
|
|
|||
|
case CUPS_TC_csISOLatin1 :
|
|||
|
case CUPS_TC_csUnicodeLatin1 :
|
|||
|
cupsCharsetToUTF8((cups_utf8_t *)supplies[i - 1].name,
|
|||
|
(char *)packet->object_value.string.bytes,
|
|||
|
sizeof(supplies[0].name), CUPS_ISO8859_1);
|
|||
|
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);
|
|||
|
break;
|
|||
|
|
|||
|
case CUPS_TC_csUCS4 :
|
|||
|
case CUPS_TC_csUTF32 :
|
|||
|
case CUPS_TC_csUTF32BE :
|
|||
|
case CUPS_TC_csUTF32LE :
|
|||
|
cupsUTF32ToUTF8((cups_utf8_t *)supplies[i - 1].name,
|
|||
|
(cups_utf32_t *)packet->object_value.string.bytes,
|
|||
|
sizeof(supplies[0].name));
|
|||
|
break;
|
|||
|
|
|||
|
case CUPS_TC_csUnicode :
|
|||
|
case CUPS_TC_csUTF16BE :
|
|||
|
case CUPS_TC_csUTF16LE :
|
|||
|
utf16_to_utf8((cups_utf8_t *)supplies[i - 1].name,
|
|||
|
packet->object_value.string.bytes,
|
|||
|
packet->object_value.string.num_bytes,
|
|||
|
sizeof(supplies[0].name), charset == CUPS_TC_csUTF16LE);
|
|||
|
break;
|
|||
|
|
|||
|
default :
|
|||
|
/*
|
|||
|
* If we get here, the printer is using an unknown character set and
|
|||
|
* we just want to copy characters that look like ASCII...
|
|||
|
*/
|
|||
|
|
|||
|
{
|
|||
|
char *src, *dst; /* Pointers into strings */
|
|||
|
|
|||
|
/*
|
|||
|
* Loop safe because both the object_value and supplies char arrays
|
|||
|
* are CUPS_SNMP_MAX_STRING elements long.
|
|||
|
*/
|
|||
|
|
|||
|
for (src = (char *)packet->object_value.string.bytes,
|
|||
|
dst = supplies[i - 1].name;
|
|||
|
*src;
|
|||
|
src ++)
|
|||
|
{
|
|||
|
if ((*src & 0x80) || *src < ' ' || *src == 0x7f)
|
|||
|
*dst++ = '?';
|
|||
|
else
|
|||
|
*dst++ = *src;
|
|||
|
}
|
|||
|
|
|||
|
*dst = '\0';
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG2: prtMarkerSuppliesDescription.1.%d = \"%s\"\n", i,
|
|||
|
supplies[i - 1].name);
|
|||
|
|
|||
|
}
|
|||
|
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesLevel))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get level...
|
|||
|
*/
|
|||
|
|
|||
|
i = packet->object_name[prtMarkerSuppliesLevelOffset];
|
|||
|
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
|
|||
|
packet->object_type != CUPS_ASN1_INTEGER)
|
|||
|
return;
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG2: prtMarkerSuppliesLevel.1.%d = %d\n", i,
|
|||
|
packet->object_value.integer);
|
|||
|
|
|||
|
if (i > num_supplies)
|
|||
|
num_supplies = i;
|
|||
|
|
|||
|
supplies[i - 1].level = packet->object_value.integer;
|
|||
|
}
|
|||
|
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity) &&
|
|||
|
!(quirks & CUPS_SNMP_CAPACITY))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get max capacity...
|
|||
|
*/
|
|||
|
|
|||
|
i = packet->object_name[prtMarkerSuppliesMaxCapacityOffset];
|
|||
|
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
|
|||
|
packet->object_type != CUPS_ASN1_INTEGER)
|
|||
|
return;
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG2: prtMarkerSuppliesMaxCapacity.1.%d = %d\n", i,
|
|||
|
packet->object_value.integer);
|
|||
|
|
|||
|
if (i > num_supplies)
|
|||
|
num_supplies = i;
|
|||
|
|
|||
|
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))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get marker type...
|
|||
|
*/
|
|||
|
|
|||
|
i = packet->object_name[prtMarkerSuppliesTypeOffset];
|
|||
|
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
|
|||
|
packet->object_type != CUPS_ASN1_INTEGER)
|
|||
|
return;
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG2: prtMarkerSuppliesType.1.%d = %d\n", i,
|
|||
|
packet->object_value.integer);
|
|||
|
|
|||
|
if (i > num_supplies)
|
|||
|
num_supplies = i;
|
|||
|
|
|||
|
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;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'utf16_to_utf8()' - Convert UTF-16 text to UTF-8.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
utf16_to_utf8(
|
|||
|
cups_utf8_t *dst, /* I - Destination buffer */
|
|||
|
const unsigned char *src, /* I - Source string */
|
|||
|
size_t srcsize, /* I - Size of source string */
|
|||
|
size_t dstsize, /* I - Size of destination buffer */
|
|||
|
int le) /* I - Source is little-endian? */
|
|||
|
{
|
|||
|
cups_utf32_t ch, /* Current character */
|
|||
|
temp[CUPS_SNMP_MAX_STRING],
|
|||
|
/* UTF-32 string */
|
|||
|
*ptr; /* Pointer into UTF-32 string */
|
|||
|
|
|||
|
|
|||
|
for (ptr = temp; srcsize >= 2;)
|
|||
|
{
|
|||
|
if (le)
|
|||
|
ch = (cups_utf32_t)(src[0] | (src[1] << 8));
|
|||
|
else
|
|||
|
ch = (cups_utf32_t)((src[0] << 8) | src[1]);
|
|||
|
|
|||
|
src += 2;
|
|||
|
srcsize -= 2;
|
|||
|
|
|||
|
if (ch >= 0xd800 && ch <= 0xdbff && srcsize >= 2)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Multi-word UTF-16 char...
|
|||
|
*/
|
|||
|
|
|||
|
cups_utf32_t lch; /* Lower word */
|
|||
|
|
|||
|
|
|||
|
if (le)
|
|||
|
lch = (cups_utf32_t)(src[0] | (src[1] << 8));
|
|||
|
else
|
|||
|
lch = (cups_utf32_t)((src[0] << 8) | src[1]);
|
|||
|
|
|||
|
if (lch >= 0xdc00 && lch <= 0xdfff)
|
|||
|
{
|
|||
|
src += 2;
|
|||
|
srcsize -= 2;
|
|||
|
|
|||
|
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ptr < (temp + CUPS_SNMP_MAX_STRING - 1))
|
|||
|
*ptr++ = ch;
|
|||
|
}
|
|||
|
|
|||
|
*ptr = '\0';
|
|||
|
|
|||
|
cupsUTF32ToUTF8(dst, temp, (int)dstsize);
|
|||
|
}
|