]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/snmp-supplies.c
Fix crasher in SNMP supply code.
[thirdparty/cups.git] / backend / snmp-supplies.c
1 /*
2 * "$Id$"
3 *
4 * SNMP supplies functions for CUPS.
5 *
6 * Copyright 2008-2011 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 #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
49
50
51 /*
52 * Local structures...
53 */
54
55 typedef struct /**** Printer supply data ****/
56 {
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 */
63 } backend_supplies_t;
64
65 typedef struct /**** Printer state table ****/
66 {
67 int bit; /* State bit */
68 const char *keyword; /* IPP printer-state-reasons keyword */
69 } backend_state_t;
70
71
72 /*
73 * Local globals...
74 */
75
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 */
86
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 },
105 /* Colorant OID */
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 };
115 /* Supplies OID */
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 },
132 /* Level OID */
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 },
146 /* Type OID */
147 prtMarkerSuppliesTypeOffset =
148 (sizeof(prtMarkerSuppliesType) /
149 sizeof(prtMarkerSuppliesType[0]));
150 /* Offset to supply index */
151
152 static const backend_state_t const printer_states[] =
153 {
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" }
167 };
168
169 static const backend_state_t const supply_states[] =
170 {
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" }
181 };
182
183
184 /*
185 * Local functions...
186 */
187
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);
192
193
194 /*
195 * 'backendSNMPSupplies()' - Get the current supplies for a device.
196 */
197
198 int /* O - 0 on success, -1 on error */
199 backendSNMPSupplies(
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 */
204 {
205 if (!httpAddrEqual(addr, &current_addr))
206 backend_init_supplies(snmp_fd, addr);
207 else if (num_supplies > 0)
208 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
209 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel,
210 CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
211
212 if (page_count)
213 *page_count = -1;
214
215 if (printer_state)
216 *printer_state = -1;
217
218 if (num_supplies > 0)
219 {
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 */
229
230 /*
231 * Generate the marker-levels value string...
232 */
233
234 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
235 {
236 if (supplies[i].max_capacity > 0)
237 percent = 100 * supplies[i].level / supplies[i].max_capacity;
238 else
239 percent = 50;
240
241 if (percent <= 10)
242 {
243 switch (supplies[i].type)
244 {
245 case CUPS_TC_toner :
246 case CUPS_TC_tonerCartridge :
247 if (percent <= 1)
248 new_supply_state |= CUPS_TONER_EMPTY;
249 else
250 new_supply_state |= CUPS_TONER_LOW;
251 break;
252 case CUPS_TC_wasteToner :
253 case CUPS_TC_wasteInk :
254 if (percent <= 1)
255 new_supply_state |= CUPS_MARKER_WASTE_FULL;
256 else
257 new_supply_state |= CUPS_MARKER_WASTE_ALMOST_FULL;
258 break;
259 case CUPS_TC_ink :
260 case CUPS_TC_inkCartridge :
261 case CUPS_TC_inkRibbon :
262 case CUPS_TC_solidWax :
263 case CUPS_TC_ribbonWax :
264 if (percent <= 1)
265 new_supply_state |= CUPS_MARKER_SUPPLY_EMPTY;
266 else
267 new_supply_state |= CUPS_MARKER_SUPPLY_LOW;
268 break;
269 case CUPS_TC_developer :
270 if (percent <= 1)
271 new_supply_state |= CUPS_DEVELOPER_EMPTY;
272 else
273 new_supply_state |= CUPS_DEVELOPER_LOW;
274 break;
275 case CUPS_TC_coronaWire :
276 case CUPS_TC_fuser :
277 case CUPS_TC_opc :
278 case CUPS_TC_transferUnit :
279 if (percent <= 1)
280 new_supply_state |= CUPS_OPC_LIFE_OVER;
281 else
282 new_supply_state |= CUPS_OPC_NEAR_EOL;
283 break;
284 }
285 }
286
287 if (i)
288 *ptr++ = ',';
289
290 if (supplies[i].max_capacity > 0)
291 sprintf(ptr, "%d", percent);
292 else
293 strcpy(ptr, "-1");
294 }
295
296 fprintf(stderr, "ATTR: marker-levels=%s\n", value);
297
298 if (supply_state < 0)
299 change_state = 0xffff;
300 else
301 change_state = supply_state ^ new_supply_state;
302
303 fprintf(stderr, "DEBUG: new_supply_state=%x, change_state=%x\n",
304 new_supply_state, change_state);
305
306 for (i = 0;
307 i < (int)(sizeof(supply_states) / sizeof(supply_states[0]));
308 i ++)
309 if (change_state & supply_states[i].bit)
310 {
311 fprintf(stderr, "STATE: %c%s\n",
312 (new_supply_state & supply_states[i].bit) ? '+' : '-',
313 supply_states[i].keyword);
314 }
315
316 supply_state = new_supply_state;
317
318 /*
319 * Get the current printer status bits...
320 */
321
322 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
323 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
324 hrPrinterDetectedErrorState))
325 return (-1);
326
327 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
328 packet.object_type != CUPS_ASN1_OCTET_STRING)
329 return (-1);
330
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);
336 else
337 new_state = 0;
338
339 if (current_state < 0)
340 change_state = 0xffff;
341 else
342 change_state = current_state ^ new_state;
343
344 fprintf(stderr, "DEBUG: new_state=%x, change_state=%x\n", new_state,
345 change_state);
346
347 for (i = 0;
348 i < (int)(sizeof(printer_states) / sizeof(printer_states[0]));
349 i ++)
350 if (change_state & printer_states[i].bit)
351 {
352 fprintf(stderr, "STATE: %c%s\n",
353 (new_state & printer_states[i].bit) ? '+' : '-',
354 printer_states[i].keyword);
355 }
356
357 current_state = new_state;
358
359 /*
360 * Get the current printer state...
361 */
362
363 if (printer_state)
364 {
365 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
366 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
367 hrPrinterStatus))
368 return (-1);
369
370 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
371 packet.object_type != CUPS_ASN1_INTEGER)
372 return (-1);
373
374 *printer_state = packet.object_value.integer;
375 }
376
377 /*
378 * Get the current page count...
379 */
380
381 if (page_count)
382 {
383 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
384 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
385 prtMarkerLifeCount))
386 return (-1);
387
388 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
389 packet.object_type != CUPS_ASN1_COUNTER)
390 return (-1);
391
392 *page_count = packet.object_value.counter;
393 }
394
395 return (0);
396 }
397 else
398 return (-1);
399 }
400
401
402 /*
403 * 'backend_init_supplies()' - Initialize the supplies list.
404 */
405
406 static void
407 backend_init_supplies(
408 int snmp_fd, /* I - SNMP socket */
409 http_addr_t *addr) /* I - Printer address */
410 {
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)],
420 /* Value string */
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 */
427 {
428 "other",
429 "unknown",
430 "toner",
431 "wasteToner",
432 "ink",
433 "inkCartridge",
434 "inkRibbon",
435 "wasteInk",
436 "opc",
437 "developer",
438 "fuserOil",
439 "solidWax",
440 "ribbonWax",
441 "wasteWax",
442 "fuser",
443 "coronaWire",
444 "fuserOilWick",
445 "cleanerUnit",
446 "fuserCleaningPad",
447 "transferUnit",
448 "tonerCartridge",
449 "fuserOiler",
450 "water",
451 "wasteWater",
452 "glueWaterAdditive",
453 "wastePaper",
454 "bindingSupply",
455 "bandingSupply",
456 "stitchingWire",
457 "shrinkWrap",
458 "paperWrap",
459 "staples",
460 "inserts",
461 "covers"
462 };
463
464
465 /*
466 * Reset state information...
467 */
468
469 current_addr = *addr;
470 current_state = -1;
471 num_supplies = -1;
472 charset = -1;
473
474 memset(supplies, 0, sizeof(supplies));
475
476 /*
477 * See if we should be getting supply levels via SNMP...
478 */
479
480 if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL ||
481 ((ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL &&
482 ppdattr->value && strcasecmp(ppdattr->value, "true")))
483 {
484 ppdClose(ppd);
485 return;
486 }
487
488 ppdClose(ppd);
489
490 /*
491 * Get the device description...
492 */
493
494 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
495 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
496 hrDeviceDescr))
497 return;
498
499 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
500 packet.object_type != CUPS_ASN1_OCTET_STRING)
501 {
502 strlcpy(description, "Unknown", sizeof(description));
503 num_supplies = 0;
504 }
505 else
506 strlcpy(description, (char *)packet.object_value.string.bytes,
507 sizeof(description));
508
509 fprintf(stderr, "DEBUG2: hrDeviceDesc=\"%s\"\n", description);
510
511 /*
512 * See if we have already queried this device...
513 */
514
515 httpAddrString(addr, addrstr, sizeof(addrstr));
516
517 if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL)
518 cachedir = CUPS_CACHEDIR;
519
520 snprintf(cachefilename, sizeof(cachefilename), "%s/%s.snmp", cachedir,
521 addrstr);
522
523 if ((cachefile = cupsFileOpen(cachefilename, "r")) != NULL)
524 {
525 /*
526 * Yes, read the cache file:
527 *
528 * 2 num_supplies charset
529 * device description
530 * supply structures...
531 */
532
533 if (cupsFileGets(cachefile, value, sizeof(value)))
534 {
535 if (sscanf(value, "2 %d%d", &num_supplies, &charset) == 2 &&
536 num_supplies <= CUPS_MAX_SUPPLIES &&
537 cupsFileGets(cachefile, value, sizeof(value)))
538 {
539 if (!strcmp(description, value))
540 cupsFileRead(cachefile, (char *)supplies,
541 num_supplies * sizeof(backend_supplies_t));
542 else
543 {
544 num_supplies = -1;
545 charset = -1;
546 }
547 }
548 else
549 {
550 num_supplies = -1;
551 charset = -1;
552 }
553 }
554
555 cupsFileClose(cachefile);
556 }
557
558 /*
559 * If the cache information isn't correct, scan for supplies...
560 */
561
562 if (charset < 0)
563 {
564 /*
565 * Get the configured character set...
566 */
567
568 int oid[CUPS_SNMP_MAX_OID]; /* OID for character set */
569
570
571 if (!_cupsSNMPWrite(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
572 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
573 prtGeneralCurrentLocalization))
574 return;
575
576 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
577 packet.object_type != CUPS_ASN1_INTEGER)
578 {
579 fprintf(stderr,
580 "DEBUG: prtGeneralCurrentLocalization type is %x, expected %x!\n",
581 packet.object_type, CUPS_ASN1_INTEGER);
582 return;
583 }
584
585 fprintf(stderr, "DEBUG2: prtGeneralCurrentLocalization=%d\n",
586 packet.object_value.integer);
587
588 _cupsSNMPCopyOID(oid, prtLocalizationCharacterSet, CUPS_SNMP_MAX_OID);
589 oid[prtLocalizationCharacterSetOffset - 2] = packet.object_value.integer;
590
591
592 if (!_cupsSNMPWrite(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
593 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
594 oid))
595 return;
596
597 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
598 packet.object_type != CUPS_ASN1_INTEGER)
599 {
600 fprintf(stderr,
601 "DEBUG: prtLocalizationCharacterSet type is %x, expected %x!\n",
602 packet.object_type, CUPS_ASN1_INTEGER);
603 return;
604 }
605
606 fprintf(stderr, "DEBUG2: prtLocalizationCharacterSet=%d\n",
607 packet.object_value.integer);
608 charset = packet.object_value.integer;
609 }
610
611 if (num_supplies < 0)
612 {
613 /*
614 * Walk the printer configuration information...
615 */
616
617 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
618 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry,
619 CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
620 }
621
622 /*
623 * Save the cached information...
624 */
625
626 if (num_supplies < 0)
627 num_supplies = 0;
628
629 if ((cachefile = cupsFileOpen(cachefilename, "w")) != NULL)
630 {
631 cupsFilePrintf(cachefile, "2 %d %d\n", num_supplies, charset);
632 cupsFilePrintf(cachefile, "%s\n", description);
633
634 if (num_supplies > 0)
635 cupsFileWrite(cachefile, (char *)supplies,
636 num_supplies * sizeof(backend_supplies_t));
637
638 cupsFileClose(cachefile);
639 }
640
641 if (num_supplies <= 0)
642 return;
643
644 /*
645 * Get the colors...
646 */
647
648 for (i = 0; i < num_supplies; i ++)
649 strcpy(supplies[i].color, "none");
650
651 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
652 _cupsSNMPDefaultCommunity(), prtMarkerColorantValue,
653 CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
654
655 /*
656 * Output the marker-colors attribute...
657 */
658
659 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
660 {
661 if (i)
662 *ptr++ = ',';
663
664 strcpy(ptr, supplies[i].color);
665 }
666
667 fprintf(stderr, "ATTR: marker-colors=%s\n", value);
668
669 /*
670 * Output the marker-names attribute...
671 */
672
673 for (i = 0, ptr = value; i < num_supplies; i ++)
674 {
675 if (i)
676 *ptr++ = ',';
677
678 *ptr++ = '\"';
679 for (name_ptr = supplies[i].name; *name_ptr;)
680 {
681 if (*name_ptr == '\\' || *name_ptr == '\"')
682 *ptr++ = '\\';
683
684 *ptr++ = *name_ptr++;
685 }
686 *ptr++ = '\"';
687 }
688
689 *ptr = '\0';
690
691 fprintf(stderr, "ATTR: marker-names=%s\n", value);
692
693 /*
694 * Output the marker-types attribute...
695 */
696
697 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
698 {
699 if (i)
700 *ptr++ = ',';
701
702 type = supplies[i].type;
703
704 if (type < CUPS_TC_other || type > CUPS_TC_covers)
705 strcpy(ptr, "unknown");
706 else
707 strcpy(ptr, types[type - CUPS_TC_other]);
708 }
709
710 fprintf(stderr, "ATTR: marker-types=%s\n", value);
711 }
712
713
714 /*
715 * 'backend_walk_cb()' - Interpret the supply value responses.
716 */
717
718 static void
719 backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */
720 void *data) /* I - User data (unused) */
721 {
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" }
733 };
734
735
736 (void)data;
737
738 if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) &&
739 packet->object_type == CUPS_ASN1_OCTET_STRING)
740 {
741 /*
742 * Get colorant...
743 */
744
745 i = packet->object_name[prtMarkerColorantValueOffset];
746
747 fprintf(stderr, "DEBUG2: prtMarkerColorantValue.1.%d = \"%s\"\n", i,
748 (char *)packet->object_value.string.bytes);
749
750 for (j = 0; j < num_supplies; j ++)
751 if (supplies[j].colorant == i)
752 {
753 for (k = 0; k < (int)(sizeof(colors) / sizeof(colors[0])); k ++)
754 if (!strcmp(colors[k][0], (char *)packet->object_value.string.bytes))
755 {
756 strcpy(supplies[j].color, colors[k][1]);
757 break;
758 }
759 }
760 }
761 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
762 {
763 /*
764 * Get colorant index...
765 */
766
767 i = packet->object_name[prtMarkerSuppliesColorantIndexOffset];
768 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
769 packet->object_type != CUPS_ASN1_INTEGER)
770 return;
771
772 fprintf(stderr, "DEBUG2: prtMarkerSuppliesColorantIndex.1.%d = %d\n", i,
773 packet->object_value.integer);
774
775 if (i > num_supplies)
776 num_supplies = i;
777
778 supplies[i - 1].colorant = packet->object_value.integer;
779 }
780 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription))
781 {
782 /*
783 * Get supply name/description...
784 */
785
786 i = packet->object_name[prtMarkerSuppliesDescriptionOffset];
787 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
788 packet->object_type != CUPS_ASN1_OCTET_STRING)
789 return;
790
791 if (i > num_supplies)
792 num_supplies = i;
793
794 switch (charset)
795 {
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));
802 break;
803
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);
809 break;
810
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);
815 break;
816
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));
824 break;
825
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);
833 break;
834
835 default :
836 /*
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...
839 */
840
841 {
842 char *src, *dst; /* Pointers into strings */
843
844
845 /*
846 * Loop safe because both the object_value and supplies char arrays
847 * are CUPS_SNMP_MAX_STRING elements long.
848 */
849
850 for (src = (char *)packet->object_value.string.bytes,
851 dst = supplies[i - 1].name;
852 *src;
853 src ++)
854 {
855 if ((*src & 0x80) || *src < ' ' || *src == 0x7f)
856 *dst++ = '?';
857 else
858 *dst++ = *src;
859 }
860
861 *dst = '\0';
862 }
863 break;
864 }
865
866 fprintf(stderr, "DEBUG2: prtMarkerSuppliesDescription.1.%d = \"%s\"\n", i,
867 supplies[i - 1].name);
868
869 }
870 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesLevel))
871 {
872 /*
873 * Get level...
874 */
875
876 i = packet->object_name[prtMarkerSuppliesLevelOffset];
877 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
878 packet->object_type != CUPS_ASN1_INTEGER)
879 return;
880
881 fprintf(stderr, "DEBUG2: prtMarkerSuppliesLevel.1.%d = %d\n", i,
882 packet->object_value.integer);
883
884 if (i > num_supplies)
885 num_supplies = i;
886
887 supplies[i - 1].level = packet->object_value.integer;
888 }
889 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity))
890 {
891 /*
892 * Get max capacity...
893 */
894
895 i = packet->object_name[prtMarkerSuppliesMaxCapacityOffset];
896 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
897 packet->object_type != CUPS_ASN1_INTEGER)
898 return;
899
900 fprintf(stderr, "DEBUG2: prtMarkerSuppliesMaxCapacity.1.%d = %d\n", i,
901 packet->object_value.integer);
902
903 if (i > num_supplies)
904 num_supplies = i;
905
906 supplies[i - 1].max_capacity = packet->object_value.integer;
907 }
908 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
909 {
910 /*
911 * Get marker type...
912 */
913
914 i = packet->object_name[prtMarkerSuppliesTypeOffset];
915 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
916 packet->object_type != CUPS_ASN1_INTEGER)
917 return;
918
919 fprintf(stderr, "DEBUG2: prtMarkerSuppliesType.1.%d = %d\n", i,
920 packet->object_value.integer);
921
922 if (i > num_supplies)
923 num_supplies = i;
924
925 supplies[i - 1].type = packet->object_value.integer;
926 }
927 }
928
929
930 /*
931 * 'utf16_to_utf8()' - Convert UTF-16 text to UTF-8.
932 */
933
934 static void
935 utf16_to_utf8(
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? */
941 {
942 cups_utf32_t ch, /* Current character */
943 temp[CUPS_SNMP_MAX_STRING],
944 /* UTF-32 string */
945 *ptr; /* Pointer into UTF-32 string */
946
947
948 for (ptr = temp; srcsize >= 2;)
949 {
950 if (le)
951 ch = src[0] | (src[1] << 8);
952 else
953 ch = (src[0] << 8) | src[1];
954
955 src += 2;
956 srcsize -= 2;
957
958 if (ch >= 0xd800 && ch <= 0xdbff && srcsize >= 2)
959 {
960 /*
961 * Multi-word UTF-16 char...
962 */
963
964 int lch; /* Lower word */
965
966
967 if (le)
968 lch = src[0] | (src[1] << 8);
969 else
970 lch = (src[0] << 8) | src[1];
971
972 if (lch >= 0xdc00 && lch <= 0xdfff)
973 {
974 src += 2;
975 srcsize -= 2;
976
977 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
978 }
979 }
980
981 if (ptr < (temp + CUPS_SNMP_MAX_STRING - 1))
982 *ptr++ = ch;
983 }
984
985 *ptr = '\0';
986
987 cupsUTF32ToUTF8(dst, temp, dstsize);
988 }
989
990
991 /*
992 * End of "$Id$".
993 */