4 * SNMP supplies functions for CUPS.
6 * Copyright 2008-2011 by Apple Inc.
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged, see the license at "http://www.cups.org/".
14 * This file is subject to the Apple OS-Developed Software exception.
18 * backendSNMPSupplies() - Get the current supplies for a device.
19 * backend_init_supplies() - Initialize the supplies list.
20 * backend_walk_cb() - Interpret the supply value responses.
21 * utf16_to_utf8() - Convert UTF-16 text to UTF-8.
25 * Include necessary headers.
28 #include "backend-private.h"
29 #include <cups/array.h>
36 #define CUPS_MAX_SUPPLIES 32 /* Maximum number of supplies for a printer */
37 #define CUPS_SUPPLY_TIMEOUT 2.0 /* Timeout for SNMP lookups */
39 #define CUPS_DEVELOPER_LOW 1
40 #define CUPS_DEVELOPER_EMPTY 2
41 #define CUPS_MARKER_SUPPLY_LOW 4
42 #define CUPS_MARKER_SUPPLY_EMPTY 8
43 #define CUPS_MARKER_WASTE_ALMOST_FULL 16
44 #define CUPS_MARKER_WASTE_FULL 32
45 #define CUPS_OPC_NEAR_EOL 64
46 #define CUPS_OPC_LIFE_OVER 128
47 #define CUPS_TONER_LOW 256
48 #define CUPS_TONER_EMPTY 512
55 typedef struct /**** Printer supply data ****/
57 char name
[CUPS_SNMP_MAX_STRING
], /* Name of supply */
58 color
[8]; /* Color: "#RRGGBB" or "none" */
59 int colorant
, /* Colorant index */
60 type
, /* Supply type */
61 max_capacity
, /* Maximum capacity */
62 level
; /* Current level value */
65 typedef struct /**** Printer state table ****/
67 int bit
; /* State bit */
68 const char *keyword
; /* IPP printer-state-reasons keyword */
76 static http_addr_t current_addr
; /* Current address */
77 static int current_state
= -1;
78 /* Current device state bits */
79 static int charset
= -1; /* Character set for supply names */
80 static int num_supplies
= 0;
81 /* Number of supplies found */
82 static backend_supplies_t supplies
[CUPS_MAX_SUPPLIES
];
83 /* Supply information */
84 static int supply_state
= -1;
85 /* Supply state info */
87 static const int hrDeviceDescr
[] =
88 { CUPS_OID_hrDeviceDescr
, 1, -1 };
89 /* Device description OID */
90 static const int hrPrinterStatus
[] =
91 { CUPS_OID_hrPrinterStatus
, 1, -1 };
92 /* Current state OID */
93 static const int hrPrinterDetectedErrorState
[] =
94 { CUPS_OID_hrPrinterDetectedErrorState
, 1, -1 };
95 /* Current printer state bits OID */
96 static const int prtGeneralCurrentLocalization
[] =
97 { CUPS_OID_prtGeneralCurrentLocalization
, 1, -1 };
98 static const int prtLocalizationCharacterSet
[] =
99 { CUPS_OID_prtLocalizationCharacterSet
, 1, 1, -1 },
100 prtLocalizationCharacterSetOffset
=
101 (sizeof(prtLocalizationCharacterSet
) /
102 sizeof(prtLocalizationCharacterSet
[0]));
103 static const int prtMarkerColorantValue
[] =
104 { CUPS_OID_prtMarkerColorantValue
, -1 },
106 prtMarkerColorantValueOffset
=
107 (sizeof(prtMarkerColorantValue
) /
108 sizeof(prtMarkerColorantValue
[0]));
109 /* Offset to colorant index */
110 static const int prtMarkerLifeCount
[] =
111 { CUPS_OID_prtMarkerLifeCount
, 1, 1, -1 };
112 /* Page counter OID */
113 static const int prtMarkerSuppliesEntry
[] =
114 { CUPS_OID_prtMarkerSuppliesEntry
, -1 };
116 static const int prtMarkerSuppliesColorantIndex
[] =
117 { CUPS_OID_prtMarkerSuppliesColorantIndex
, -1 },
118 /* Colorant index OID */
119 prtMarkerSuppliesColorantIndexOffset
=
120 (sizeof(prtMarkerSuppliesColorantIndex
) /
121 sizeof(prtMarkerSuppliesColorantIndex
[0]));
122 /* Offset to supply index */
123 static const int prtMarkerSuppliesDescription
[] =
124 { CUPS_OID_prtMarkerSuppliesDescription
, -1 },
125 /* Description OID */
126 prtMarkerSuppliesDescriptionOffset
=
127 (sizeof(prtMarkerSuppliesDescription
) /
128 sizeof(prtMarkerSuppliesDescription
[0]));
129 /* Offset to supply index */
130 static const int prtMarkerSuppliesLevel
[] =
131 { CUPS_OID_prtMarkerSuppliesLevel
, -1 },
133 prtMarkerSuppliesLevelOffset
=
134 (sizeof(prtMarkerSuppliesLevel
) /
135 sizeof(prtMarkerSuppliesLevel
[0]));
136 /* Offset to supply index */
137 static const int prtMarkerSuppliesMaxCapacity
[] =
138 { CUPS_OID_prtMarkerSuppliesMaxCapacity
, -1 },
139 /* Max capacity OID */
140 prtMarkerSuppliesMaxCapacityOffset
=
141 (sizeof(prtMarkerSuppliesMaxCapacity
) /
142 sizeof(prtMarkerSuppliesMaxCapacity
[0]));
143 /* Offset to supply index */
144 static const int prtMarkerSuppliesType
[] =
145 { CUPS_OID_prtMarkerSuppliesType
, -1 },
147 prtMarkerSuppliesTypeOffset
=
148 (sizeof(prtMarkerSuppliesType
) /
149 sizeof(prtMarkerSuppliesType
[0]));
150 /* Offset to supply index */
152 static const backend_state_t
const printer_states
[] =
154 { CUPS_TC_lowPaper
, "media-low-report" },
155 { CUPS_TC_noPaper
| CUPS_TC_inputTrayEmpty
, "media-empty-warning" },
156 /* { CUPS_TC_lowToner, "toner-low-report" }, */ /* now use prtMarkerSupplies */
157 /* { CUPS_TC_noToner, "toner-empty-warning" }, */ /* now use prtMarkerSupplies */
158 { CUPS_TC_doorOpen
, "door-open-report" },
159 { CUPS_TC_jammed
, "media-jam-warning" },
160 /* { CUPS_TC_offline, "offline-report" }, */ /* unreliable */
161 /* { CUPS_TC_serviceRequested | CUPS_TC_overduePreventMaint, "service-needed-warning" }, */ /* unreliable */
162 { CUPS_TC_inputTrayMissing
, "input-tray-missing-warning" },
163 { CUPS_TC_outputTrayMissing
, "output-tray-missing-warning" },
164 { CUPS_TC_markerSupplyMissing
, "marker-supply-missing-warning" },
165 { CUPS_TC_outputNearFull
, "output-area-almost-full-report" },
166 { CUPS_TC_outputFull
, "output-area-full-warning" }
169 static const backend_state_t
const supply_states
[] =
171 { CUPS_DEVELOPER_LOW
, "developer-low-report" },
172 { CUPS_DEVELOPER_EMPTY
, "developer-empty-warning" },
173 { CUPS_MARKER_SUPPLY_LOW
, "marker-supply-low-report" },
174 { CUPS_MARKER_SUPPLY_EMPTY
, "marker-supply-empty-warning" },
175 { CUPS_MARKER_WASTE_ALMOST_FULL
, "marker-waste-almost-full-report" },
176 { CUPS_MARKER_WASTE_FULL
, "marker-waste-full-warning" },
177 { CUPS_OPC_NEAR_EOL
, "opc-near-eol-report" },
178 { CUPS_OPC_LIFE_OVER
, "opc-life-over-warning" },
179 { CUPS_TONER_LOW
, "toner-low-report" },
180 { CUPS_TONER_EMPTY
, "toner-empty-warning" }
188 static void backend_init_supplies(int snmp_fd
, http_addr_t
*addr
);
189 static void backend_walk_cb(cups_snmp_t
*packet
, void *data
);
190 static void utf16_to_utf8(cups_utf8_t
*dst
, const unsigned char *src
,
191 size_t srcsize
, size_t dstsize
, int le
);
195 * 'backendSNMPSupplies()' - Get the current supplies for a device.
198 int /* O - 0 on success, -1 on error */
200 int snmp_fd
, /* I - SNMP socket */
201 http_addr_t
*addr
, /* I - Printer address */
202 int *page_count
, /* O - Page count */
203 int *printer_state
) /* O - Printer state */
205 if (!httpAddrEqual(addr
, ¤t_addr
))
206 backend_init_supplies(snmp_fd
, addr
);
207 else if (num_supplies
> 0)
208 _cupsSNMPWalk(snmp_fd
, ¤t_addr
, CUPS_SNMP_VERSION_1
,
209 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel
,
210 CUPS_SUPPLY_TIMEOUT
, backend_walk_cb
, NULL
);
218 if (num_supplies
> 0)
220 int i
, /* Looping var */
221 percent
, /* Percent full */
222 new_state
, /* New state value */
223 change_state
, /* State change */
224 new_supply_state
= 0; /* Supply state */
225 char value
[CUPS_MAX_SUPPLIES
* 4],
226 /* marker-levels value string */
227 *ptr
; /* Pointer into value string */
228 cups_snmp_t packet
; /* SNMP response packet */
231 * Generate the marker-levels value string...
234 for (i
= 0, ptr
= value
; i
< num_supplies
; i
++, ptr
+= strlen(ptr
))
236 if (supplies
[i
].max_capacity
> 0)
237 percent
= 100 * supplies
[i
].level
/ supplies
[i
].max_capacity
;
243 switch (supplies
[i
].type
)
246 case CUPS_TC_tonerCartridge
:
248 new_supply_state
|= CUPS_TONER_EMPTY
;
250 new_supply_state
|= CUPS_TONER_LOW
;
252 case CUPS_TC_wasteToner
:
253 case CUPS_TC_wasteInk
:
255 new_supply_state
|= CUPS_MARKER_WASTE_FULL
;
257 new_supply_state
|= CUPS_MARKER_WASTE_ALMOST_FULL
;
260 case CUPS_TC_inkCartridge
:
261 case CUPS_TC_inkRibbon
:
262 case CUPS_TC_solidWax
:
263 case CUPS_TC_ribbonWax
:
265 new_supply_state
|= CUPS_MARKER_SUPPLY_EMPTY
;
267 new_supply_state
|= CUPS_MARKER_SUPPLY_LOW
;
269 case CUPS_TC_developer
:
271 new_supply_state
|= CUPS_DEVELOPER_EMPTY
;
273 new_supply_state
|= CUPS_DEVELOPER_LOW
;
275 case CUPS_TC_coronaWire
:
278 case CUPS_TC_transferUnit
:
280 new_supply_state
|= CUPS_OPC_LIFE_OVER
;
282 new_supply_state
|= CUPS_OPC_NEAR_EOL
;
290 if (supplies
[i
].max_capacity
> 0)
291 sprintf(ptr
, "%d", percent
);
296 fprintf(stderr
, "ATTR: marker-levels=%s\n", value
);
298 if (supply_state
< 0)
299 change_state
= 0xffff;
301 change_state
= supply_state
^ new_supply_state
;
303 fprintf(stderr
, "DEBUG: new_supply_state=%x, change_state=%x\n",
304 new_supply_state
, change_state
);
307 i
< (int)(sizeof(supply_states
) / sizeof(supply_states
[0]));
309 if (change_state
& supply_states
[i
].bit
)
311 fprintf(stderr
, "STATE: %c%s\n",
312 (new_supply_state
& supply_states
[i
].bit
) ? '+' : '-',
313 supply_states
[i
].keyword
);
316 supply_state
= new_supply_state
;
319 * Get the current printer status bits...
322 if (!_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
323 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
324 hrPrinterDetectedErrorState
))
327 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
328 packet
.object_type
!= CUPS_ASN1_OCTET_STRING
)
331 if (packet
.object_value
.string
.num_bytes
== 2)
332 new_state
= (packet
.object_value
.string
.bytes
[0] << 8) |
333 packet
.object_value
.string
.bytes
[1];
334 else if (packet
.object_value
.string
.num_bytes
== 1)
335 new_state
= (packet
.object_value
.string
.bytes
[0] << 8);
339 if (current_state
< 0)
340 change_state
= 0xffff;
342 change_state
= current_state
^ new_state
;
344 fprintf(stderr
, "DEBUG: new_state=%x, change_state=%x\n", new_state
,
348 i
< (int)(sizeof(printer_states
) / sizeof(printer_states
[0]));
350 if (change_state
& printer_states
[i
].bit
)
352 fprintf(stderr
, "STATE: %c%s\n",
353 (new_state
& printer_states
[i
].bit
) ? '+' : '-',
354 printer_states
[i
].keyword
);
357 current_state
= new_state
;
360 * Get the current printer state...
365 if (!_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
366 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
370 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
371 packet
.object_type
!= CUPS_ASN1_INTEGER
)
374 *printer_state
= packet
.object_value
.integer
;
378 * Get the current page count...
383 if (!_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
384 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
388 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
389 packet
.object_type
!= CUPS_ASN1_COUNTER
)
392 *page_count
= packet
.object_value
.counter
;
403 * 'backend_init_supplies()' - Initialize the supplies list.
407 backend_init_supplies(
408 int snmp_fd
, /* I - SNMP socket */
409 http_addr_t
*addr
) /* I - Printer address */
411 int i
, /* Looping var */
412 type
; /* Current marker type */
413 cups_file_t
*cachefile
; /* Cache file */
414 const char *cachedir
; /* CUPS_CACHEDIR value */
415 char addrstr
[1024], /* Address string */
416 cachefilename
[1024], /* Cache filename */
417 description
[CUPS_SNMP_MAX_STRING
],
418 /* Device description string */
419 value
[CUPS_MAX_SUPPLIES
* (CUPS_SNMP_MAX_STRING
* 2 + 3)],
421 *ptr
, /* Pointer into value string */
422 *name_ptr
; /* Pointer into name string */
423 cups_snmp_t packet
; /* SNMP response packet */
424 ppd_file_t
*ppd
; /* PPD file for this queue */
425 ppd_attr_t
*ppdattr
; /* cupsSNMPSupplies attribute */
426 static const char * const types
[] = /* Supply types */
466 * Reset state information...
469 current_addr
= *addr
;
474 memset(supplies
, 0, sizeof(supplies
));
477 * See if we should be getting supply levels via SNMP...
480 if ((ppd
= ppdOpenFile(getenv("PPD"))) == NULL
||
481 ((ppdattr
= ppdFindAttr(ppd
, "cupsSNMPSupplies", NULL
)) != NULL
&&
482 ppdattr
->value
&& strcasecmp(ppdattr
->value
, "true")))
491 * Get the device description...
494 if (!_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
495 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
499 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
500 packet
.object_type
!= CUPS_ASN1_OCTET_STRING
)
502 strlcpy(description
, "Unknown", sizeof(description
));
506 strlcpy(description
, (char *)packet
.object_value
.string
.bytes
,
507 sizeof(description
));
509 fprintf(stderr
, "DEBUG2: hrDeviceDesc=\"%s\"\n", description
);
512 * See if we have already queried this device...
515 httpAddrString(addr
, addrstr
, sizeof(addrstr
));
517 if ((cachedir
= getenv("CUPS_CACHEDIR")) == NULL
)
518 cachedir
= CUPS_CACHEDIR
;
520 snprintf(cachefilename
, sizeof(cachefilename
), "%s/%s.snmp", cachedir
,
523 if ((cachefile
= cupsFileOpen(cachefilename
, "r")) != NULL
)
526 * Yes, read the cache file:
528 * 2 num_supplies charset
530 * supply structures...
533 if (cupsFileGets(cachefile
, value
, sizeof(value
)))
535 if (sscanf(value
, "2 %d%d", &num_supplies
, &charset
) == 2 &&
536 num_supplies
<= CUPS_MAX_SUPPLIES
&&
537 cupsFileGets(cachefile
, value
, sizeof(value
)))
539 if (!strcmp(description
, value
))
540 cupsFileRead(cachefile
, (char *)supplies
,
541 num_supplies
* sizeof(backend_supplies_t
));
555 cupsFileClose(cachefile
);
559 * If the cache information isn't correct, scan for supplies...
565 * Get the configured character set...
568 int oid
[CUPS_SNMP_MAX_OID
]; /* OID for character set */
571 if (!_cupsSNMPWrite(snmp_fd
, ¤t_addr
, CUPS_SNMP_VERSION_1
,
572 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
573 prtGeneralCurrentLocalization
))
576 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
577 packet
.object_type
!= CUPS_ASN1_INTEGER
)
580 "DEBUG: prtGeneralCurrentLocalization type is %x, expected %x!\n",
581 packet
.object_type
, CUPS_ASN1_INTEGER
);
585 fprintf(stderr
, "DEBUG2: prtGeneralCurrentLocalization=%d\n",
586 packet
.object_value
.integer
);
588 _cupsSNMPCopyOID(oid
, prtLocalizationCharacterSet
, CUPS_SNMP_MAX_OID
);
589 oid
[prtLocalizationCharacterSetOffset
- 2] = packet
.object_value
.integer
;
592 if (!_cupsSNMPWrite(snmp_fd
, ¤t_addr
, CUPS_SNMP_VERSION_1
,
593 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
597 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
598 packet
.object_type
!= CUPS_ASN1_INTEGER
)
601 "DEBUG: prtLocalizationCharacterSet type is %x, expected %x!\n",
602 packet
.object_type
, CUPS_ASN1_INTEGER
);
606 fprintf(stderr
, "DEBUG2: prtLocalizationCharacterSet=%d\n",
607 packet
.object_value
.integer
);
608 charset
= packet
.object_value
.integer
;
611 if (num_supplies
< 0)
614 * Walk the printer configuration information...
617 _cupsSNMPWalk(snmp_fd
, ¤t_addr
, CUPS_SNMP_VERSION_1
,
618 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry
,
619 CUPS_SUPPLY_TIMEOUT
, backend_walk_cb
, NULL
);
623 * Save the cached information...
626 if (num_supplies
< 0)
629 if ((cachefile
= cupsFileOpen(cachefilename
, "w")) != NULL
)
631 cupsFilePrintf(cachefile
, "2 %d %d\n", num_supplies
, charset
);
632 cupsFilePrintf(cachefile
, "%s\n", description
);
634 if (num_supplies
> 0)
635 cupsFileWrite(cachefile
, (char *)supplies
,
636 num_supplies
* sizeof(backend_supplies_t
));
638 cupsFileClose(cachefile
);
641 if (num_supplies
<= 0)
648 for (i
= 0; i
< num_supplies
; i
++)
649 strcpy(supplies
[i
].color
, "none");
651 _cupsSNMPWalk(snmp_fd
, ¤t_addr
, CUPS_SNMP_VERSION_1
,
652 _cupsSNMPDefaultCommunity(), prtMarkerColorantValue
,
653 CUPS_SUPPLY_TIMEOUT
, backend_walk_cb
, NULL
);
656 * Output the marker-colors attribute...
659 for (i
= 0, ptr
= value
; i
< num_supplies
; i
++, ptr
+= strlen(ptr
))
664 strcpy(ptr
, supplies
[i
].color
);
667 fprintf(stderr
, "ATTR: marker-colors=%s\n", value
);
670 * Output the marker-names attribute...
673 for (i
= 0, ptr
= value
; i
< num_supplies
; i
++)
679 for (name_ptr
= supplies
[i
].name
; *name_ptr
;)
681 if (*name_ptr
== '\\' || *name_ptr
== '\"')
684 *ptr
++ = *name_ptr
++;
691 fprintf(stderr
, "ATTR: marker-names=%s\n", value
);
694 * Output the marker-types attribute...
697 for (i
= 0, ptr
= value
; i
< num_supplies
; i
++, ptr
+= strlen(ptr
))
702 type
= supplies
[i
].type
;
704 if (type
< CUPS_TC_other
|| type
> CUPS_TC_covers
)
705 strcpy(ptr
, "unknown");
707 strcpy(ptr
, types
[type
- CUPS_TC_other
]);
710 fprintf(stderr
, "ATTR: marker-types=%s\n", value
);
715 * 'backend_walk_cb()' - Interpret the supply value responses.
719 backend_walk_cb(cups_snmp_t
*packet
, /* I - SNMP packet */
720 void *data
) /* I - User data (unused) */
722 int i
, j
, k
; /* Looping vars */
723 static const char * const colors
[8][2] =
724 { /* Standard color names */
725 { "black", "#000000" },
726 { "blue", "#0000FF" },
727 { "cyan", "#00FFFF" },
728 { "green", "#00FF00" },
729 { "magenta", "#FF00FF" },
730 { "red", "#FF0000" },
731 { "white", "#FFFFFF" },
732 { "yellow", "#FFFF00" }
738 if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerColorantValue
) &&
739 packet
->object_type
== CUPS_ASN1_OCTET_STRING
)
745 i
= packet
->object_name
[prtMarkerColorantValueOffset
];
747 fprintf(stderr
, "DEBUG2: prtMarkerColorantValue.1.%d = \"%s\"\n", i
,
748 (char *)packet
->object_value
.string
.bytes
);
750 for (j
= 0; j
< num_supplies
; j
++)
751 if (supplies
[j
].colorant
== i
)
753 for (k
= 0; k
< (int)(sizeof(colors
) / sizeof(colors
[0])); k
++)
754 if (!strcmp(colors
[k
][0], (char *)packet
->object_value
.string
.bytes
))
756 strcpy(supplies
[j
].color
, colors
[k
][1]);
761 else if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerSuppliesColorantIndex
))
764 * Get colorant index...
767 i
= packet
->object_name
[prtMarkerSuppliesColorantIndexOffset
];
768 if (i
< 1 || i
> CUPS_MAX_SUPPLIES
||
769 packet
->object_type
!= CUPS_ASN1_INTEGER
)
772 fprintf(stderr
, "DEBUG2: prtMarkerSuppliesColorantIndex.1.%d = %d\n", i
,
773 packet
->object_value
.integer
);
775 if (i
> num_supplies
)
778 supplies
[i
- 1].colorant
= packet
->object_value
.integer
;
780 else if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerSuppliesDescription
))
783 * Get supply name/description...
786 i
= packet
->object_name
[prtMarkerSuppliesDescriptionOffset
];
787 if (i
< 1 || i
> CUPS_MAX_SUPPLIES
||
788 packet
->object_type
!= CUPS_ASN1_OCTET_STRING
)
791 if (i
> num_supplies
)
796 case CUPS_TC_csASCII
:
797 case CUPS_TC_csUTF8
:
798 case CUPS_TC_csUnicodeASCII
:
799 strlcpy(supplies
[i
- 1].name
,
800 (char *)packet
->object_value
.string
.bytes
,
801 sizeof(supplies
[0].name
));
804 case CUPS_TC_csISOLatin1
:
805 case CUPS_TC_csUnicodeLatin1
:
806 cupsCharsetToUTF8((cups_utf8_t
*)supplies
[i
- 1].name
,
807 (char *)packet
->object_value
.string
.bytes
,
808 sizeof(supplies
[0].name
), CUPS_ISO8859_1
);
811 case CUPS_TC_csShiftJIS
:
812 cupsCharsetToUTF8((cups_utf8_t
*)supplies
[i
- 1].name
,
813 (char *)packet
->object_value
.string
.bytes
,
814 sizeof(supplies
[0].name
), CUPS_JIS_X0213
);
817 case CUPS_TC_csUCS4
:
818 case CUPS_TC_csUTF32
:
819 case CUPS_TC_csUTF32BE
:
820 case CUPS_TC_csUTF32LE
:
821 cupsUTF32ToUTF8((cups_utf8_t
*)supplies
[i
- 1].name
,
822 (cups_utf32_t
*)packet
->object_value
.string
.bytes
,
823 sizeof(supplies
[0].name
));
826 case CUPS_TC_csUnicode
:
827 case CUPS_TC_csUTF16BE
:
828 case CUPS_TC_csUTF16LE
:
829 utf16_to_utf8((cups_utf8_t
*)supplies
[i
- 1].name
,
830 packet
->object_value
.string
.bytes
,
831 packet
->object_value
.string
.num_bytes
,
832 sizeof(supplies
[0].name
), charset
== CUPS_TC_csUTF16LE
);
837 * If we get here, the printer is using an unknown character set and
838 * we just want to copy characters that look like ASCII...
842 char *src
, *dst
; /* Pointers into strings */
846 * Loop safe because both the object_value and supplies char arrays
847 * are CUPS_SNMP_MAX_STRING elements long.
850 for (src
= (char *)packet
->object_value
.string
.bytes
,
851 dst
= supplies
[i
- 1].name
;
855 if ((*src
& 0x80) || *src
< ' ' || *src
== 0x7f)
866 fprintf(stderr
, "DEBUG2: prtMarkerSuppliesDescription.1.%d = \"%s\"\n", i
,
867 supplies
[i
- 1].name
);
870 else if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerSuppliesLevel
))
876 i
= packet
->object_name
[prtMarkerSuppliesLevelOffset
];
877 if (i
< 1 || i
> CUPS_MAX_SUPPLIES
||
878 packet
->object_type
!= CUPS_ASN1_INTEGER
)
881 fprintf(stderr
, "DEBUG2: prtMarkerSuppliesLevel.1.%d = %d\n", i
,
882 packet
->object_value
.integer
);
884 if (i
> num_supplies
)
887 supplies
[i
- 1].level
= packet
->object_value
.integer
;
889 else if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerSuppliesMaxCapacity
))
892 * Get max capacity...
895 i
= packet
->object_name
[prtMarkerSuppliesMaxCapacityOffset
];
896 if (i
< 1 || i
> CUPS_MAX_SUPPLIES
||
897 packet
->object_type
!= CUPS_ASN1_INTEGER
)
900 fprintf(stderr
, "DEBUG2: prtMarkerSuppliesMaxCapacity.1.%d = %d\n", i
,
901 packet
->object_value
.integer
);
903 if (i
> num_supplies
)
906 supplies
[i
- 1].max_capacity
= packet
->object_value
.integer
;
908 else if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerSuppliesType
))
914 i
= packet
->object_name
[prtMarkerSuppliesTypeOffset
];
915 if (i
< 1 || i
> CUPS_MAX_SUPPLIES
||
916 packet
->object_type
!= CUPS_ASN1_INTEGER
)
919 fprintf(stderr
, "DEBUG2: prtMarkerSuppliesType.1.%d = %d\n", i
,
920 packet
->object_value
.integer
);
922 if (i
> num_supplies
)
925 supplies
[i
- 1].type
= packet
->object_value
.integer
;
931 * 'utf16_to_utf8()' - Convert UTF-16 text to UTF-8.
936 cups_utf8_t
*dst
, /* I - Destination buffer */
937 const unsigned char *src
, /* I - Source string */
938 size_t srcsize
, /* I - Size of source string */
939 size_t dstsize
, /* I - Size of destination buffer */
940 int le
) /* I - Source is little-endian? */
942 cups_utf32_t ch
, /* Current character */
943 temp
[CUPS_SNMP_MAX_STRING
],
945 *ptr
; /* Pointer into UTF-32 string */
948 for (ptr
= temp
; srcsize
>= 2;)
951 ch
= src
[0] | (src
[1] << 8);
953 ch
= (src
[0] << 8) | src
[1];
958 if (ch
>= 0xd800 && ch
<= 0xdbff && srcsize
>= 2)
961 * Multi-word UTF-16 char...
964 int lch
; /* Lower word */
968 lch
= src
[0] | (src
[1] << 8);
970 lch
= (src
[0] << 8) | src
[1];
972 if (lch
>= 0xdc00 && lch
<= 0xdfff)
977 ch
= (((ch
& 0x3ff) << 10) | (lch
& 0x3ff)) + 0x10000;
981 if (ptr
< (temp
+ CUPS_SNMP_MAX_STRING
- 1))
987 cupsUTF32ToUTF8(dst
, temp
, dstsize
);