]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/snmp-supplies.c
Merge changes from CUPS 1.4svn-r8033.
[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-report\n", stderr);
198 else
199 fputs("STATE: -media-low-report\n", stderr);
200
201 if (i & (CUPS_TC_noPaper | CUPS_TC_inputTrayEmpty))
202 fputs("STATE: +media-empty-warning\n", stderr);
203 else
204 fputs("STATE: -media-empty-warning\n", stderr);
205
206 if (i & CUPS_TC_lowToner)
207 fputs("STATE: +toner-low-report\n", stderr);
208 else
209 fputs("STATE: -toner-low-report\n", stderr);
210
211 if (i & CUPS_TC_noToner)
212 fputs("STATE: +toner-empty-warning\n", stderr);
213 else
214 fputs("STATE: -toner-empty-warning\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-warning\n", stderr);
223 else
224 fputs("STATE: -media-jam-warning\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-warning\n", stderr);
233 else
234 fputs("STATE: -service-needed-warning\n", stderr);
235
236 if (i & CUPS_TC_inputTrayMissing)
237 fputs("STATE: +input-tray-missing-warning\n", stderr);
238 else
239 fputs("STATE: -input-tray-missing-warning\n", stderr);
240
241 if (i & CUPS_TC_outputTrayMissing)
242 fputs("STATE: +output-tray-missing-warning\n", stderr);
243 else
244 fputs("STATE: -output-tray-missing-warning\n", stderr);
245
246 if (i & CUPS_TC_markerSupplyMissing)
247 fputs("STATE: +marker-supply-missing-warning\n", stderr);
248 else
249 fputs("STATE: -marker-supply-missing-warning\n", stderr);
250
251 if (i & CUPS_TC_outputNearFull)
252 fputs("STATE: +output-area-almost-full-report\n", stderr);
253 else
254 fputs("STATE: -output-area-almost-full-report\n", stderr);
255
256 if (i & CUPS_TC_outputFull)
257 fputs("STATE: +output-area-full-warning\n", stderr);
258 else
259 fputs("STATE: -output-area-full-warning\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 ppd_file_t *ppd; /* PPD file for this queue */
327 ppd_attr_t *ppdattr; /* cupsSNMPSupplies attribute */
328 static const char * const types[] = /* Supply types */
329 {
330 "other",
331 "unknown",
332 "toner",
333 "wasteToner",
334 "ink",
335 "inkCartridge",
336 "inkRibbon",
337 "wasteInk",
338 "opc",
339 "developer",
340 "fuserOil",
341 "solidWax",
342 "ribbonWax",
343 "wasteWax",
344 "fuser",
345 "coronaWire",
346 "fuserOilWick",
347 "cleanerUnit",
348 "fuserCleaningPad",
349 "transferUnit",
350 "tonerCartridge",
351 "fuserOiler",
352 "water",
353 "wasteWater",
354 "glueWaterAdditive",
355 "wastePaper",
356 "bindingSupply",
357 "bandingSupply",
358 "stitchingWire",
359 "shrinkWrap",
360 "paperWrap",
361 "staples",
362 "inserts",
363 "covers"
364 };
365
366
367 /*
368 * Reset state information...
369 */
370
371 current_addr = *addr;
372 num_supplies = -1;
373
374 memset(supplies, 0, sizeof(supplies));
375
376 /*
377 * See if we should be getting supply levels via SNMP...
378 */
379
380 if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL &&
381 (ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL &&
382 ppdattr->value && strcasecmp(ppdattr->value, "true"))
383 {
384 ppdClose(ppd);
385 return;
386 }
387
388 ppdClose(ppd);
389
390 /*
391 * Get the device description...
392 */
393
394 if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
395 _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
396 hrDeviceDescr))
397 return;
398
399 if (!_cupsSNMPRead(snmp_fd, &packet, 0.5) ||
400 packet.object_type != CUPS_ASN1_OCTET_STRING)
401 {
402 strlcpy(description, "Unknown", sizeof(description));
403 num_supplies = 0;
404 }
405 else
406 strlcpy(description, packet.object_value.string, sizeof(description));
407
408 /*
409 * See if we have already queried this device...
410 */
411
412 httpAddrString(addr, addrstr, sizeof(addrstr));
413
414 if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL)
415 cachedir = CUPS_CACHEDIR;
416
417 snprintf(cachefilename, sizeof(cachefilename), "%s/%s.snmp", cachedir,
418 addrstr);
419
420 if ((cachefile = cupsFileOpen(cachefilename, "r")) != NULL)
421 {
422 /*
423 * Yes, read the cache file:
424 *
425 * 1 num_supplies
426 * device description
427 * supply structures...
428 */
429
430 if (cupsFileGets(cachefile, value, sizeof(value)))
431 {
432 if (sscanf(value, "1 %d", &num_supplies) == 1 &&
433 num_supplies <= CUPS_MAX_SUPPLIES &&
434 cupsFileGets(cachefile, value, sizeof(value)))
435 {
436 if ((ptr = value + strlen(value) - 1) >= value && *ptr == '\n')
437 *ptr = '\n';
438
439 if (!strcmp(description, value))
440 cupsFileRead(cachefile, (char *)supplies,
441 num_supplies * sizeof(backend_supplies_t));
442 else
443 num_supplies = -1;
444 }
445 else
446 num_supplies = -1;
447 }
448
449 cupsFileClose(cachefile);
450 }
451
452 /*
453 * If the cache information isn't correct, scan for supplies...
454 */
455
456 if (num_supplies < 0)
457 {
458 /*
459 * Walk the printer configuration information...
460 */
461
462 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
463 _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry, 0.5,
464 backend_walk_cb, NULL);
465 }
466
467 /*
468 * Save the cached information...
469 */
470
471 if (num_supplies < 0)
472 num_supplies = 0;
473
474 if ((cachefile = cupsFileOpen(cachefilename, "w")) != NULL)
475 {
476 cupsFilePrintf(cachefile, "1 %d\n", num_supplies);
477 cupsFilePrintf(cachefile, "%s\n", description);
478
479 if (num_supplies > 0)
480 cupsFileWrite(cachefile, (char *)supplies,
481 num_supplies * sizeof(backend_supplies_t));
482
483 cupsFileClose(cachefile);
484 }
485
486 if (num_supplies <= 0)
487 return;
488
489 /*
490 * Get the colors...
491 */
492
493 for (i = 0; i < num_supplies; i ++)
494 strcpy(supplies[i].color, "none");
495
496 _cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
497 _cupsSNMPDefaultCommunity(), prtMarkerColorantValue, 0.5,
498 backend_walk_cb, NULL);
499
500 /*
501 * Output the marker-colors attribute...
502 */
503
504 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
505 {
506 if (i)
507 *ptr++ = ',';
508
509 strcpy(ptr, supplies[i].color);
510 }
511
512 fprintf(stderr, "ATTR: marker-colors=%s\n", value);
513
514 /*
515 * Output the marker-names attribute...
516 */
517
518 for (i = 0, ptr = value; i < num_supplies; i ++)
519 {
520 if (i)
521 *ptr++ = ',';
522
523 *ptr++ = '\"';
524 for (name_ptr = supplies[i].name; *name_ptr;)
525 {
526 if (*name_ptr == '\\' || *name_ptr == '\"')
527 *ptr++ = '\\';
528
529 *ptr++ = *name_ptr++;
530 }
531 *ptr++ = '\"';
532 }
533
534 *ptr = '\0';
535
536 fprintf(stderr, "ATTR: marker-names=%s\n", value);
537
538 /*
539 * Output the marker-types attribute...
540 */
541
542 for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
543 {
544 if (i)
545 *ptr++ = ',';
546
547 type = supplies[i].type;
548
549 if (type < CUPS_TC_other || type > CUPS_TC_covers)
550 strcpy(ptr, "unknown");
551 else
552 strcpy(ptr, types[type - CUPS_TC_other]);
553 }
554
555 fprintf(stderr, "ATTR: marker-types=%s\n", value);
556 }
557
558
559 /*
560 * 'backend_walk_cb()' - Interpret the supply value responses...
561 */
562
563 static void
564 backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */
565 void *data) /* I - User data (unused) */
566 {
567 int i, j, k; /* Looping vars */
568 static const char * const colors[8][2] =
569 { /* Standard color names */
570 { "black", "#000000" },
571 { "blue", "#0000FF" },
572 { "cyan", "#00FFFF" },
573 { "green", "#00FF00" },
574 { "magenta", "#FF00FF" },
575 { "red", "#FF0000" },
576 { "white", "#FFFFFF" },
577 { "yellow", "#FFFF00" }
578 };
579
580
581 (void)data;
582
583 if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) &&
584 packet->object_type == CUPS_ASN1_OCTET_STRING)
585 {
586 /*
587 * Get colorant...
588 */
589
590 i = packet->object_name[prtMarkerColorantValueOffset];
591
592 fprintf(stderr, "DEBUG2: prtMarkerColorantValue.1.%d = \"%s\"\n", i,
593 packet->object_value.string);
594
595 for (j = 0; j < num_supplies; j ++)
596 if (supplies[j].colorant == i)
597 {
598 for (k = 0; k < (int)(sizeof(colors) / sizeof(colors[0])); k ++)
599 if (!strcmp(colors[k][0], packet->object_value.string))
600 {
601 strcpy(supplies[j].color, colors[k][1]);
602 break;
603 }
604 }
605 }
606 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
607 {
608 /*
609 * Get colorant index...
610 */
611
612 i = packet->object_name[prtMarkerSuppliesColorantIndexOffset];
613 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
614 packet->object_type != CUPS_ASN1_INTEGER)
615 return;
616
617 fprintf(stderr, "DEBUG2: prtMarkerSuppliesColorantIndex.1.%d = %d\n", i,
618 packet->object_value.integer);
619
620 if (i > num_supplies)
621 num_supplies = i;
622
623 supplies[i - 1].colorant = packet->object_value.integer;
624 }
625 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription))
626 {
627 /*
628 * Get supply name/description...
629 */
630
631 i = packet->object_name[prtMarkerSuppliesDescriptionOffset];
632 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
633 packet->object_type != CUPS_ASN1_OCTET_STRING)
634 return;
635
636 fprintf(stderr, "DEBUG2: prtMarkerSuppliesDescription.1.%d = \"%s\"\n", i,
637 packet->object_value.string);
638
639 if (i > num_supplies)
640 num_supplies = i;
641
642 strlcpy(supplies[i - 1].name, packet->object_value.string,
643 sizeof(supplies[0].name));
644 }
645 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesLevel))
646 {
647 /*
648 * Get level...
649 */
650
651 i = packet->object_name[prtMarkerSuppliesLevelOffset];
652 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
653 packet->object_type != CUPS_ASN1_INTEGER)
654 return;
655
656 fprintf(stderr, "DEBUG2: prtMarkerSuppliesLevel.1.%d = %d\n", i,
657 packet->object_value.integer);
658
659 if (i > num_supplies)
660 num_supplies = i;
661
662 supplies[i - 1].level = packet->object_value.integer;
663 }
664 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity))
665 {
666 /*
667 * Get max capacity...
668 */
669
670 i = packet->object_name[prtMarkerSuppliesMaxCapacityOffset];
671 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
672 packet->object_type != CUPS_ASN1_INTEGER)
673 return;
674
675 fprintf(stderr, "DEBUG2: prtMarkerSuppliesMaxCapacity.1.%d = %d\n", i,
676 packet->object_value.integer);
677
678 if (i > num_supplies)
679 num_supplies = i;
680
681 supplies[i - 1].max_capacity = packet->object_value.integer;
682 }
683 else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
684 {
685 /*
686 * Get marker type...
687 */
688
689 i = packet->object_name[prtMarkerSuppliesTypeOffset];
690 if (i < 1 || i > CUPS_MAX_SUPPLIES ||
691 packet->object_type != CUPS_ASN1_INTEGER)
692 return;
693
694 fprintf(stderr, "DEBUG2: prtMarkerSuppliesType.1.%d = %d\n", i,
695 packet->object_value.integer);
696
697 if (i > num_supplies)
698 num_supplies = i;
699
700 supplies[i - 1].type = packet->object_value.integer;
701 }
702 }
703
704
705 /*
706 * End of "$Id$".
707 */