]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/snmp-supplies.c
Sync up with CUPS 1.6svn-r10269 (changes from Zin TOT merged into cups.org TOT)
[thirdparty/cups.git] / backend / snmp-supplies.c
CommitLineData
568fa3fa
MS
1/*
2 * "$Id$"
3 *
c8fef167 4 * SNMP supplies functions for CUPS.
568fa3fa 5 *
12f89d24 6 * Copyright 2008-2012 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 */
12f89d24 411 value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 4 + 3)],
568fa3fa
MS
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 /*
12f89d24
MS
662 * Output the marker-names attribute (the double quoting is necessary to deal
663 * with embedded quotes and commas in the marker names...)
568fa3fa
MS
664 */
665
666 for (i = 0, ptr = value; i < num_supplies; i ++)
667 {
668 if (i)
669 *ptr++ = ',';
670
12f89d24 671 *ptr++ = '\'';
568fa3fa
MS
672 *ptr++ = '\"';
673 for (name_ptr = supplies[i].name; *name_ptr;)
674 {
12f89d24
MS
675 if (*name_ptr == '\\' || *name_ptr == '\"' || *name_ptr == '\'')
676 {
677 *ptr++ = '\\';
678 *ptr++ = '\\';
568fa3fa 679 *ptr++ = '\\';
12f89d24 680 }
568fa3fa
MS
681
682 *ptr++ = *name_ptr++;
683 }
684 *ptr++ = '\"';
12f89d24 685 *ptr++ = '\'';
568fa3fa
MS
686 }
687
688 *ptr = '\0';
689
690 fprintf(stderr, "ATTR: marker-names=%s\n", value);
691
692 /*
693 * Output the marker-types attribute...
694 */
695
696 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
697 {
698 if (i)
699 *ptr++ = ',';
700
701 type = supplies[i].type;
702
703 if (type < CUPS_TC_other || type > CUPS_TC_covers)
704 strcpy(ptr, "unknown");
705 else
706 strcpy(ptr, types[type - CUPS_TC_other]);
707 }
708
709 fprintf(stderr, "ATTR: marker-types=%s\n", value);
710}
711
712
713/*
68b10830 714 * 'backend_walk_cb()' - Interpret the supply value responses.
568fa3fa
MS
715 */
716
717static void
718backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */
719 void *data) /* I - User data (unused) */
720{
721 int i, j, k; /* Looping vars */
12f89d24 722 static const char * const colors[][2] =
568fa3fa 723 { /* Standard color names */
12f89d24
MS
724 { "black", "#000000" },
725 { "blue", "#0000FF" },
726 { "brown", "#A52A2A" },
727 { "cyan", "#00FFFF" },
728 { "dark-gray", "#404040" },
729 { "dark gray", "#404040" },
730 { "dark-yellow", "#FFCC00" },
731 { "dark yellow", "#FFCC00" },
732 { "gold", "#FFD700" },
733 { "gray", "#808080" },
734 { "green", "#00FF00" },
735 { "light-black", "#606060" },
736 { "light black", "#606060" },
737 { "light-cyan", "#E0FFFF" },
738 { "light cyan", "#E0FFFF" },
739 { "light-gray", "#D3D3D3" },
740 { "light gray", "#D3D3D3" },
741 { "light-magenta", "#FF77FF" },
742 { "light magenta", "#FF77FF" },
743 { "magenta", "#FF00FF" },
744 { "orange", "#FFA500" },
745 { "red", "#FF0000" },
746 { "silver", "#C0C0C0" },
747 { "white", "#FFFFFF" },
748 { "yellow", "#FFFF00" }
568fa3fa
MS
749 };
750
751
752 (void)data;
753
7a14d768 754 if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) &&
568fa3fa
MS
755 packet->object_type == CUPS_ASN1_OCTET_STRING)
756 {
757 /*
758 * Get colorant...
759 */
760
761 i = packet->object_name[prtMarkerColorantValueOffset];
762
763 fprintf(stderr, "DEBUG2: prtMarkerColorantValue.1.%d = \"%s\"\n", i,
d1c13e16 764 (char *)packet->object_value.string.bytes);
568fa3fa
MS
765
766 for (j = 0; j < num_supplies; j ++)
767 if (supplies[j].colorant == i)
768 {
769 for (k = 0; k < (int)(sizeof(colors) / sizeof(colors[0])); k ++)
12f89d24
MS
770 if (!_cups_strcasecmp(colors[k][0],
771 (char *)packet->object_value.string.bytes))
568fa3fa
MS
772 {
773 strcpy(supplies[j].color, colors[k][1]);
774 break;
775 }
776 }
777 }
7a14d768 778 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
568fa3fa
MS
779 {
780 /*
781 * Get colorant index...
782 */
783
784 i = packet->object_name[prtMarkerSuppliesColorantIndexOffset];
785 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
786 packet->object_type != CUPS_ASN1_INTEGER)
787 return;
788
789 fprintf(stderr, "DEBUG2: prtMarkerSuppliesColorantIndex.1.%d = %d\n", i,
790 packet->object_value.integer);
791
792 if (i > num_supplies)
793 num_supplies = i;
794
795 supplies[i - 1].colorant = packet->object_value.integer;
796 }
7a14d768 797 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription))
568fa3fa
MS
798 {
799 /*
800 * Get supply name/description...
801 */
802
803 i = packet->object_name[prtMarkerSuppliesDescriptionOffset];
804 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
805 packet->object_type != CUPS_ASN1_OCTET_STRING)
806 return;
807
568fa3fa
MS
808 if (i > num_supplies)
809 num_supplies = i;
810
68b10830
MS
811 switch (charset)
812 {
813 case CUPS_TC_csASCII :
814 case CUPS_TC_csUTF8 :
815 case CUPS_TC_csUnicodeASCII :
816 strlcpy(supplies[i - 1].name,
817 (char *)packet->object_value.string.bytes,
818 sizeof(supplies[0].name));
819 break;
820
821 case CUPS_TC_csISOLatin1 :
822 case CUPS_TC_csUnicodeLatin1 :
823 cupsCharsetToUTF8((cups_utf8_t *)supplies[i - 1].name,
824 (char *)packet->object_value.string.bytes,
825 sizeof(supplies[0].name), CUPS_ISO8859_1);
826 break;
827
828 case CUPS_TC_csShiftJIS :
a2326b5b 829 case CUPS_TC_csWindows31J : /* Close enough for our purposes */
68b10830
MS
830 cupsCharsetToUTF8((cups_utf8_t *)supplies[i - 1].name,
831 (char *)packet->object_value.string.bytes,
832 sizeof(supplies[0].name), CUPS_JIS_X0213);
833 break;
834
835 case CUPS_TC_csUCS4 :
836 case CUPS_TC_csUTF32 :
837 case CUPS_TC_csUTF32BE :
838 case CUPS_TC_csUTF32LE :
839 cupsUTF32ToUTF8((cups_utf8_t *)supplies[i - 1].name,
840 (cups_utf32_t *)packet->object_value.string.bytes,
841 sizeof(supplies[0].name));
842 break;
843
844 case CUPS_TC_csUnicode :
845 case CUPS_TC_csUTF16BE :
846 case CUPS_TC_csUTF16LE :
847 utf16_to_utf8((cups_utf8_t *)supplies[i - 1].name,
848 packet->object_value.string.bytes,
849 packet->object_value.string.num_bytes,
850 sizeof(supplies[0].name), charset == CUPS_TC_csUTF16LE);
851 break;
852
853 default :
854 /*
855 * If we get here, the printer is using an unknown character set and
856 * we just want to copy characters that look like ASCII...
857 */
858
859 {
860 char *src, *dst; /* Pointers into strings */
861
68b10830
MS
862 /*
863 * Loop safe because both the object_value and supplies char arrays
864 * are CUPS_SNMP_MAX_STRING elements long.
865 */
866
867 for (src = (char *)packet->object_value.string.bytes,
868 dst = supplies[i - 1].name;
869 *src;
870 src ++)
871 {
872 if ((*src & 0x80) || *src < ' ' || *src == 0x7f)
873 *dst++ = '?';
874 else
875 *dst++ = *src;
876 }
877
878 *dst = '\0';
879 }
880 break;
881 }
882
883 fprintf(stderr, "DEBUG2: prtMarkerSuppliesDescription.1.%d = \"%s\"\n", i,
884 supplies[i - 1].name);
885
568fa3fa 886 }
7a14d768 887 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesLevel))
568fa3fa
MS
888 {
889 /*
890 * Get level...
891 */
892
893 i = packet->object_name[prtMarkerSuppliesLevelOffset];
894 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
895 packet->object_type != CUPS_ASN1_INTEGER)
896 return;
897
898 fprintf(stderr, "DEBUG2: prtMarkerSuppliesLevel.1.%d = %d\n", i,
899 packet->object_value.integer);
900
901 if (i > num_supplies)
902 num_supplies = i;
903
904 supplies[i - 1].level = packet->object_value.integer;
905 }
7a14d768 906 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity))
568fa3fa
MS
907 {
908 /*
909 * Get max capacity...
910 */
911
912 i = packet->object_name[prtMarkerSuppliesMaxCapacityOffset];
913 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
914 packet->object_type != CUPS_ASN1_INTEGER)
915 return;
916
917 fprintf(stderr, "DEBUG2: prtMarkerSuppliesMaxCapacity.1.%d = %d\n", i,
918 packet->object_value.integer);
919
920 if (i > num_supplies)
921 num_supplies = i;
922
923 supplies[i - 1].max_capacity = packet->object_value.integer;
924 }
7a14d768 925 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
568fa3fa
MS
926 {
927 /*
928 * Get marker type...
929 */
930
931 i = packet->object_name[prtMarkerSuppliesTypeOffset];
932 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
933 packet->object_type != CUPS_ASN1_INTEGER)
934 return;
935
936 fprintf(stderr, "DEBUG2: prtMarkerSuppliesType.1.%d = %d\n", i,
937 packet->object_value.integer);
938
939 if (i > num_supplies)
940 num_supplies = i;
941
942 supplies[i - 1].type = packet->object_value.integer;
943 }
944}
945
946
68b10830
MS
947/*
948 * 'utf16_to_utf8()' - Convert UTF-16 text to UTF-8.
949 */
950
951static void
952utf16_to_utf8(
953 cups_utf8_t *dst, /* I - Destination buffer */
954 const unsigned char *src, /* I - Source string */
955 size_t srcsize, /* I - Size of source string */
956 size_t dstsize, /* I - Size of destination buffer */
957 int le) /* I - Source is little-endian? */
958{
959 cups_utf32_t ch, /* Current character */
960 temp[CUPS_SNMP_MAX_STRING],
961 /* UTF-32 string */
962 *ptr; /* Pointer into UTF-32 string */
963
964
965 for (ptr = temp; srcsize >= 2;)
966 {
967 if (le)
968 ch = src[0] | (src[1] << 8);
969 else
970 ch = (src[0] << 8) | src[1];
971
972 src += 2;
973 srcsize -= 2;
974
975 if (ch >= 0xd800 && ch <= 0xdbff && srcsize >= 2)
976 {
977 /*
978 * Multi-word UTF-16 char...
979 */
980
981 int lch; /* Lower word */
982
983
984 if (le)
985 lch = src[0] | (src[1] << 8);
986 else
987 lch = (src[0] << 8) | src[1];
988
989 if (lch >= 0xdc00 && lch <= 0xdfff)
990 {
991 src += 2;
992 srcsize -= 2;
993
994 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
995 }
996 }
997
998 if (ptr < (temp + CUPS_SNMP_MAX_STRING - 1))
999 *ptr++ = ch;
1000 }
1001
1002 *ptr = '\0';
1003
1004 cupsUTF32ToUTF8(dst, temp, dstsize);
1005}
1006
1007
568fa3fa
MS
1008/*
1009 * End of "$Id$".
1010 */