4 * SNMP supplies functions for CUPS.
6 * Copyright 2008-2012 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 0x0001
40 #define CUPS_DEVELOPER_EMPTY 0x0002
41 #define CUPS_MARKER_SUPPLY_LOW 0x0004
42 #define CUPS_MARKER_SUPPLY_EMPTY 0x0008
43 #define CUPS_OPC_NEAR_EOL 0x0010
44 #define CUPS_OPC_LIFE_OVER 0x0020
45 #define CUPS_TONER_LOW 0x0040
46 #define CUPS_TONER_EMPTY 0x0080
47 #define CUPS_WASTE_ALMOST_FULL 0x0100
48 #define CUPS_WASTE_FULL 0x0200
49 #define CUPS_CLEANER_NEAR_EOL 0x0400 /* Proposed JPS3 */
50 #define CUPS_CLEANER_LIFE_OVER 0x0800 /* Proposed JPS3 */
57 typedef struct /**** Printer supply data ****/
59 char name
[CUPS_SNMP_MAX_STRING
], /* Name of supply */
60 color
[8]; /* Color: "#RRGGBB" or "none" */
61 int colorant
, /* Colorant index */
62 type
, /* Supply type */
63 max_capacity
, /* Maximum capacity */
64 level
; /* Current level value */
67 typedef struct /**** Printer state table ****/
69 int bit
; /* State bit */
70 const char *keyword
; /* IPP printer-state-reasons keyword */
78 static http_addr_t current_addr
; /* Current address */
79 static int current_state
= -1;
80 /* Current device state bits */
81 static int charset
= -1; /* Character set for supply names */
82 static int num_supplies
= 0;
83 /* Number of supplies found */
84 static backend_supplies_t supplies
[CUPS_MAX_SUPPLIES
];
85 /* Supply information */
86 static int supply_state
= -1;
87 /* Supply state info */
89 static const int hrDeviceDescr
[] =
90 { CUPS_OID_hrDeviceDescr
, 1, -1 };
91 /* Device description OID */
92 static const int hrPrinterStatus
[] =
93 { CUPS_OID_hrPrinterStatus
, 1, -1 };
94 /* Current state OID */
95 static const int hrPrinterDetectedErrorState
[] =
96 { CUPS_OID_hrPrinterDetectedErrorState
, 1, -1 };
97 /* Current printer state bits OID */
98 static const int prtGeneralCurrentLocalization
[] =
99 { CUPS_OID_prtGeneralCurrentLocalization
, 1, -1 };
100 static const int prtLocalizationCharacterSet
[] =
101 { CUPS_OID_prtLocalizationCharacterSet
, 1, 1, -1 },
102 prtLocalizationCharacterSetOffset
=
103 (sizeof(prtLocalizationCharacterSet
) /
104 sizeof(prtLocalizationCharacterSet
[0]));
105 static const int prtMarkerColorantValue
[] =
106 { CUPS_OID_prtMarkerColorantValue
, -1 },
108 prtMarkerColorantValueOffset
=
109 (sizeof(prtMarkerColorantValue
) /
110 sizeof(prtMarkerColorantValue
[0]));
111 /* Offset to colorant index */
112 static const int prtMarkerLifeCount
[] =
113 { CUPS_OID_prtMarkerLifeCount
, 1, 1, -1 };
114 /* Page counter OID */
115 static const int prtMarkerSuppliesEntry
[] =
116 { CUPS_OID_prtMarkerSuppliesEntry
, -1 };
118 static const int prtMarkerSuppliesColorantIndex
[] =
119 { CUPS_OID_prtMarkerSuppliesColorantIndex
, -1 },
120 /* Colorant index OID */
121 prtMarkerSuppliesColorantIndexOffset
=
122 (sizeof(prtMarkerSuppliesColorantIndex
) /
123 sizeof(prtMarkerSuppliesColorantIndex
[0]));
124 /* Offset to supply index */
125 static const int prtMarkerSuppliesDescription
[] =
126 { CUPS_OID_prtMarkerSuppliesDescription
, -1 },
127 /* Description OID */
128 prtMarkerSuppliesDescriptionOffset
=
129 (sizeof(prtMarkerSuppliesDescription
) /
130 sizeof(prtMarkerSuppliesDescription
[0]));
131 /* Offset to supply index */
132 static const int prtMarkerSuppliesLevel
[] =
133 { CUPS_OID_prtMarkerSuppliesLevel
, -1 },
135 prtMarkerSuppliesLevelOffset
=
136 (sizeof(prtMarkerSuppliesLevel
) /
137 sizeof(prtMarkerSuppliesLevel
[0]));
138 /* Offset to supply index */
139 static const int prtMarkerSuppliesMaxCapacity
[] =
140 { CUPS_OID_prtMarkerSuppliesMaxCapacity
, -1 },
141 /* Max capacity OID */
142 prtMarkerSuppliesMaxCapacityOffset
=
143 (sizeof(prtMarkerSuppliesMaxCapacity
) /
144 sizeof(prtMarkerSuppliesMaxCapacity
[0]));
145 /* Offset to supply index */
146 static const int prtMarkerSuppliesType
[] =
147 { CUPS_OID_prtMarkerSuppliesType
, -1 },
149 prtMarkerSuppliesTypeOffset
=
150 (sizeof(prtMarkerSuppliesType
) /
151 sizeof(prtMarkerSuppliesType
[0]));
152 /* Offset to supply index */
153 static const int prtMarkerSuppliesSupplyUnit
[] =
154 { CUPS_OID_prtMarkerSuppliesSupplyUnit
, -1 },
156 prtMarkerSuppliesSupplyUnitOffset
=
157 (sizeof(prtMarkerSuppliesSupplyUnit
) /
158 sizeof(prtMarkerSuppliesSupplyUnit
[0]));
159 /* Offset to supply index */
161 static const backend_state_t
const printer_states
[] =
163 /* { CUPS_TC_lowPaper, "media-low-report" }, */
164 { CUPS_TC_noPaper
| CUPS_TC_inputTrayEmpty
, "media-empty-warning" },
165 /* { CUPS_TC_lowToner, "toner-low-report" }, */ /* now use prtMarkerSupplies */
166 /* { CUPS_TC_noToner, "toner-empty-warning" }, */ /* now use prtMarkerSupplies */
167 { CUPS_TC_doorOpen
, "door-open-report" },
168 { CUPS_TC_jammed
, "media-jam-warning" },
169 /* { CUPS_TC_offline, "offline-report" }, */ /* unreliable */
170 /* { CUPS_TC_serviceRequested | CUPS_TC_overduePreventMaint, "service-needed-warning" }, */ /* unreliable */
171 { CUPS_TC_inputTrayMissing
, "input-tray-missing-warning" },
172 { CUPS_TC_outputTrayMissing
, "output-tray-missing-warning" },
173 { CUPS_TC_markerSupplyMissing
, "marker-supply-missing-warning" },
174 { CUPS_TC_outputNearFull
, "output-area-almost-full-report" },
175 { CUPS_TC_outputFull
, "output-area-full-warning" }
178 static const backend_state_t
const supply_states
[] =
180 { CUPS_DEVELOPER_LOW
, "developer-low-report" },
181 { CUPS_DEVELOPER_EMPTY
, "developer-empty-warning" },
182 { CUPS_MARKER_SUPPLY_LOW
, "marker-supply-low-report" },
183 { CUPS_MARKER_SUPPLY_EMPTY
, "marker-supply-empty-warning" },
184 { CUPS_OPC_NEAR_EOL
, "opc-near-eol-report" },
185 { CUPS_OPC_LIFE_OVER
, "opc-life-over-warning" },
186 { CUPS_TONER_LOW
, "toner-low-report" },
187 { CUPS_TONER_EMPTY
, "toner-empty-warning" },
188 { CUPS_WASTE_ALMOST_FULL
, "waste-receptacle-almost-full-report" },
189 { CUPS_WASTE_FULL
, "waste-receptacle-full-warning" },
190 { CUPS_CLEANER_NEAR_EOL
, "cleaner-life-almost-over-report" },
191 { CUPS_CLEANER_LIFE_OVER
, "cleaner-life-over-warning" },
199 static void backend_init_supplies(int snmp_fd
, http_addr_t
*addr
);
200 static void backend_walk_cb(cups_snmp_t
*packet
, void *data
);
201 static void utf16_to_utf8(cups_utf8_t
*dst
, const unsigned char *src
,
202 size_t srcsize
, size_t dstsize
, int le
);
206 * 'backendSNMPSupplies()' - Get the current supplies for a device.
209 int /* O - 0 on success, -1 on error */
211 int snmp_fd
, /* I - SNMP socket */
212 http_addr_t
*addr
, /* I - Printer address */
213 int *page_count
, /* O - Page count */
214 int *printer_state
) /* O - Printer state */
216 if (!httpAddrEqual(addr
, ¤t_addr
))
217 backend_init_supplies(snmp_fd
, addr
);
218 else if (num_supplies
> 0)
219 _cupsSNMPWalk(snmp_fd
, ¤t_addr
, CUPS_SNMP_VERSION_1
,
220 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel
,
221 CUPS_SUPPLY_TIMEOUT
, backend_walk_cb
, NULL
);
229 if (num_supplies
> 0)
231 int i
, /* Looping var */
232 percent
, /* Percent full */
233 new_state
, /* New state value */
234 change_state
, /* State change */
235 new_supply_state
= 0; /* Supply state */
236 char value
[CUPS_MAX_SUPPLIES
* 4],
237 /* marker-levels value string */
238 *ptr
; /* Pointer into value string */
239 cups_snmp_t packet
; /* SNMP response packet */
242 * Generate the marker-levels value string...
245 for (i
= 0, ptr
= value
; i
< num_supplies
; i
++, ptr
+= strlen(ptr
))
247 if (supplies
[i
].max_capacity
> 0 && supplies
[i
].level
>= 0)
248 percent
= 100 * supplies
[i
].level
/ supplies
[i
].max_capacity
;
254 switch (supplies
[i
].type
)
257 case CUPS_TC_tonerCartridge
:
259 new_supply_state
|= CUPS_TONER_EMPTY
;
261 new_supply_state
|= CUPS_TONER_LOW
;
264 case CUPS_TC_inkCartridge
:
265 case CUPS_TC_inkRibbon
:
266 case CUPS_TC_solidWax
:
267 case CUPS_TC_ribbonWax
:
269 new_supply_state
|= CUPS_MARKER_SUPPLY_EMPTY
;
271 new_supply_state
|= CUPS_MARKER_SUPPLY_LOW
;
273 case CUPS_TC_developer
:
275 new_supply_state
|= CUPS_DEVELOPER_EMPTY
;
277 new_supply_state
|= CUPS_DEVELOPER_LOW
;
279 case CUPS_TC_coronaWire
:
282 case CUPS_TC_transferUnit
:
284 new_supply_state
|= CUPS_OPC_LIFE_OVER
;
286 new_supply_state
|= CUPS_OPC_NEAR_EOL
;
288 case CUPS_TC_wasteInk
:
289 case CUPS_TC_wastePaper
:
290 case CUPS_TC_wasteToner
:
291 case CUPS_TC_wasteWater
:
292 case CUPS_TC_wasteWax
:
294 new_supply_state
|= CUPS_WASTE_FULL
;
296 new_supply_state
|= CUPS_WASTE_ALMOST_FULL
;
298 case CUPS_TC_cleanerUnit
:
299 case CUPS_TC_fuserCleaningPad
:
301 new_supply_state
|= CUPS_CLEANER_LIFE_OVER
;
303 new_supply_state
|= CUPS_CLEANER_NEAR_EOL
;
311 if (supplies
[i
].max_capacity
> 0 && supplies
[i
].level
>= 0)
312 sprintf(ptr
, "%d", percent
);
317 fprintf(stderr
, "ATTR: marker-levels=%s\n", value
);
319 if (supply_state
< 0)
320 change_state
= 0xffff;
322 change_state
= supply_state
^ new_supply_state
;
324 fprintf(stderr
, "DEBUG: new_supply_state=%x, change_state=%x\n",
325 new_supply_state
, change_state
);
328 i
< (int)(sizeof(supply_states
) / sizeof(supply_states
[0]));
330 if (change_state
& supply_states
[i
].bit
)
332 fprintf(stderr
, "STATE: %c%s\n",
333 (new_supply_state
& supply_states
[i
].bit
) ? '+' : '-',
334 supply_states
[i
].keyword
);
337 supply_state
= new_supply_state
;
340 * Get the current printer status bits...
343 if (!_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
344 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
345 hrPrinterDetectedErrorState
))
348 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
349 packet
.object_type
!= CUPS_ASN1_OCTET_STRING
)
352 if (packet
.object_value
.string
.num_bytes
== 2)
353 new_state
= (packet
.object_value
.string
.bytes
[0] << 8) |
354 packet
.object_value
.string
.bytes
[1];
355 else if (packet
.object_value
.string
.num_bytes
== 1)
356 new_state
= (packet
.object_value
.string
.bytes
[0] << 8);
360 if (current_state
< 0)
361 change_state
= 0xffff;
363 change_state
= current_state
^ new_state
;
365 fprintf(stderr
, "DEBUG: new_state=%x, change_state=%x\n", new_state
,
369 i
< (int)(sizeof(printer_states
) / sizeof(printer_states
[0]));
371 if (change_state
& printer_states
[i
].bit
)
373 fprintf(stderr
, "STATE: %c%s\n",
374 (new_state
& printer_states
[i
].bit
) ? '+' : '-',
375 printer_states
[i
].keyword
);
378 current_state
= new_state
;
381 * Get the current printer state...
386 if (!_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
387 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
391 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
392 packet
.object_type
!= CUPS_ASN1_INTEGER
)
395 *printer_state
= packet
.object_value
.integer
;
399 * Get the current page count...
404 if (!_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
405 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
409 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
410 packet
.object_type
!= CUPS_ASN1_COUNTER
)
413 *page_count
= packet
.object_value
.counter
;
424 * 'backend_init_supplies()' - Initialize the supplies list.
428 backend_init_supplies(
429 int snmp_fd
, /* I - SNMP socket */
430 http_addr_t
*addr
) /* I - Printer address */
432 int i
, /* Looping var */
433 type
; /* Current marker type */
434 cups_file_t
*cachefile
; /* Cache file */
435 const char *cachedir
; /* CUPS_CACHEDIR value */
436 char addrstr
[1024], /* Address string */
437 cachefilename
[1024], /* Cache filename */
438 description
[CUPS_SNMP_MAX_STRING
],
439 /* Device description string */
440 value
[CUPS_MAX_SUPPLIES
* (CUPS_SNMP_MAX_STRING
* 4 + 3)],
442 *ptr
, /* Pointer into value string */
443 *name_ptr
; /* Pointer into name string */
444 cups_snmp_t packet
; /* SNMP response packet */
445 ppd_file_t
*ppd
; /* PPD file for this queue */
446 ppd_attr_t
*ppdattr
; /* cupsSNMPSupplies attribute */
447 static const char * const types
[] = /* Supply types */
487 * Reset state information...
490 current_addr
= *addr
;
495 memset(supplies
, 0, sizeof(supplies
));
498 * See if we should be getting supply levels via SNMP...
501 if ((ppd
= ppdOpenFile(getenv("PPD"))) == NULL
||
502 ((ppdattr
= ppdFindAttr(ppd
, "cupsSNMPSupplies", NULL
)) != NULL
&&
503 ppdattr
->value
&& _cups_strcasecmp(ppdattr
->value
, "true")))
512 * Get the device description...
515 if (!_cupsSNMPWrite(snmp_fd
, addr
, CUPS_SNMP_VERSION_1
,
516 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
520 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
521 packet
.object_type
!= CUPS_ASN1_OCTET_STRING
)
523 strlcpy(description
, "Unknown", sizeof(description
));
527 strlcpy(description
, (char *)packet
.object_value
.string
.bytes
,
528 sizeof(description
));
530 fprintf(stderr
, "DEBUG2: hrDeviceDesc=\"%s\"\n", description
);
533 * See if we have already queried this device...
536 httpAddrString(addr
, addrstr
, sizeof(addrstr
));
538 if ((cachedir
= getenv("CUPS_CACHEDIR")) == NULL
)
539 cachedir
= CUPS_CACHEDIR
;
541 snprintf(cachefilename
, sizeof(cachefilename
), "%s/%s.snmp", cachedir
,
544 if ((cachefile
= cupsFileOpen(cachefilename
, "r")) != NULL
)
547 * Yes, read the cache file:
549 * 2 num_supplies charset
551 * supply structures...
554 if (cupsFileGets(cachefile
, value
, sizeof(value
)))
556 if (sscanf(value
, "2 %d%d", &num_supplies
, &charset
) == 2 &&
557 num_supplies
<= CUPS_MAX_SUPPLIES
&&
558 cupsFileGets(cachefile
, value
, sizeof(value
)))
560 if (!strcmp(description
, value
))
561 cupsFileRead(cachefile
, (char *)supplies
,
562 num_supplies
* sizeof(backend_supplies_t
));
576 cupsFileClose(cachefile
);
580 * If the cache information isn't correct, scan for supplies...
586 * Get the configured character set...
589 int oid
[CUPS_SNMP_MAX_OID
]; /* OID for character set */
592 if (!_cupsSNMPWrite(snmp_fd
, ¤t_addr
, CUPS_SNMP_VERSION_1
,
593 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
594 prtGeneralCurrentLocalization
))
597 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
598 packet
.object_type
!= CUPS_ASN1_INTEGER
)
601 "DEBUG: prtGeneralCurrentLocalization type is %x, expected %x!\n",
602 packet
.object_type
, CUPS_ASN1_INTEGER
);
606 fprintf(stderr
, "DEBUG2: prtGeneralCurrentLocalization=%d\n",
607 packet
.object_value
.integer
);
609 _cupsSNMPCopyOID(oid
, prtLocalizationCharacterSet
, CUPS_SNMP_MAX_OID
);
610 oid
[prtLocalizationCharacterSetOffset
- 2] = packet
.object_value
.integer
;
613 if (!_cupsSNMPWrite(snmp_fd
, ¤t_addr
, CUPS_SNMP_VERSION_1
,
614 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST
, 1,
618 if (!_cupsSNMPRead(snmp_fd
, &packet
, CUPS_SUPPLY_TIMEOUT
) ||
619 packet
.object_type
!= CUPS_ASN1_INTEGER
)
622 "DEBUG: prtLocalizationCharacterSet type is %x, expected %x!\n",
623 packet
.object_type
, CUPS_ASN1_INTEGER
);
627 fprintf(stderr
, "DEBUG2: prtLocalizationCharacterSet=%d\n",
628 packet
.object_value
.integer
);
629 charset
= packet
.object_value
.integer
;
632 if (num_supplies
< 0)
635 * Walk the printer configuration information...
638 _cupsSNMPWalk(snmp_fd
, ¤t_addr
, CUPS_SNMP_VERSION_1
,
639 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry
,
640 CUPS_SUPPLY_TIMEOUT
, backend_walk_cb
, NULL
);
644 * Save the cached information...
647 if (num_supplies
< 0)
650 if ((cachefile
= cupsFileOpen(cachefilename
, "w")) != NULL
)
652 cupsFilePrintf(cachefile
, "2 %d %d\n", num_supplies
, charset
);
653 cupsFilePrintf(cachefile
, "%s\n", description
);
655 if (num_supplies
> 0)
656 cupsFileWrite(cachefile
, (char *)supplies
,
657 num_supplies
* sizeof(backend_supplies_t
));
659 cupsFileClose(cachefile
);
662 if (num_supplies
<= 0)
669 for (i
= 0; i
< num_supplies
; i
++)
670 strcpy(supplies
[i
].color
, "none");
672 _cupsSNMPWalk(snmp_fd
, ¤t_addr
, CUPS_SNMP_VERSION_1
,
673 _cupsSNMPDefaultCommunity(), prtMarkerColorantValue
,
674 CUPS_SUPPLY_TIMEOUT
, backend_walk_cb
, NULL
);
677 * Output the marker-colors attribute...
680 for (i
= 0, ptr
= value
; i
< num_supplies
; i
++, ptr
+= strlen(ptr
))
685 strcpy(ptr
, supplies
[i
].color
);
688 fprintf(stderr
, "ATTR: marker-colors=%s\n", value
);
691 * Output the marker-names attribute (the double quoting is necessary to deal
692 * with embedded quotes and commas in the marker names...)
695 for (i
= 0, ptr
= value
; i
< num_supplies
; i
++)
702 for (name_ptr
= supplies
[i
].name
; *name_ptr
;)
704 if (*name_ptr
== '\\' || *name_ptr
== '\"' || *name_ptr
== '\'')
711 *ptr
++ = *name_ptr
++;
719 fprintf(stderr
, "ATTR: marker-names=%s\n", value
);
722 * Output the marker-types attribute...
725 for (i
= 0, ptr
= value
; i
< num_supplies
; i
++, ptr
+= strlen(ptr
))
730 type
= supplies
[i
].type
;
732 if (type
< CUPS_TC_other
|| type
> CUPS_TC_covers
)
733 strcpy(ptr
, "unknown");
735 strcpy(ptr
, types
[type
- CUPS_TC_other
]);
738 fprintf(stderr
, "ATTR: marker-types=%s\n", value
);
743 * 'backend_walk_cb()' - Interpret the supply value responses.
747 backend_walk_cb(cups_snmp_t
*packet
, /* I - SNMP packet */
748 void *data
) /* I - User data (unused) */
750 int i
, j
, k
; /* Looping vars */
751 static const char * const colors
[][2] =
752 { /* Standard color names */
753 { "black", "#000000" },
754 { "blue", "#0000FF" },
755 { "brown", "#A52A2A" },
756 { "cyan", "#00FFFF" },
757 { "dark-gray", "#404040" },
758 { "dark gray", "#404040" },
759 { "dark-yellow", "#FFCC00" },
760 { "dark yellow", "#FFCC00" },
761 { "gold", "#FFD700" },
762 { "gray", "#808080" },
763 { "green", "#00FF00" },
764 { "light-black", "#606060" },
765 { "light black", "#606060" },
766 { "light-cyan", "#E0FFFF" },
767 { "light cyan", "#E0FFFF" },
768 { "light-gray", "#D3D3D3" },
769 { "light gray", "#D3D3D3" },
770 { "light-magenta", "#FF77FF" },
771 { "light magenta", "#FF77FF" },
772 { "magenta", "#FF00FF" },
773 { "orange", "#FFA500" },
774 { "red", "#FF0000" },
775 { "silver", "#C0C0C0" },
776 { "white", "#FFFFFF" },
777 { "yellow", "#FFFF00" }
783 if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerColorantValue
) &&
784 packet
->object_type
== CUPS_ASN1_OCTET_STRING
)
790 i
= packet
->object_name
[prtMarkerColorantValueOffset
];
792 fprintf(stderr
, "DEBUG2: prtMarkerColorantValue.1.%d = \"%s\"\n", i
,
793 (char *)packet
->object_value
.string
.bytes
);
795 for (j
= 0; j
< num_supplies
; j
++)
796 if (supplies
[j
].colorant
== i
)
798 for (k
= 0; k
< (int)(sizeof(colors
) / sizeof(colors
[0])); k
++)
799 if (!_cups_strcasecmp(colors
[k
][0],
800 (char *)packet
->object_value
.string
.bytes
))
802 strcpy(supplies
[j
].color
, colors
[k
][1]);
807 else if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerSuppliesColorantIndex
))
810 * Get colorant index...
813 i
= packet
->object_name
[prtMarkerSuppliesColorantIndexOffset
];
814 if (i
< 1 || i
> CUPS_MAX_SUPPLIES
||
815 packet
->object_type
!= CUPS_ASN1_INTEGER
)
818 fprintf(stderr
, "DEBUG2: prtMarkerSuppliesColorantIndex.1.%d = %d\n", i
,
819 packet
->object_value
.integer
);
821 if (i
> num_supplies
)
824 supplies
[i
- 1].colorant
= packet
->object_value
.integer
;
826 else if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerSuppliesDescription
))
829 * Get supply name/description...
832 i
= packet
->object_name
[prtMarkerSuppliesDescriptionOffset
];
833 if (i
< 1 || i
> CUPS_MAX_SUPPLIES
||
834 packet
->object_type
!= CUPS_ASN1_OCTET_STRING
)
837 if (i
> num_supplies
)
842 case CUPS_TC_csASCII
:
843 case CUPS_TC_csUTF8
:
844 case CUPS_TC_csUnicodeASCII
:
845 strlcpy(supplies
[i
- 1].name
,
846 (char *)packet
->object_value
.string
.bytes
,
847 sizeof(supplies
[0].name
));
850 case CUPS_TC_csISOLatin1
:
851 case CUPS_TC_csUnicodeLatin1
:
852 cupsCharsetToUTF8((cups_utf8_t
*)supplies
[i
- 1].name
,
853 (char *)packet
->object_value
.string
.bytes
,
854 sizeof(supplies
[0].name
), CUPS_ISO8859_1
);
857 case CUPS_TC_csShiftJIS
:
858 case CUPS_TC_csWindows31J
: /* Close enough for our purposes */
859 cupsCharsetToUTF8((cups_utf8_t
*)supplies
[i
- 1].name
,
860 (char *)packet
->object_value
.string
.bytes
,
861 sizeof(supplies
[0].name
), CUPS_JIS_X0213
);
864 case CUPS_TC_csUCS4
:
865 case CUPS_TC_csUTF32
:
866 case CUPS_TC_csUTF32BE
:
867 case CUPS_TC_csUTF32LE
:
868 cupsUTF32ToUTF8((cups_utf8_t
*)supplies
[i
- 1].name
,
869 (cups_utf32_t
*)packet
->object_value
.string
.bytes
,
870 sizeof(supplies
[0].name
));
873 case CUPS_TC_csUnicode
:
874 case CUPS_TC_csUTF16BE
:
875 case CUPS_TC_csUTF16LE
:
876 utf16_to_utf8((cups_utf8_t
*)supplies
[i
- 1].name
,
877 packet
->object_value
.string
.bytes
,
878 packet
->object_value
.string
.num_bytes
,
879 sizeof(supplies
[0].name
), charset
== CUPS_TC_csUTF16LE
);
884 * If we get here, the printer is using an unknown character set and
885 * we just want to copy characters that look like ASCII...
889 char *src
, *dst
; /* Pointers into strings */
892 * Loop safe because both the object_value and supplies char arrays
893 * are CUPS_SNMP_MAX_STRING elements long.
896 for (src
= (char *)packet
->object_value
.string
.bytes
,
897 dst
= supplies
[i
- 1].name
;
901 if ((*src
& 0x80) || *src
< ' ' || *src
== 0x7f)
912 fprintf(stderr
, "DEBUG2: prtMarkerSuppliesDescription.1.%d = \"%s\"\n", i
,
913 supplies
[i
- 1].name
);
916 else if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerSuppliesLevel
))
922 i
= packet
->object_name
[prtMarkerSuppliesLevelOffset
];
923 if (i
< 1 || i
> CUPS_MAX_SUPPLIES
||
924 packet
->object_type
!= CUPS_ASN1_INTEGER
)
927 fprintf(stderr
, "DEBUG2: prtMarkerSuppliesLevel.1.%d = %d\n", i
,
928 packet
->object_value
.integer
);
930 if (i
> num_supplies
)
933 supplies
[i
- 1].level
= packet
->object_value
.integer
;
935 else if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerSuppliesMaxCapacity
))
938 * Get max capacity...
941 i
= packet
->object_name
[prtMarkerSuppliesMaxCapacityOffset
];
942 if (i
< 1 || i
> CUPS_MAX_SUPPLIES
||
943 packet
->object_type
!= CUPS_ASN1_INTEGER
)
946 fprintf(stderr
, "DEBUG2: prtMarkerSuppliesMaxCapacity.1.%d = %d\n", i
,
947 packet
->object_value
.integer
);
949 if (i
> num_supplies
)
952 if (supplies
[i
- 1].max_capacity
== 0 &&
953 packet
->object_value
.integer
> 0)
954 supplies
[i
- 1].max_capacity
= packet
->object_value
.integer
;
956 else if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerSuppliesType
))
962 i
= packet
->object_name
[prtMarkerSuppliesTypeOffset
];
963 if (i
< 1 || i
> CUPS_MAX_SUPPLIES
||
964 packet
->object_type
!= CUPS_ASN1_INTEGER
)
967 fprintf(stderr
, "DEBUG2: prtMarkerSuppliesType.1.%d = %d\n", i
,
968 packet
->object_value
.integer
);
970 if (i
> num_supplies
)
973 supplies
[i
- 1].type
= packet
->object_value
.integer
;
975 else if (_cupsSNMPIsOIDPrefixed(packet
, prtMarkerSuppliesSupplyUnit
))
978 * Get units for capacity...
981 i
= packet
->object_name
[prtMarkerSuppliesSupplyUnitOffset
];
982 if (i
< 1 || i
> CUPS_MAX_SUPPLIES
||
983 packet
->object_type
!= CUPS_ASN1_INTEGER
)
986 fprintf(stderr
, "DEBUG2: prtMarkerSuppliesSupplyUnit.1.%d = %d\n", i
,
987 packet
->object_value
.integer
);
989 if (i
> num_supplies
)
992 if (packet
->object_value
.integer
== CUPS_TC_percent
)
993 supplies
[i
- 1].max_capacity
= 100;
999 * 'utf16_to_utf8()' - Convert UTF-16 text to UTF-8.
1004 cups_utf8_t
*dst
, /* I - Destination buffer */
1005 const unsigned char *src
, /* I - Source string */
1006 size_t srcsize
, /* I - Size of source string */
1007 size_t dstsize
, /* I - Size of destination buffer */
1008 int le
) /* I - Source is little-endian? */
1010 cups_utf32_t ch
, /* Current character */
1011 temp
[CUPS_SNMP_MAX_STRING
],
1013 *ptr
; /* Pointer into UTF-32 string */
1016 for (ptr
= temp
; srcsize
>= 2;)
1019 ch
= src
[0] | (src
[1] << 8);
1021 ch
= (src
[0] << 8) | src
[1];
1026 if (ch
>= 0xd800 && ch
<= 0xdbff && srcsize
>= 2)
1029 * Multi-word UTF-16 char...
1032 int lch
; /* Lower word */
1036 lch
= src
[0] | (src
[1] << 8);
1038 lch
= (src
[0] << 8) | src
[1];
1040 if (lch
>= 0xdc00 && lch
<= 0xdfff)
1045 ch
= (((ch
& 0x3ff) << 10) | (lch
& 0x3ff)) + 0x10000;
1049 if (ptr
< (temp
+ CUPS_SNMP_MAX_STRING
- 1))
1055 cupsUTF32ToUTF8(dst
, temp
, dstsize
);