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