]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/snmp-supplies.c
Merge changes from CUPS 1.6svn-r9939.
[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
eac3a0a0
MS
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
c8fef167 47
568fa3fa
MS
48
49/*
50 * Local structures...
51 */
52
745129be 53typedef struct /**** Printer supply data ****/
568fa3fa
MS
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
745129be
MS
63typedef struct /**** Printer state table ****/
64{
65 int bit; /* State bit */
66 const char *keyword; /* IPP printer-state-reasons keyword */
67} backend_state_t;
68
568fa3fa
MS
69
70/*
71 * Local globals...
72 */
73
74static http_addr_t current_addr; /* Current address */
745129be
MS
75static int current_state = -1;
76 /* Current device state bits */
68b10830 77static int charset = -1; /* Character set for supply names */
c8fef167 78static int num_supplies = 0;
568fa3fa
MS
79 /* Number of supplies found */
80static backend_supplies_t supplies[CUPS_MAX_SUPPLIES];
81 /* Supply information */
c8fef167
MS
82static int supply_state = -1;
83 /* Supply state info */
568fa3fa
MS
84
85static const int hrDeviceDescr[] =
86 { CUPS_OID_hrDeviceDescr, 1, -1 };
87 /* Device description OID */
88static const int hrPrinterStatus[] =
89 { CUPS_OID_hrPrinterStatus, 1, -1 };
90 /* Current state OID */
91static const int hrPrinterDetectedErrorState[] =
92 { CUPS_OID_hrPrinterDetectedErrorState, 1, -1 };
93 /* Current printer state bits OID */
68b10830
MS
94static const int prtGeneralCurrentLocalization[] =
95 { CUPS_OID_prtGeneralCurrentLocalization, 1, -1 };
96static const int prtLocalizationCharacterSet[] =
97 { CUPS_OID_prtLocalizationCharacterSet, 1, 1, -1 },
98 prtLocalizationCharacterSetOffset =
99 (sizeof(prtLocalizationCharacterSet) /
100 sizeof(prtLocalizationCharacterSet[0]));
568fa3fa
MS
101static 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 */
108static const int prtMarkerLifeCount[] =
109 { CUPS_OID_prtMarkerLifeCount, 1, 1, -1 };
110 /* Page counter OID */
111static const int prtMarkerSuppliesEntry[] =
112 { CUPS_OID_prtMarkerSuppliesEntry, -1 };
113 /* Supplies OID */
114static 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 */
121static 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 */
128static 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 */
135static 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 */
142static 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
745129be
MS
150static 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" },
c8fef167
MS
154 /* { CUPS_TC_lowToner, "toner-low-report" }, */ /* now use prtMarkerSupplies */
155 /* { CUPS_TC_noToner, "toner-empty-warning" }, */ /* now use prtMarkerSupplies */
745129be
MS
156 { CUPS_TC_doorOpen, "door-open-report" },
157 { CUPS_TC_jammed, "media-jam-warning" },
158 /* { CUPS_TC_offline, "offline-report" }, */ /* unreliable */
e07d4801 159 /* { CUPS_TC_serviceRequested | CUPS_TC_overduePreventMaint, "service-needed-warning" }, */ /* unreliable */
745129be
MS
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
c8fef167
MS
167static 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" },
c8fef167
MS
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
568fa3fa
MS
179
180/*
181 * Local functions...
182 */
183
184static void backend_init_supplies(int snmp_fd, http_addr_t *addr);
185static void backend_walk_cb(cups_snmp_t *packet, void *data);
68b10830
MS
186static void utf16_to_utf8(cups_utf8_t *dst, const unsigned char *src,
187 size_t srcsize, size_t dstsize, int le);
568fa3fa
MS
188
189
190/*
191 * 'backendSNMPSupplies()' - Get the current supplies for a device.
192 */
193
194int /* O - 0 on success, -1 on error */
195backendSNMPSupplies(
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)
7a14d768 204 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
68b10830
MS
205 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel,
206 CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
568fa3fa
MS
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 {
745129be 216 int i, /* Looping var */
c8fef167 217 percent, /* Percent full */
745129be 218 new_state, /* New state value */
c8fef167
MS
219 change_state, /* State change */
220 new_supply_state = 0; /* Supply state */
568fa3fa
MS
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 */
568fa3fa
MS
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 {
a4845881 232 if (supplies[i].max_capacity > 0 && supplies[i].level >= 0)
07ed0e9a
MS
233 percent = 100 * supplies[i].level / supplies[i].max_capacity;
234 else
235 percent = 50;
c8fef167 236
a4845881 237 if (percent <= 5)
c8fef167
MS
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 :
c8fef167
MS
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
568fa3fa
MS
279 if (i)
280 *ptr++ = ',';
281
a4845881 282 if (supplies[i].max_capacity > 0 && supplies[i].level >= 0)
c8fef167 283 sprintf(ptr, "%d", percent);
06d4e77b
MS
284 else
285 strcpy(ptr, "-1");
568fa3fa
MS
286 }
287
288 fprintf(stderr, "ATTR: marker-levels=%s\n", value);
289
c8fef167
MS
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
568fa3fa
MS
310 /*
311 * Get the current printer status bits...
312 */
313
7a14d768
MS
314 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
315 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
568fa3fa
MS
316 hrPrinterDetectedErrorState))
317 return (-1);
318
68b10830 319 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
568fa3fa
MS
320 packet.object_type != CUPS_ASN1_OCTET_STRING)
321 return (-1);
322
18ecb428
MS
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];
ef55b745
MS
326 else if (packet.object_value.string.num_bytes == 1)
327 new_state = (packet.object_value.string.bytes[0] << 8);
18ecb428
MS
328 else
329 new_state = 0;
568fa3fa 330
745129be
MS
331 if (current_state < 0)
332 change_state = 0xffff;
568fa3fa 333 else
745129be 334 change_state = current_state ^ new_state;
568fa3fa 335
c8fef167
MS
336 fprintf(stderr, "DEBUG: new_state=%x, change_state=%x\n", new_state,
337 change_state);
229681c1 338
745129be
MS
339 for (i = 0;
340 i < (int)(sizeof(printer_states) / sizeof(printer_states[0]));
341 i ++)
342 if (change_state & printer_states[i].bit)
229681c1 343 {
c8fef167
MS
344 fprintf(stderr, "STATE: %c%s\n",
345 (new_state & printer_states[i].bit) ? '+' : '-',
346 printer_states[i].keyword);
229681c1 347 }
568fa3fa 348
745129be 349 current_state = new_state;
568fa3fa
MS
350
351 /*
352 * Get the current printer state...
353 */
354
355 if (printer_state)
356 {
7a14d768
MS
357 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
358 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
568fa3fa
MS
359 hrPrinterStatus))
360 return (-1);
361
68b10830 362 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
568fa3fa
MS
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 {
7a14d768
MS
375 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
376 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
568fa3fa
MS
377 prtMarkerLifeCount))
378 return (-1);
379
68b10830 380 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
568fa3fa
MS
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
398static void
399backend_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 */
58dc1933
MS
416 ppd_file_t *ppd; /* PPD file for this queue */
417 ppd_attr_t *ppdattr; /* cupsSNMPSupplies attribute */
568fa3fa
MS
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
745129be
MS
461 current_addr = *addr;
462 current_state = -1;
463 num_supplies = -1;
68b10830 464 charset = -1;
568fa3fa
MS
465
466 memset(supplies, 0, sizeof(supplies));
467
58dc1933
MS
468 /*
469 * See if we should be getting supply levels via SNMP...
470 */
471
f14324a7
MS
472 if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL ||
473 ((ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL &&
88f9aafc 474 ppdattr->value && _cups_strcasecmp(ppdattr->value, "true")))
58dc1933
MS
475 {
476 ppdClose(ppd);
477 return;
478 }
479
480 ppdClose(ppd);
481
568fa3fa
MS
482 /*
483 * Get the device description...
484 */
485
7a14d768
MS
486 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
487 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
568fa3fa
MS
488 hrDeviceDescr))
489 return;
490
68b10830 491 if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
568fa3fa
MS
492 packet.object_type != CUPS_ASN1_OCTET_STRING)
493 {
494 strlcpy(description, "Unknown", sizeof(description));
495 num_supplies = 0;
496 }
497 else
d1c13e16
MS
498 strlcpy(description, (char *)packet.object_value.string.bytes,
499 sizeof(description));
568fa3fa 500
68b10830
MS
501 fprintf(stderr, "DEBUG2: hrDeviceDesc=\"%s\"\n", description);
502
568fa3fa
MS
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 *
68b10830 520 * 2 num_supplies charset
568fa3fa
MS
521 * device description
522 * supply structures...
523 */
524
525 if (cupsFileGets(cachefile, value, sizeof(value)))
526 {
68b10830 527 if (sscanf(value, "2 %d%d", &num_supplies, &charset) == 2 &&
568fa3fa
MS
528 num_supplies <= CUPS_MAX_SUPPLIES &&
529 cupsFileGets(cachefile, value, sizeof(value)))
530 {
568fa3fa
MS
531 if (!strcmp(description, value))
532 cupsFileRead(cachefile, (char *)supplies,
533 num_supplies * sizeof(backend_supplies_t));
534 else
68b10830 535 {
568fa3fa 536 num_supplies = -1;
68b10830
MS
537 charset = -1;
538 }
568fa3fa
MS
539 }
540 else
68b10830 541 {
568fa3fa 542 num_supplies = -1;
68b10830
MS
543 charset = -1;
544 }
568fa3fa
MS
545 }
546
547 cupsFileClose(cachefile);
548 }
549
550 /*
551 * If the cache information isn't correct, scan for supplies...
552 */
553
68b10830
MS
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
568fa3fa
MS
603 if (num_supplies < 0)
604 {
605 /*
606 * Walk the printer configuration information...
607 */
608
7a14d768 609 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
68b10830
MS
610 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry,
611 CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
568fa3fa
MS
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 {
68b10830 623 cupsFilePrintf(cachefile, "2 %d %d\n", num_supplies, charset);
568fa3fa
MS
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
7a14d768 643 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
68b10830
MS
644 _cupsSNMPDefaultCommunity(), prtMarkerColorantValue,
645 CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
568fa3fa
MS
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/*
68b10830 707 * 'backend_walk_cb()' - Interpret the supply value responses.
568fa3fa
MS
708 */
709
710static void
711backend_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
7a14d768 730 if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) &&
568fa3fa
MS
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,
d1c13e16 740 (char *)packet->object_value.string.bytes);
568fa3fa
MS
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 ++)
d1c13e16 746 if (!strcmp(colors[k][0], (char *)packet->object_value.string.bytes))
568fa3fa
MS
747 {
748 strcpy(supplies[j].color, colors[k][1]);
749 break;
750 }
751 }
752 }
7a14d768 753 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
568fa3fa
MS
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 }
7a14d768 772 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription))
568fa3fa
MS
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
568fa3fa
MS
783 if (i > num_supplies)
784 num_supplies = i;
785
68b10830
MS
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
568fa3fa 861 }
7a14d768 862 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesLevel))
568fa3fa
MS
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 }
7a14d768 881 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity))
568fa3fa
MS
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 }
7a14d768 900 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
568fa3fa
MS
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
68b10830
MS
922/*
923 * 'utf16_to_utf8()' - Convert UTF-16 text to UTF-8.
924 */
925
926static void
927utf16_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
568fa3fa
MS
983/*
984 * End of "$Id$".
985 */