]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/snmp-supplies.c
Merge changes from CUPS 1.4svn-r7874.
[thirdparty/cups.git] / backend / snmp-supplies.c
1 /*
2 * "$Id$"
3 *
4 * SNMP supplies functions for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2008 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 */
22
23 /*
24 * Include necessary headers.
25 */
26
27 #include "backend-private.h"
28 #include <cups/array.h>
29
30
31 /*
32 * Local constants...
33 */
34
35 #define CUPS_MAX_SUPPLIES 32 /* Maximum number of supplies for a printer */
36
37
38 /*
39 * Local structures...
40 */
41
42 typedef struct
43 {
44 char name[CUPS_SNMP_MAX_STRING], /* Name of supply */
45 color[8]; /* Color: "#RRGGBB" or "none" */
46 int colorant, /* Colorant index */
47 type, /* Supply type */
48 max_capacity, /* Maximum capacity */
49 level; /* Current level value */
50 } backend_supplies_t;
51
52
53 /*
54 * Local globals...
55 */
56
57 static http_addr_t current_addr; /* Current address */
58 static int num_supplies = 0;
59 /* Number of supplies found */
60 static backend_supplies_t supplies[CUPS_MAX_SUPPLIES];
61 /* Supply information */
62
63 static const int hrDeviceDescr[] =
64 { CUPS_OID_hrDeviceDescr, 1, -1 };
65 /* Device description OID */
66 static const int hrPrinterStatus[] =
67 { CUPS_OID_hrPrinterStatus, 1, -1 };
68 /* Current state OID */
69 static const int hrPrinterDetectedErrorState[] =
70 { CUPS_OID_hrPrinterDetectedErrorState, 1, -1 };
71 /* Current printer state bits OID */
72 static const int prtMarkerColorantValue[] =
73 { CUPS_OID_prtMarkerColorantValue, -1 },
74 /* Colorant OID */
75 prtMarkerColorantValueOffset =
76 (sizeof(prtMarkerColorantValue) /
77 sizeof(prtMarkerColorantValue[0]));
78 /* Offset to colorant index */
79 static const int prtMarkerLifeCount[] =
80 { CUPS_OID_prtMarkerLifeCount, 1, 1, -1 };
81 /* Page counter OID */
82 static const int prtMarkerSuppliesEntry[] =
83 { CUPS_OID_prtMarkerSuppliesEntry, -1 };
84 /* Supplies OID */
85 static const int prtMarkerSuppliesColorantIndex[] =
86 { CUPS_OID_prtMarkerSuppliesColorantIndex, -1 },
87 /* Colorant index OID */
88 prtMarkerSuppliesColorantIndexOffset =
89 (sizeof(prtMarkerSuppliesColorantIndex) /
90 sizeof(prtMarkerSuppliesColorantIndex[0]));
91 /* Offset to supply index */
92 static const int prtMarkerSuppliesDescription[] =
93 { CUPS_OID_prtMarkerSuppliesDescription, -1 },
94 /* Description OID */
95 prtMarkerSuppliesDescriptionOffset =
96 (sizeof(prtMarkerSuppliesDescription) /
97 sizeof(prtMarkerSuppliesDescription[0]));
98 /* Offset to supply index */
99 static const int prtMarkerSuppliesLevel[] =
100 { CUPS_OID_prtMarkerSuppliesLevel, -1 },
101 /* Level OID */
102 prtMarkerSuppliesLevelOffset =
103 (sizeof(prtMarkerSuppliesLevel) /
104 sizeof(prtMarkerSuppliesLevel[0]));
105 /* Offset to supply index */
106 static const int prtMarkerSuppliesMaxCapacity[] =
107 { CUPS_OID_prtMarkerSuppliesMaxCapacity, -1 },
108 /* Max capacity OID */
109 prtMarkerSuppliesMaxCapacityOffset =
110 (sizeof(prtMarkerSuppliesMaxCapacity) /
111 sizeof(prtMarkerSuppliesMaxCapacity[0]));
112 /* Offset to supply index */
113 static const int prtMarkerSuppliesType[] =
114 { CUPS_OID_prtMarkerSuppliesType, -1 },
115 /* Type OID */
116 prtMarkerSuppliesTypeOffset =
117 (sizeof(prtMarkerSuppliesType) /
118 sizeof(prtMarkerSuppliesType[0]));
119 /* Offset to supply index */
120
121
122 /*
123 * Local functions...
124 */
125
126 static void backend_init_supplies(int snmp_fd, http_addr_t *addr);
127 static void backend_walk_cb(cups_snmp_t *packet, void *data);
128
129
130 /*
131 * 'backendSNMPSupplies()' - Get the current supplies for a device.
132 */
133
134 int /* O - 0 on success, -1 on error */
135 backendSNMPSupplies(
136 int snmp_fd, /* I - SNMP socket */
137 http_addr_t *addr, /* I - Printer address */
138 int *page_count, /* O - Page count */
139 int *printer_state) /* O - Printer state */
140 {
141 if (!httpAddrEqual(addr, &current_addr))
142 backend_init_supplies(snmp_fd, addr);
143 else if (num_supplies > 0)
144 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
145 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel, 0.5,
146 backend_walk_cb, NULL);
147
148 if (page_count)
149 *page_count = -1;
150
151 if (printer_state)
152 *printer_state = -1;
153
154 if (num_supplies > 0)
155 {
156 int i; /* Looping var */
157 char value[CUPS_MAX_SUPPLIES * 4],
158 /* marker-levels value string */
159 *ptr; /* Pointer into value string */
160 cups_snmp_t packet; /* SNMP response packet */
161
162
163 /*
164 * Generate the marker-levels value string...
165 */
166
167 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
168 {
169 if (i)
170 *ptr++ = ',';
171
172 if (supplies[i].max_capacity > 0)
173 sprintf(ptr, "%d", 100 * supplies[i].level / supplies[i].max_capacity);
174 else
175 strcpy(ptr, "-1");
176 }
177
178 fprintf(stderr, "ATTR: marker-levels=%s\n", value);
179
180 /*
181 * Get the current printer status bits...
182 */
183
184 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
185 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
186 hrPrinterDetectedErrorState))
187 return (-1);
188
189 if (!_cupsSNMPRead(snmp_fd, &packet, 0.5) ||
190 packet.object_type != CUPS_ASN1_OCTET_STRING)
191 return (-1);
192
193 i = ((packet.object_value.string[0] & 255) << 8) |
194 (packet.object_value.string[1] & 255);
195
196 if (i & CUPS_TC_lowPaper)
197 fputs("STATE: +media-low-warning\n", stderr);
198 else
199 fputs("STATE: -media-low-warning\n", stderr);
200
201 if (i & (CUPS_TC_noPaper | CUPS_TC_inputTrayEmpty))
202 fputs("STATE: +media-empty-error\n", stderr);
203 else
204 fputs("STATE: -media-empty-error\n", stderr);
205
206 if (i & CUPS_TC_lowToner)
207 fputs("STATE: +toner-low-warning\n", stderr);
208 else
209 fputs("STATE: -toner-low-warning\n", stderr);
210
211 if (i & CUPS_TC_noToner)
212 fputs("STATE: +toner-empty-error\n", stderr);
213 else
214 fputs("STATE: -toner-empty-error\n", stderr);
215
216 if (i & CUPS_TC_doorOpen)
217 fputs("STATE: +door-open-report\n", stderr);
218 else
219 fputs("STATE: -door-open-report\n", stderr);
220
221 if (i & CUPS_TC_jammed)
222 fputs("STATE: +media-jam-error\n", stderr);
223 else
224 fputs("STATE: -media-jam-error\n", stderr);
225
226 if (i & CUPS_TC_offline)
227 fputs("STATE: +offline-report\n", stderr);
228 else
229 fputs("STATE: -offline-report\n", stderr);
230
231 if (i & (CUPS_TC_serviceRequested | CUPS_TC_overduePreventMaint))
232 fputs("STATE: +service-needed-error\n", stderr);
233 else
234 fputs("STATE: -service-needed-error\n", stderr);
235
236 if (i & CUPS_TC_inputTrayMissing)
237 fputs("STATE: +input-tray-missing-error\n", stderr);
238 else
239 fputs("STATE: -input-tray-missing-error\n", stderr);
240
241 if (i & CUPS_TC_outputTrayMissing)
242 fputs("STATE: +output-tray-missing-error\n", stderr);
243 else
244 fputs("STATE: -output-tray-missing-error\n", stderr);
245
246 if (i & CUPS_TC_markerSupplyMissing)
247 fputs("STATE: +marker-supply-missing-error\n", stderr);
248 else
249 fputs("STATE: -marker-supply-missing-error\n", stderr);
250
251 if (i & CUPS_TC_outputNearFull)
252 fputs("STATE: +output-area-almost-full-warning\n", stderr);
253 else
254 fputs("STATE: -output-area-almost-full-warning\n", stderr);
255
256 if (i & CUPS_TC_outputFull)
257 fputs("STATE: +output-area-full-error\n", stderr);
258 else
259 fputs("STATE: -output-area-full-error\n", stderr);
260
261 /*
262 * Get the current printer state...
263 */
264
265 if (printer_state)
266 {
267 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
268 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
269 hrPrinterStatus))
270 return (-1);
271
272 if (!_cupsSNMPRead(snmp_fd, &packet, 0.5) ||
273 packet.object_type != CUPS_ASN1_INTEGER)
274 return (-1);
275
276 *printer_state = packet.object_value.integer;
277 }
278
279 /*
280 * Get the current page count...
281 */
282
283 if (page_count)
284 {
285 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
286 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
287 prtMarkerLifeCount))
288 return (-1);
289
290 if (!_cupsSNMPRead(snmp_fd, &packet, 0.5) ||
291 packet.object_type != CUPS_ASN1_COUNTER)
292 return (-1);
293
294 *page_count = packet.object_value.counter;
295 }
296
297 return (0);
298 }
299 else
300 return (-1);
301 }
302
303
304 /*
305 * 'backend_init_supplies()' - Initialize the supplies list.
306 */
307
308 static void
309 backend_init_supplies(
310 int snmp_fd, /* I - SNMP socket */
311 http_addr_t *addr) /* I - Printer address */
312 {
313 int i, /* Looping var */
314 type; /* Current marker type */
315 cups_file_t *cachefile; /* Cache file */
316 const char *cachedir; /* CUPS_CACHEDIR value */
317 char addrstr[1024], /* Address string */
318 cachefilename[1024], /* Cache filename */
319 description[CUPS_SNMP_MAX_STRING],
320 /* Device description string */
321 value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 2 + 3)],
322 /* Value string */
323 *ptr, /* Pointer into value string */
324 *name_ptr; /* Pointer into name string */
325 cups_snmp_t packet; /* SNMP response packet */
326 static const char * const types[] = /* Supply types */
327 {
328 "other",
329 "unknown",
330 "toner",
331 "wasteToner",
332 "ink",
333 "inkCartridge",
334 "inkRibbon",
335 "wasteInk",
336 "opc",
337 "developer",
338 "fuserOil",
339 "solidWax",
340 "ribbonWax",
341 "wasteWax",
342 "fuser",
343 "coronaWire",
344 "fuserOilWick",
345 "cleanerUnit",
346 "fuserCleaningPad",
347 "transferUnit",
348 "tonerCartridge",
349 "fuserOiler",
350 "water",
351 "wasteWater",
352 "glueWaterAdditive",
353 "wastePaper",
354 "bindingSupply",
355 "bandingSupply",
356 "stitchingWire",
357 "shrinkWrap",
358 "paperWrap",
359 "staples",
360 "inserts",
361 "covers"
362 };
363
364
365 /*
366 * Reset state information...
367 */
368
369 current_addr = *addr;
370 num_supplies = -1;
371
372 memset(supplies, 0, sizeof(supplies));
373
374 /*
375 * Get the device description...
376 */
377
378 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
379 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
380 hrDeviceDescr))
381 return;
382
383 if (!_cupsSNMPRead(snmp_fd, &packet, 0.5) ||
384 packet.object_type != CUPS_ASN1_OCTET_STRING)
385 {
386 strlcpy(description, "Unknown", sizeof(description));
387 num_supplies = 0;
388 }
389 else
390 strlcpy(description, packet.object_value.string, sizeof(description));
391
392 /*
393 * See if we have already queried this device...
394 */
395
396 httpAddrString(addr, addrstr, sizeof(addrstr));
397
398 if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL)
399 cachedir = CUPS_CACHEDIR;
400
401 snprintf(cachefilename, sizeof(cachefilename), "%s/%s.snmp", cachedir,
402 addrstr);
403
404 if ((cachefile = cupsFileOpen(cachefilename, "r")) != NULL)
405 {
406 /*
407 * Yes, read the cache file:
408 *
409 * 1 num_supplies
410 * device description
411 * supply structures...
412 */
413
414 if (cupsFileGets(cachefile, value, sizeof(value)))
415 {
416 if (sscanf(value, "1 %d", &num_supplies) == 1 &&
417 num_supplies <= CUPS_MAX_SUPPLIES &&
418 cupsFileGets(cachefile, value, sizeof(value)))
419 {
420 if ((ptr = value + strlen(value) - 1) >= value && *ptr == '\n')
421 *ptr = '\n';
422
423 if (!strcmp(description, value))
424 cupsFileRead(cachefile, (char *)supplies,
425 num_supplies * sizeof(backend_supplies_t));
426 else
427 num_supplies = -1;
428 }
429 else
430 num_supplies = -1;
431 }
432
433 cupsFileClose(cachefile);
434 }
435
436 /*
437 * If the cache information isn't correct, scan for supplies...
438 */
439
440 if (num_supplies < 0)
441 {
442 /*
443 * Walk the printer configuration information...
444 */
445
446 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
447 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry, 0.5,
448 backend_walk_cb, NULL);
449 }
450
451 /*
452 * Save the cached information...
453 */
454
455 if (num_supplies < 0)
456 num_supplies = 0;
457
458 if ((cachefile = cupsFileOpen(cachefilename, "w")) != NULL)
459 {
460 cupsFilePrintf(cachefile, "1 %d\n", num_supplies);
461 cupsFilePrintf(cachefile, "%s\n", description);
462
463 if (num_supplies > 0)
464 cupsFileWrite(cachefile, (char *)supplies,
465 num_supplies * sizeof(backend_supplies_t));
466
467 cupsFileClose(cachefile);
468 }
469
470 if (num_supplies <= 0)
471 return;
472
473 /*
474 * Get the colors...
475 */
476
477 for (i = 0; i < num_supplies; i ++)
478 strcpy(supplies[i].color, "none");
479
480 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
481 _cupsSNMPDefaultCommunity(), prtMarkerColorantValue, 0.5,
482 backend_walk_cb, NULL);
483
484 /*
485 * Output the marker-colors attribute...
486 */
487
488 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
489 {
490 if (i)
491 *ptr++ = ',';
492
493 strcpy(ptr, supplies[i].color);
494 }
495
496 fprintf(stderr, "ATTR: marker-colors=%s\n", value);
497
498 /*
499 * Output the marker-names attribute...
500 */
501
502 for (i = 0, ptr = value; i < num_supplies; i ++)
503 {
504 if (i)
505 *ptr++ = ',';
506
507 *ptr++ = '\"';
508 for (name_ptr = supplies[i].name; *name_ptr;)
509 {
510 if (*name_ptr == '\\' || *name_ptr == '\"')
511 *ptr++ = '\\';
512
513 *ptr++ = *name_ptr++;
514 }
515 *ptr++ = '\"';
516 }
517
518 *ptr = '\0';
519
520 fprintf(stderr, "ATTR: marker-names=%s\n", value);
521
522 /*
523 * Output the marker-types attribute...
524 */
525
526 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
527 {
528 if (i)
529 *ptr++ = ',';
530
531 type = supplies[i].type;
532
533 if (type < CUPS_TC_other || type > CUPS_TC_covers)
534 strcpy(ptr, "unknown");
535 else
536 strcpy(ptr, types[type - CUPS_TC_other]);
537 }
538
539 fprintf(stderr, "ATTR: marker-types=%s\n", value);
540 }
541
542
543 /*
544 * 'backend_walk_cb()' - Interpret the supply value responses...
545 */
546
547 static void
548 backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */
549 void *data) /* I - User data (unused) */
550 {
551 int i, j, k; /* Looping vars */
552 static const char * const colors[8][2] =
553 { /* Standard color names */
554 { "black", "#000000" },
555 { "blue", "#0000FF" },
556 { "cyan", "#00FFFF" },
557 { "green", "#00FF00" },
558 { "magenta", "#FF00FF" },
559 { "red", "#FF0000" },
560 { "white", "#FFFFFF" },
561 { "yellow", "#FFFF00" }
562 };
563
564
565 (void)data;
566
567 if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) &&
568 packet->object_type == CUPS_ASN1_OCTET_STRING)
569 {
570 /*
571 * Get colorant...
572 */
573
574 i = packet->object_name[prtMarkerColorantValueOffset];
575
576 fprintf(stderr, "DEBUG2: prtMarkerColorantValue.1.%d = \"%s\"\n", i,
577 packet->object_value.string);
578
579 for (j = 0; j < num_supplies; j ++)
580 if (supplies[j].colorant == i)
581 {
582 for (k = 0; k < (int)(sizeof(colors) / sizeof(colors[0])); k ++)
583 if (!strcmp(colors[k][0], packet->object_value.string))
584 {
585 strcpy(supplies[j].color, colors[k][1]);
586 break;
587 }
588 }
589 }
590 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
591 {
592 /*
593 * Get colorant index...
594 */
595
596 i = packet->object_name[prtMarkerSuppliesColorantIndexOffset];
597 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
598 packet->object_type != CUPS_ASN1_INTEGER)
599 return;
600
601 fprintf(stderr, "DEBUG2: prtMarkerSuppliesColorantIndex.1.%d = %d\n", i,
602 packet->object_value.integer);
603
604 if (i > num_supplies)
605 num_supplies = i;
606
607 supplies[i - 1].colorant = packet->object_value.integer;
608 }
609 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription))
610 {
611 /*
612 * Get supply name/description...
613 */
614
615 i = packet->object_name[prtMarkerSuppliesDescriptionOffset];
616 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
617 packet->object_type != CUPS_ASN1_OCTET_STRING)
618 return;
619
620 fprintf(stderr, "DEBUG2: prtMarkerSuppliesDescription.1.%d = \"%s\"\n", i,
621 packet->object_value.string);
622
623 if (i > num_supplies)
624 num_supplies = i;
625
626 strlcpy(supplies[i - 1].name, packet->object_value.string,
627 sizeof(supplies[0].name));
628 }
629 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesLevel))
630 {
631 /*
632 * Get level...
633 */
634
635 i = packet->object_name[prtMarkerSuppliesLevelOffset];
636 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
637 packet->object_type != CUPS_ASN1_INTEGER)
638 return;
639
640 fprintf(stderr, "DEBUG2: prtMarkerSuppliesLevel.1.%d = %d\n", i,
641 packet->object_value.integer);
642
643 if (i > num_supplies)
644 num_supplies = i;
645
646 supplies[i - 1].level = packet->object_value.integer;
647 }
648 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity))
649 {
650 /*
651 * Get max capacity...
652 */
653
654 i = packet->object_name[prtMarkerSuppliesMaxCapacityOffset];
655 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
656 packet->object_type != CUPS_ASN1_INTEGER)
657 return;
658
659 fprintf(stderr, "DEBUG2: prtMarkerSuppliesMaxCapacity.1.%d = %d\n", i,
660 packet->object_value.integer);
661
662 if (i > num_supplies)
663 num_supplies = i;
664
665 supplies[i - 1].max_capacity = packet->object_value.integer;
666 }
667 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
668 {
669 /*
670 * Get marker type...
671 */
672
673 i = packet->object_name[prtMarkerSuppliesTypeOffset];
674 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
675 packet->object_type != CUPS_ASN1_INTEGER)
676 return;
677
678 fprintf(stderr, "DEBUG2: prtMarkerSuppliesType.1.%d = %d\n", i,
679 packet->object_value.integer);
680
681 if (i > num_supplies)
682 num_supplies = i;
683
684 supplies[i - 1].type = packet->object_value.integer;
685 }
686 }
687
688
689 /*
690 * End of "$Id$".
691 */