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