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