#include "backend-private.h"
#include <cups/array.h>
#define CUPS_MAX_SUPPLIES 32
#define CUPS_SUPPLY_TIMEOUT 2.0
#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
typedef struct
{
char name[CUPS_SNMP_MAX_STRING],
color[8];
int colorant,
type,
max_capacity,
level;
} backend_supplies_t;
typedef struct
{
int bit;
const char *keyword;
} backend_state_t;
static http_addr_t current_addr;
static int current_state = -1;
static int charset = -1;
static int num_supplies = 0;
static backend_supplies_t supplies[CUPS_MAX_SUPPLIES];
static int supply_state = -1;
static const int hrDeviceDescr[] =
{ CUPS_OID_hrDeviceDescr, 1, -1 };
static const int hrPrinterStatus[] =
{ CUPS_OID_hrPrinterStatus, 1, -1 };
static const int hrPrinterDetectedErrorState[] =
{ CUPS_OID_hrPrinterDetectedErrorState, 1, -1 };
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 },
prtMarkerColorantValueOffset =
(sizeof(prtMarkerColorantValue) /
sizeof(prtMarkerColorantValue[0]));
static const int prtMarkerLifeCount[] =
{ CUPS_OID_prtMarkerLifeCount, 1, 1, -1 };
static const int prtMarkerSuppliesEntry[] =
{ CUPS_OID_prtMarkerSuppliesEntry, -1 };
static const int prtMarkerSuppliesColorantIndex[] =
{ CUPS_OID_prtMarkerSuppliesColorantIndex, -1 },
prtMarkerSuppliesColorantIndexOffset =
(sizeof(prtMarkerSuppliesColorantIndex) /
sizeof(prtMarkerSuppliesColorantIndex[0]));
static const int prtMarkerSuppliesDescription[] =
{ CUPS_OID_prtMarkerSuppliesDescription, -1 },
prtMarkerSuppliesDescriptionOffset =
(sizeof(prtMarkerSuppliesDescription) /
sizeof(prtMarkerSuppliesDescription[0]));
static const int prtMarkerSuppliesLevel[] =
{ CUPS_OID_prtMarkerSuppliesLevel, -1 },
prtMarkerSuppliesLevelOffset =
(sizeof(prtMarkerSuppliesLevel) /
sizeof(prtMarkerSuppliesLevel[0]));
static const int prtMarkerSuppliesMaxCapacity[] =
{ CUPS_OID_prtMarkerSuppliesMaxCapacity, -1 },
prtMarkerSuppliesMaxCapacityOffset =
(sizeof(prtMarkerSuppliesMaxCapacity) /
sizeof(prtMarkerSuppliesMaxCapacity[0]));
static const int prtMarkerSuppliesType[] =
{ CUPS_OID_prtMarkerSuppliesType, -1 },
prtMarkerSuppliesTypeOffset =
(sizeof(prtMarkerSuppliesType) /
sizeof(prtMarkerSuppliesType[0]));
static const backend_state_t const printer_states[] =
{
{ CUPS_TC_lowPaper, "media-low-report" },
{ CUPS_TC_noPaper | CUPS_TC_inputTrayEmpty, "media-empty-warning" },
{ CUPS_TC_doorOpen, "door-open-report" },
{ CUPS_TC_jammed, "media-jam-warning" },
{ 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 const 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" }
};
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);
int
backendSNMPSupplies(
int snmp_fd,
http_addr_t *addr,
int *page_count,
int *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,
percent,
new_state,
change_state,
new_supply_state = 0;
char value[CUPS_MAX_SUPPLIES * 4],
*ptr;
cups_snmp_t packet;
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
percent = 50;
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_wasteToner :
case CUPS_TC_wasteInk :
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 (i)
*ptr++ = ',';
if (supplies[i].max_capacity > 0 && supplies[i].level >= 0)
sprintf(ptr, "%d", percent);
else
strcpy(ptr, "-1");
}
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;
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;
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;
}
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);
}
static void
backend_init_supplies(
int snmp_fd,
http_addr_t *addr)
{
int i,
type;
cups_file_t *cachefile;
const char *cachedir;
char addrstr[1024],
cachefilename[1024],
description[CUPS_SNMP_MAX_STRING],
value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 4 + 3)],
*ptr,
*name_ptr;
cups_snmp_t packet;
ppd_file_t *ppd;
ppd_attr_t *ppdattr;
static const char * const types[] =
{
"other",
"unknown",
"toner",
"wasteToner",
"ink",
"inkCartridge",
"inkRibbon",
"wasteInk",
"opc",
"developer",
"fuserOil",
"solidWax",
"ribbonWax",
"wasteWax",
"fuser",
"coronaWire",
"fuserOilWick",
"cleanerUnit",
"fuserCleaningPad",
"transferUnit",
"tonerCartridge",
"fuserOiler",
"water",
"wasteWater",
"glueWaterAdditive",
"wastePaper",
"bindingSupply",
"bandingSupply",
"stitchingWire",
"shrinkWrap",
"paperWrap",
"staples",
"inserts",
"covers"
};
current_addr = *addr;
current_state = -1;
num_supplies = -1;
charset = -1;
memset(supplies, 0, sizeof(supplies));
if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL ||
((ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL &&
ppdattr->value && _cups_strcasecmp(ppdattr->value, "true")))
{
ppdClose(ppd);
return;
}
ppdClose(ppd);
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);
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)
{
if (cupsFileGets(cachefile, value, sizeof(value)))
{
if (sscanf(value, "2 %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));
else
{
num_supplies = -1;
charset = -1;
}
}
else
{
num_supplies = -1;
charset = -1;
}
}
cupsFileClose(cachefile);
}
if (charset < 0)
{
int oid[CUPS_SNMP_MAX_OID];
if (!_cupsSNMPWrite(snmp_fd, ¤t_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, ¤t_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)
{
_cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1,
_cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry,
CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
}
if (num_supplies < 0)
num_supplies = 0;
if ((cachefile = cupsFileOpen(cachefilename, "w")) != NULL)
{
cupsFilePrintf(cachefile, "2 %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));
cupsFileClose(cachefile);
}
if (num_supplies <= 0)
return;
for (i = 0; i < num_supplies; i ++)
strcpy(supplies[i].color, "none");
_cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1,
_cupsSNMPDefaultCommunity(), prtMarkerColorantValue,
CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
{
if (i)
*ptr++ = ',';
strcpy(ptr, supplies[i].color);
}
fprintf(stderr, "ATTR: marker-colors=%s\n", value);
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);
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)
strcpy(ptr, "unknown");
else
strcpy(ptr, types[type - CUPS_TC_other]);
}
fprintf(stderr, "ATTR: marker-types=%s\n", value);
}
static void
backend_walk_cb(cups_snmp_t *packet,
void *data)
{
int i, j, k;
static const char * const colors[][2] =
{
{ "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)
{
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))
{
strcpy(supplies[j].color, colors[k][1]);
break;
}
}
}
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
{
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))
{
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 :
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 :
{
char *src, *dst;
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))
{
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))
{
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;
supplies[i - 1].max_capacity = packet->object_value.integer;
}
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
{
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;
}
}
static void
utf16_to_utf8(
cups_utf8_t *dst,
const unsigned char *src,
size_t srcsize,
size_t dstsize,
int le)
{
cups_utf32_t ch,
temp[CUPS_SNMP_MAX_STRING],
*ptr;
for (ptr = temp; srcsize >= 2;)
{
if (le)
ch = src[0] | (src[1] << 8);
else
ch = (src[0] << 8) | src[1];
src += 2;
srcsize -= 2;
if (ch >= 0xd800 && ch <= 0xdbff && srcsize >= 2)
{
int lch;
if (le)
lch = src[0] | (src[1] << 8);
else
lch = (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, dstsize);
}