]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/snmp-supplies.c
Merge changes from CUPS 1.5svn-r9400
[thirdparty/cups.git] / backend / snmp-supplies.c
1 /*
2 * "$Id$"
3 *
4 * SNMP supplies functions for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2008-2009 by Apple Inc.
7 *
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/".
13 *
14 * This file is subject to the Apple OS-Developed Software exception.
15 *
16 * Contents:
17 *
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.
22 */
23
24 /*
25 * Include necessary headers.
26 */
27
28 #include "backend-private.h"
29 #include <cups/array.h>
30
31
32 /*
33 * Local constants...
34 */
35
36 #define CUPS_MAX_SUPPLIES 32 /* Maximum number of supplies for a printer */
37 #define CUPS_SUPPLY_TIMEOUT 2.0 /* Timeout for SNMP lookups */
38
39
40 /*
41 * Local structures...
42 */
43
44 typedef struct /**** Printer supply data ****/
45 {
46 char name[CUPS_SNMP_MAX_STRING], /* Name of supply */
47 color[8]; /* Color: "#RRGGBB" or "none" */
48 int colorant, /* Colorant index */
49 type, /* Supply type */
50 max_capacity, /* Maximum capacity */
51 level; /* Current level value */
52 } backend_supplies_t;
53
54 typedef struct /**** Printer state table ****/
55 {
56 int bit; /* State bit */
57 const char *keyword; /* IPP printer-state-reasons keyword */
58 } backend_state_t;
59
60
61 /*
62 * Local globals...
63 */
64
65 static http_addr_t current_addr; /* Current address */
66 static int current_state = -1;
67 /* Current device state bits */
68 static int charset = -1; /* Character set for supply names */
69 static int laser_printer = -1,
70 /* Laser printer with toner? */
71 num_supplies = 0;
72 /* Number of supplies found */
73 static backend_supplies_t supplies[CUPS_MAX_SUPPLIES];
74 /* Supply information */
75
76 static const int hrDeviceDescr[] =
77 { CUPS_OID_hrDeviceDescr, 1, -1 };
78 /* Device description OID */
79 static const int hrPrinterStatus[] =
80 { CUPS_OID_hrPrinterStatus, 1, -1 };
81 /* Current state OID */
82 static const int hrPrinterDetectedErrorState[] =
83 { CUPS_OID_hrPrinterDetectedErrorState, 1, -1 };
84 /* Current printer state bits OID */
85 static const int prtGeneralCurrentLocalization[] =
86 { CUPS_OID_prtGeneralCurrentLocalization, 1, -1 };
87 static const int prtLocalizationCharacterSet[] =
88 { CUPS_OID_prtLocalizationCharacterSet, 1, 1, -1 },
89 prtLocalizationCharacterSetOffset =
90 (sizeof(prtLocalizationCharacterSet) /
91 sizeof(prtLocalizationCharacterSet[0]));
92 static const int prtMarkerColorantValue[] =
93 { CUPS_OID_prtMarkerColorantValue, -1 },
94 /* Colorant OID */
95 prtMarkerColorantValueOffset =
96 (sizeof(prtMarkerColorantValue) /
97 sizeof(prtMarkerColorantValue[0]));
98 /* Offset to colorant index */
99 static const int prtMarkerLifeCount[] =
100 { CUPS_OID_prtMarkerLifeCount, 1, 1, -1 };
101 /* Page counter OID */
102 static const int prtMarkerSuppliesEntry[] =
103 { CUPS_OID_prtMarkerSuppliesEntry, -1 };
104 /* Supplies OID */
105 static const int prtMarkerSuppliesColorantIndex[] =
106 { CUPS_OID_prtMarkerSuppliesColorantIndex, -1 },
107 /* Colorant index OID */
108 prtMarkerSuppliesColorantIndexOffset =
109 (sizeof(prtMarkerSuppliesColorantIndex) /
110 sizeof(prtMarkerSuppliesColorantIndex[0]));
111 /* Offset to supply index */
112 static const int prtMarkerSuppliesDescription[] =
113 { CUPS_OID_prtMarkerSuppliesDescription, -1 },
114 /* Description OID */
115 prtMarkerSuppliesDescriptionOffset =
116 (sizeof(prtMarkerSuppliesDescription) /
117 sizeof(prtMarkerSuppliesDescription[0]));
118 /* Offset to supply index */
119 static const int prtMarkerSuppliesLevel[] =
120 { CUPS_OID_prtMarkerSuppliesLevel, -1 },
121 /* Level OID */
122 prtMarkerSuppliesLevelOffset =
123 (sizeof(prtMarkerSuppliesLevel) /
124 sizeof(prtMarkerSuppliesLevel[0]));
125 /* Offset to supply index */
126 static const int prtMarkerSuppliesMaxCapacity[] =
127 { CUPS_OID_prtMarkerSuppliesMaxCapacity, -1 },
128 /* Max capacity OID */
129 prtMarkerSuppliesMaxCapacityOffset =
130 (sizeof(prtMarkerSuppliesMaxCapacity) /
131 sizeof(prtMarkerSuppliesMaxCapacity[0]));
132 /* Offset to supply index */
133 static const int prtMarkerSuppliesType[] =
134 { CUPS_OID_prtMarkerSuppliesType, -1 },
135 /* Type OID */
136 prtMarkerSuppliesTypeOffset =
137 (sizeof(prtMarkerSuppliesType) /
138 sizeof(prtMarkerSuppliesType[0]));
139 /* Offset to supply index */
140
141 static const backend_state_t const printer_states[] =
142 {
143 { CUPS_TC_lowPaper, "media-low-report" },
144 { CUPS_TC_noPaper | CUPS_TC_inputTrayEmpty, "media-empty-warning" },
145 { CUPS_TC_lowToner, "toner-low-report" },
146 { CUPS_TC_noToner, "toner-empty-warning" },
147 { CUPS_TC_doorOpen, "door-open-report" },
148 { CUPS_TC_jammed, "media-jam-warning" },
149 /* { CUPS_TC_offline, "offline-report" }, */ /* unreliable */
150 /* { CUPS_TC_serviceRequested | CUPS_TC_overduePreventMaint, "service-needed-warning" }, */ /* unreliable */
151 { CUPS_TC_inputTrayMissing, "input-tray-missing-warning" },
152 { CUPS_TC_outputTrayMissing, "output-tray-missing-warning" },
153 { CUPS_TC_markerSupplyMissing, "marker-supply-missing-warning" },
154 { CUPS_TC_outputNearFull, "output-area-almost-full-report" },
155 { CUPS_TC_outputFull, "output-area-full-warning" }
156 };
157
158
159 /*
160 * Local functions...
161 */
162
163 static void backend_init_supplies(int snmp_fd, http_addr_t *addr);
164 static void backend_walk_cb(cups_snmp_t *packet, void *data);
165 static void utf16_to_utf8(cups_utf8_t *dst, const unsigned char *src,
166 size_t srcsize, size_t dstsize, int le);
167
168
169 /*
170 * 'backendSNMPSupplies()' - Get the current supplies for a device.
171 */
172
173 int /* O - 0 on success, -1 on error */
174 backendSNMPSupplies(
175 int snmp_fd, /* I - SNMP socket */
176 http_addr_t *addr, /* I - Printer address */
177 int *page_count, /* O - Page count */
178 int *printer_state) /* O - Printer state */
179 {
180 if (!httpAddrEqual(addr, &current_addr))
181 backend_init_supplies(snmp_fd, addr);
182 else if (num_supplies > 0)
183 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
184 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel,
185 CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
186
187 if (page_count)
188 *page_count = -1;
189
190 if (printer_state)
191 *printer_state = -1;
192
193 if (num_supplies > 0)
194 {
195 int i, /* Looping var */
196 new_state, /* New state value */
197 change_state; /* State change */
198 char value[CUPS_MAX_SUPPLIES * 4],
199 /* marker-levels value string */
200 *ptr; /* Pointer into value string */
201 cups_snmp_t packet; /* SNMP response packet */
202
203 /*
204 * Generate the marker-levels value string...
205 */
206
207 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
208 {
209 if (i)
210 *ptr++ = ',';
211
212 if (supplies[i].max_capacity > 0)
213 sprintf(ptr, "%d", 100 * supplies[i].level / supplies[i].max_capacity);
214 else
215 strcpy(ptr, "-1");
216 }
217
218 fprintf(stderr, "ATTR: marker-levels=%s\n", value);
219
220 /*
221 * Get the current printer status bits...
222 */
223
224 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
225 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
226 hrPrinterDetectedErrorState))
227 return (-1);
228
229 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
230 packet.object_type != CUPS_ASN1_OCTET_STRING)
231 return (-1);
232
233 if (packet.object_value.string.num_bytes == 2)
234 new_state = (packet.object_value.string.bytes[0] << 8) |
235 packet.object_value.string.bytes[1];
236 else if (packet.object_value.string.num_bytes == 1)
237 new_state = (packet.object_value.string.bytes[0] << 8);
238 else
239 new_state = 0;
240
241 if (current_state < 0)
242 change_state = 0xffff;
243 else
244 change_state = current_state ^ new_state;
245
246 fprintf(stderr, "DEBUG: new_state=%x, change_state=%x, laser_printer=%d\n",
247 new_state, change_state, laser_printer);
248
249 for (i = 0;
250 i < (int)(sizeof(printer_states) / sizeof(printer_states[0]));
251 i ++)
252 if (change_state & printer_states[i].bit)
253 {
254 if (!laser_printer && !strncmp(printer_states[i].keyword, "toner-", 6))
255 {
256 /*
257 * Map toner-xxx to marker-supply-xxx to avoid confusing "out of toner"
258 * messages on inkjet print queues...
259 */
260
261 if (printer_states[i].bit == CUPS_TC_lowToner)
262 fprintf(stderr, "STATE: %cmarker-supply-low-report\n",
263 (new_state & CUPS_TC_lowToner) ? '+' : '-');
264 else
265 fprintf(stderr, "STATE: %cmarker-supply-empty-warning\n",
266 (new_state & CUPS_TC_noToner) ? '+' : '-');
267 }
268 else
269 fprintf(stderr, "STATE: %c%s\n",
270 (new_state & printer_states[i].bit) ? '+' : '-',
271 printer_states[i].keyword);
272 }
273
274 current_state = new_state;
275
276 /*
277 * Get the current printer state...
278 */
279
280 if (printer_state)
281 {
282 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
283 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
284 hrPrinterStatus))
285 return (-1);
286
287 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
288 packet.object_type != CUPS_ASN1_INTEGER)
289 return (-1);
290
291 *printer_state = packet.object_value.integer;
292 }
293
294 /*
295 * Get the current page count...
296 */
297
298 if (page_count)
299 {
300 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
301 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
302 prtMarkerLifeCount))
303 return (-1);
304
305 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
306 packet.object_type != CUPS_ASN1_COUNTER)
307 return (-1);
308
309 *page_count = packet.object_value.counter;
310 }
311
312 return (0);
313 }
314 else
315 return (-1);
316 }
317
318
319 /*
320 * 'backend_init_supplies()' - Initialize the supplies list.
321 */
322
323 static void
324 backend_init_supplies(
325 int snmp_fd, /* I - SNMP socket */
326 http_addr_t *addr) /* I - Printer address */
327 {
328 int i, /* Looping var */
329 type; /* Current marker type */
330 cups_file_t *cachefile; /* Cache file */
331 const char *cachedir; /* CUPS_CACHEDIR value */
332 char addrstr[1024], /* Address string */
333 cachefilename[1024], /* Cache filename */
334 description[CUPS_SNMP_MAX_STRING],
335 /* Device description string */
336 value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 2 + 3)],
337 /* Value string */
338 *ptr, /* Pointer into value string */
339 *name_ptr; /* Pointer into name string */
340 cups_snmp_t packet; /* SNMP response packet */
341 ppd_file_t *ppd; /* PPD file for this queue */
342 ppd_attr_t *ppdattr; /* cupsSNMPSupplies attribute */
343 static const char * const types[] = /* Supply types */
344 {
345 "other",
346 "unknown",
347 "toner",
348 "wasteToner",
349 "ink",
350 "inkCartridge",
351 "inkRibbon",
352 "wasteInk",
353 "opc",
354 "developer",
355 "fuserOil",
356 "solidWax",
357 "ribbonWax",
358 "wasteWax",
359 "fuser",
360 "coronaWire",
361 "fuserOilWick",
362 "cleanerUnit",
363 "fuserCleaningPad",
364 "transferUnit",
365 "tonerCartridge",
366 "fuserOiler",
367 "water",
368 "wasteWater",
369 "glueWaterAdditive",
370 "wastePaper",
371 "bindingSupply",
372 "bandingSupply",
373 "stitchingWire",
374 "shrinkWrap",
375 "paperWrap",
376 "staples",
377 "inserts",
378 "covers"
379 };
380
381
382 /*
383 * Reset state information...
384 */
385
386 current_addr = *addr;
387 current_state = -1;
388 num_supplies = -1;
389 charset = -1;
390
391 memset(supplies, 0, sizeof(supplies));
392
393 /*
394 * See if we should be getting supply levels via SNMP...
395 */
396
397 if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL &&
398 (ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL &&
399 ppdattr->value && strcasecmp(ppdattr->value, "true"))
400 {
401 ppdClose(ppd);
402 return;
403 }
404
405 ppdClose(ppd);
406
407 /*
408 * Get the device description...
409 */
410
411 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
412 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
413 hrDeviceDescr))
414 return;
415
416 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
417 packet.object_type != CUPS_ASN1_OCTET_STRING)
418 {
419 strlcpy(description, "Unknown", sizeof(description));
420 num_supplies = 0;
421 }
422 else
423 strlcpy(description, (char *)packet.object_value.string.bytes,
424 sizeof(description));
425
426 fprintf(stderr, "DEBUG2: hrDeviceDesc=\"%s\"\n", description);
427
428 /*
429 * See if we have already queried this device...
430 */
431
432 httpAddrString(addr, addrstr, sizeof(addrstr));
433
434 if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL)
435 cachedir = CUPS_CACHEDIR;
436
437 snprintf(cachefilename, sizeof(cachefilename), "%s/%s.snmp", cachedir,
438 addrstr);
439
440 if ((cachefile = cupsFileOpen(cachefilename, "r")) != NULL)
441 {
442 /*
443 * Yes, read the cache file:
444 *
445 * 2 num_supplies charset
446 * device description
447 * supply structures...
448 */
449
450 if (cupsFileGets(cachefile, value, sizeof(value)))
451 {
452 if (sscanf(value, "2 %d%d", &num_supplies, &charset) == 2 &&
453 num_supplies <= CUPS_MAX_SUPPLIES &&
454 cupsFileGets(cachefile, value, sizeof(value)))
455 {
456 if (!strcmp(description, value))
457 cupsFileRead(cachefile, (char *)supplies,
458 num_supplies * sizeof(backend_supplies_t));
459 else
460 {
461 num_supplies = -1;
462 charset = -1;
463 }
464 }
465 else
466 {
467 num_supplies = -1;
468 charset = -1;
469 }
470 }
471
472 cupsFileClose(cachefile);
473 }
474
475 /*
476 * If the cache information isn't correct, scan for supplies...
477 */
478
479 if (charset < 0)
480 {
481 /*
482 * Get the configured character set...
483 */
484
485 int oid[CUPS_SNMP_MAX_OID]; /* OID for character set */
486
487
488 if (!_cupsSNMPWrite(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
489 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
490 prtGeneralCurrentLocalization))
491 return;
492
493 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
494 packet.object_type != CUPS_ASN1_INTEGER)
495 {
496 fprintf(stderr,
497 "DEBUG: prtGeneralCurrentLocalization type is %x, expected %x!\n",
498 packet.object_type, CUPS_ASN1_INTEGER);
499 return;
500 }
501
502 fprintf(stderr, "DEBUG2: prtGeneralCurrentLocalization=%d\n",
503 packet.object_value.integer);
504
505 _cupsSNMPCopyOID(oid, prtLocalizationCharacterSet, CUPS_SNMP_MAX_OID);
506 oid[prtLocalizationCharacterSetOffset - 2] = packet.object_value.integer;
507
508
509 if (!_cupsSNMPWrite(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
510 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
511 oid))
512 return;
513
514 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
515 packet.object_type != CUPS_ASN1_INTEGER)
516 {
517 fprintf(stderr,
518 "DEBUG: prtLocalizationCharacterSet type is %x, expected %x!\n",
519 packet.object_type, CUPS_ASN1_INTEGER);
520 return;
521 }
522
523 fprintf(stderr, "DEBUG2: prtLocalizationCharacterSet=%d\n",
524 packet.object_value.integer);
525 charset = packet.object_value.integer;
526 }
527
528 if (num_supplies < 0)
529 {
530 /*
531 * Walk the printer configuration information...
532 */
533
534 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
535 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry,
536 CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
537 }
538
539 /*
540 * Save the cached information...
541 */
542
543 if (num_supplies < 0)
544 num_supplies = 0;
545
546 if ((cachefile = cupsFileOpen(cachefilename, "w")) != NULL)
547 {
548 cupsFilePrintf(cachefile, "2 %d %d\n", num_supplies, charset);
549 cupsFilePrintf(cachefile, "%s\n", description);
550
551 if (num_supplies > 0)
552 cupsFileWrite(cachefile, (char *)supplies,
553 num_supplies * sizeof(backend_supplies_t));
554
555 cupsFileClose(cachefile);
556 }
557
558 if (num_supplies <= 0)
559 return;
560
561 /*
562 * Get the colors...
563 */
564
565 for (i = 0; i < num_supplies; i ++)
566 strcpy(supplies[i].color, "none");
567
568 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
569 _cupsSNMPDefaultCommunity(), prtMarkerColorantValue,
570 CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
571
572 /*
573 * Output the marker-colors attribute...
574 */
575
576 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
577 {
578 if (i)
579 *ptr++ = ',';
580
581 strcpy(ptr, supplies[i].color);
582 }
583
584 fprintf(stderr, "ATTR: marker-colors=%s\n", value);
585
586 /*
587 * Output the marker-names attribute...
588 */
589
590 for (i = 0, ptr = value; i < num_supplies; i ++)
591 {
592 if (i)
593 *ptr++ = ',';
594
595 *ptr++ = '\"';
596 for (name_ptr = supplies[i].name; *name_ptr;)
597 {
598 if (*name_ptr == '\\' || *name_ptr == '\"')
599 *ptr++ = '\\';
600
601 *ptr++ = *name_ptr++;
602 }
603 *ptr++ = '\"';
604 }
605
606 *ptr = '\0';
607
608 fprintf(stderr, "ATTR: marker-names=%s\n", value);
609
610 /*
611 * Output the marker-types attribute...
612 */
613
614 laser_printer = 0;
615
616 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
617 {
618 if (i)
619 *ptr++ = ',';
620
621 type = supplies[i].type;
622
623 if (type == CUPS_TC_toner)
624 laser_printer = 1;
625
626 if (type < CUPS_TC_other || type > CUPS_TC_covers)
627 strcpy(ptr, "unknown");
628 else
629 strcpy(ptr, types[type - CUPS_TC_other]);
630 }
631
632 fprintf(stderr, "ATTR: marker-types=%s\n", value);
633 }
634
635
636 /*
637 * 'backend_walk_cb()' - Interpret the supply value responses.
638 */
639
640 static void
641 backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */
642 void *data) /* I - User data (unused) */
643 {
644 int i, j, k; /* Looping vars */
645 static const char * const colors[8][2] =
646 { /* Standard color names */
647 { "black", "#000000" },
648 { "blue", "#0000FF" },
649 { "cyan", "#00FFFF" },
650 { "green", "#00FF00" },
651 { "magenta", "#FF00FF" },
652 { "red", "#FF0000" },
653 { "white", "#FFFFFF" },
654 { "yellow", "#FFFF00" }
655 };
656
657
658 (void)data;
659
660 if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) &&
661 packet->object_type == CUPS_ASN1_OCTET_STRING)
662 {
663 /*
664 * Get colorant...
665 */
666
667 i = packet->object_name[prtMarkerColorantValueOffset];
668
669 fprintf(stderr, "DEBUG2: prtMarkerColorantValue.1.%d = \"%s\"\n", i,
670 (char *)packet->object_value.string.bytes);
671
672 for (j = 0; j < num_supplies; j ++)
673 if (supplies[j].colorant == i)
674 {
675 for (k = 0; k < (int)(sizeof(colors) / sizeof(colors[0])); k ++)
676 if (!strcmp(colors[k][0], (char *)packet->object_value.string.bytes))
677 {
678 strcpy(supplies[j].color, colors[k][1]);
679 break;
680 }
681 }
682 }
683 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
684 {
685 /*
686 * Get colorant index...
687 */
688
689 i = packet->object_name[prtMarkerSuppliesColorantIndexOffset];
690 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
691 packet->object_type != CUPS_ASN1_INTEGER)
692 return;
693
694 fprintf(stderr, "DEBUG2: prtMarkerSuppliesColorantIndex.1.%d = %d\n", i,
695 packet->object_value.integer);
696
697 if (i > num_supplies)
698 num_supplies = i;
699
700 supplies[i - 1].colorant = packet->object_value.integer;
701 }
702 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription))
703 {
704 /*
705 * Get supply name/description...
706 */
707
708 i = packet->object_name[prtMarkerSuppliesDescriptionOffset];
709 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
710 packet->object_type != CUPS_ASN1_OCTET_STRING)
711 return;
712
713 if (i > num_supplies)
714 num_supplies = i;
715
716 switch (charset)
717 {
718 case CUPS_TC_csASCII :
719 case CUPS_TC_csUTF8 :
720 case CUPS_TC_csUnicodeASCII :
721 strlcpy(supplies[i - 1].name,
722 (char *)packet->object_value.string.bytes,
723 sizeof(supplies[0].name));
724 break;
725
726 case CUPS_TC_csISOLatin1 :
727 case CUPS_TC_csUnicodeLatin1 :
728 cupsCharsetToUTF8((cups_utf8_t *)supplies[i - 1].name,
729 (char *)packet->object_value.string.bytes,
730 sizeof(supplies[0].name), CUPS_ISO8859_1);
731 break;
732
733 case CUPS_TC_csShiftJIS :
734 cupsCharsetToUTF8((cups_utf8_t *)supplies[i - 1].name,
735 (char *)packet->object_value.string.bytes,
736 sizeof(supplies[0].name), CUPS_JIS_X0213);
737 break;
738
739 case CUPS_TC_csUCS4 :
740 case CUPS_TC_csUTF32 :
741 case CUPS_TC_csUTF32BE :
742 case CUPS_TC_csUTF32LE :
743 cupsUTF32ToUTF8((cups_utf8_t *)supplies[i - 1].name,
744 (cups_utf32_t *)packet->object_value.string.bytes,
745 sizeof(supplies[0].name));
746 break;
747
748 case CUPS_TC_csUnicode :
749 case CUPS_TC_csUTF16BE :
750 case CUPS_TC_csUTF16LE :
751 utf16_to_utf8((cups_utf8_t *)supplies[i - 1].name,
752 packet->object_value.string.bytes,
753 packet->object_value.string.num_bytes,
754 sizeof(supplies[0].name), charset == CUPS_TC_csUTF16LE);
755 break;
756
757 default :
758 /*
759 * If we get here, the printer is using an unknown character set and
760 * we just want to copy characters that look like ASCII...
761 */
762
763 {
764 char *src, *dst; /* Pointers into strings */
765
766
767 /*
768 * Loop safe because both the object_value and supplies char arrays
769 * are CUPS_SNMP_MAX_STRING elements long.
770 */
771
772 for (src = (char *)packet->object_value.string.bytes,
773 dst = supplies[i - 1].name;
774 *src;
775 src ++)
776 {
777 if ((*src & 0x80) || *src < ' ' || *src == 0x7f)
778 *dst++ = '?';
779 else
780 *dst++ = *src;
781 }
782
783 *dst = '\0';
784 }
785 break;
786 }
787
788 fprintf(stderr, "DEBUG2: prtMarkerSuppliesDescription.1.%d = \"%s\"\n", i,
789 supplies[i - 1].name);
790
791 }
792 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesLevel))
793 {
794 /*
795 * Get level...
796 */
797
798 i = packet->object_name[prtMarkerSuppliesLevelOffset];
799 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
800 packet->object_type != CUPS_ASN1_INTEGER)
801 return;
802
803 fprintf(stderr, "DEBUG2: prtMarkerSuppliesLevel.1.%d = %d\n", i,
804 packet->object_value.integer);
805
806 if (i > num_supplies)
807 num_supplies = i;
808
809 supplies[i - 1].level = packet->object_value.integer;
810 }
811 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity))
812 {
813 /*
814 * Get max capacity...
815 */
816
817 i = packet->object_name[prtMarkerSuppliesMaxCapacityOffset];
818 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
819 packet->object_type != CUPS_ASN1_INTEGER)
820 return;
821
822 fprintf(stderr, "DEBUG2: prtMarkerSuppliesMaxCapacity.1.%d = %d\n", i,
823 packet->object_value.integer);
824
825 if (i > num_supplies)
826 num_supplies = i;
827
828 supplies[i - 1].max_capacity = packet->object_value.integer;
829 }
830 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
831 {
832 /*
833 * Get marker type...
834 */
835
836 i = packet->object_name[prtMarkerSuppliesTypeOffset];
837 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
838 packet->object_type != CUPS_ASN1_INTEGER)
839 return;
840
841 fprintf(stderr, "DEBUG2: prtMarkerSuppliesType.1.%d = %d\n", i,
842 packet->object_value.integer);
843
844 if (i > num_supplies)
845 num_supplies = i;
846
847 supplies[i - 1].type = packet->object_value.integer;
848 }
849 }
850
851
852 /*
853 * 'utf16_to_utf8()' - Convert UTF-16 text to UTF-8.
854 */
855
856 static void
857 utf16_to_utf8(
858 cups_utf8_t *dst, /* I - Destination buffer */
859 const unsigned char *src, /* I - Source string */
860 size_t srcsize, /* I - Size of source string */
861 size_t dstsize, /* I - Size of destination buffer */
862 int le) /* I - Source is little-endian? */
863 {
864 cups_utf32_t ch, /* Current character */
865 temp[CUPS_SNMP_MAX_STRING],
866 /* UTF-32 string */
867 *ptr; /* Pointer into UTF-32 string */
868
869
870 for (ptr = temp; srcsize >= 2;)
871 {
872 if (le)
873 ch = src[0] | (src[1] << 8);
874 else
875 ch = (src[0] << 8) | src[1];
876
877 src += 2;
878 srcsize -= 2;
879
880 if (ch >= 0xd800 && ch <= 0xdbff && srcsize >= 2)
881 {
882 /*
883 * Multi-word UTF-16 char...
884 */
885
886 int lch; /* Lower word */
887
888
889 if (le)
890 lch = src[0] | (src[1] << 8);
891 else
892 lch = (src[0] << 8) | src[1];
893
894 if (lch >= 0xdc00 && lch <= 0xdfff)
895 {
896 src += 2;
897 srcsize -= 2;
898
899 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
900 }
901 }
902
903 if (ptr < (temp + CUPS_SNMP_MAX_STRING - 1))
904 *ptr++ = ch;
905 }
906
907 *ptr = '\0';
908
909 cupsUTF32ToUTF8(dst, temp, dstsize);
910 }
911
912
913 /*
914 * End of "$Id$".
915 */