Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
srohatgi01
GitHub Repository: srohatgi01/cups
Path: blob/master/backend/snmp-supplies.c
1090 views
1
/*
2
* SNMP supplies functions for CUPS.
3
*
4
* Copyright © 2008-2015 by Apple Inc.
5
*
6
* Licensed under Apache License v2.0. See the file "LICENSE" for more
7
* information.
8
*/
9
10
/*
11
* Include necessary headers.
12
*/
13
14
#include "backend-private.h"
15
#include <cups/ppd-private.h>
16
#include <cups/array.h>
17
18
19
/*
20
* Local constants...
21
*/
22
23
#define CUPS_MAX_SUPPLIES 32 /* Maximum number of supplies for a printer */
24
#define CUPS_SUPPLY_TIMEOUT 2.0 /* Timeout for SNMP lookups */
25
26
#define CUPS_DEVELOPER_LOW 0x0001
27
#define CUPS_DEVELOPER_EMPTY 0x0002
28
#define CUPS_MARKER_SUPPLY_LOW 0x0004
29
#define CUPS_MARKER_SUPPLY_EMPTY 0x0008
30
#define CUPS_OPC_NEAR_EOL 0x0010
31
#define CUPS_OPC_LIFE_OVER 0x0020
32
#define CUPS_TONER_LOW 0x0040
33
#define CUPS_TONER_EMPTY 0x0080
34
#define CUPS_WASTE_ALMOST_FULL 0x0100
35
#define CUPS_WASTE_FULL 0x0200
36
#define CUPS_CLEANER_NEAR_EOL 0x0400 /* Proposed JPS3 */
37
#define CUPS_CLEANER_LIFE_OVER 0x0800 /* Proposed JPS3 */
38
39
#define CUPS_SNMP_NONE 0x0000
40
#define CUPS_SNMP_CAPACITY 0x0001 /* Supply levels reported as percentages */
41
42
43
/*
44
* Local structures...
45
*/
46
47
typedef struct /**** Printer supply data ****/
48
{
49
char name[CUPS_SNMP_MAX_STRING], /* Name of supply */
50
color[8]; /* Color: "#RRGGBB" or "none" */
51
int colorant, /* Colorant index */
52
sclass, /* Supply class */
53
type, /* Supply type */
54
max_capacity, /* Maximum capacity */
55
level; /* Current level value */
56
} backend_supplies_t;
57
58
typedef struct /**** Printer state table ****/
59
{
60
int bit; /* State bit */
61
const char *keyword; /* IPP printer-state-reasons keyword */
62
} backend_state_t;
63
64
65
/*
66
* Local globals...
67
*/
68
69
static http_addr_t current_addr; /* Current address */
70
static int current_state = -1;
71
/* Current device state bits */
72
static int charset = -1; /* Character set for supply names */
73
static unsigned quirks = CUPS_SNMP_NONE;
74
/* Quirks we have to work around */
75
static int num_supplies = 0;
76
/* Number of supplies found */
77
static backend_supplies_t supplies[CUPS_MAX_SUPPLIES];
78
/* Supply information */
79
static int supply_state = -1;
80
/* Supply state info */
81
82
static const int hrDeviceDescr[] =
83
{ CUPS_OID_hrDeviceDescr, 1, -1 };
84
/* Device description OID */
85
static const int hrPrinterStatus[] =
86
{ CUPS_OID_hrPrinterStatus, 1, -1 };
87
/* Current state OID */
88
static const int hrPrinterDetectedErrorState[] =
89
{ CUPS_OID_hrPrinterDetectedErrorState, 1, -1 };
90
/* Current printer state bits OID */
91
static const int prtGeneralCurrentLocalization[] =
92
{ CUPS_OID_prtGeneralCurrentLocalization, 1, -1 };
93
static const int prtLocalizationCharacterSet[] =
94
{ CUPS_OID_prtLocalizationCharacterSet, 1, 1, -1 },
95
prtLocalizationCharacterSetOffset =
96
(sizeof(prtLocalizationCharacterSet) /
97
sizeof(prtLocalizationCharacterSet[0]));
98
static const int prtMarkerColorantValue[] =
99
{ CUPS_OID_prtMarkerColorantValue, -1 },
100
/* Colorant OID */
101
prtMarkerColorantValueOffset =
102
(sizeof(prtMarkerColorantValue) /
103
sizeof(prtMarkerColorantValue[0]));
104
/* Offset to colorant index */
105
static const int prtMarkerLifeCount[] =
106
{ CUPS_OID_prtMarkerLifeCount, 1, 1, -1 };
107
/* Page counter OID */
108
static const int prtMarkerSuppliesEntry[] =
109
{ CUPS_OID_prtMarkerSuppliesEntry, -1 };
110
/* Supplies OID */
111
static const int prtMarkerSuppliesColorantIndex[] =
112
{ CUPS_OID_prtMarkerSuppliesColorantIndex, -1 },
113
/* Colorant index OID */
114
prtMarkerSuppliesColorantIndexOffset =
115
(sizeof(prtMarkerSuppliesColorantIndex) /
116
sizeof(prtMarkerSuppliesColorantIndex[0]));
117
/* Offset to supply index */
118
static const int prtMarkerSuppliesDescription[] =
119
{ CUPS_OID_prtMarkerSuppliesDescription, -1 },
120
/* Description OID */
121
prtMarkerSuppliesDescriptionOffset =
122
(sizeof(prtMarkerSuppliesDescription) /
123
sizeof(prtMarkerSuppliesDescription[0]));
124
/* Offset to supply index */
125
static const int prtMarkerSuppliesLevel[] =
126
{ CUPS_OID_prtMarkerSuppliesLevel, -1 },
127
/* Level OID */
128
prtMarkerSuppliesLevelOffset =
129
(sizeof(prtMarkerSuppliesLevel) /
130
sizeof(prtMarkerSuppliesLevel[0]));
131
/* Offset to supply index */
132
static const int prtMarkerSuppliesMaxCapacity[] =
133
{ CUPS_OID_prtMarkerSuppliesMaxCapacity, -1 },
134
/* Max capacity OID */
135
prtMarkerSuppliesMaxCapacityOffset =
136
(sizeof(prtMarkerSuppliesMaxCapacity) /
137
sizeof(prtMarkerSuppliesMaxCapacity[0]));
138
/* Offset to supply index */
139
static const int prtMarkerSuppliesClass[] =
140
{ CUPS_OID_prtMarkerSuppliesClass, -1 },
141
/* Class OID */
142
prtMarkerSuppliesClassOffset =
143
(sizeof(prtMarkerSuppliesClass) /
144
sizeof(prtMarkerSuppliesClass[0]));
145
/* Offset to supply index */
146
static const int prtMarkerSuppliesType[] =
147
{ CUPS_OID_prtMarkerSuppliesType, -1 },
148
/* Type OID */
149
prtMarkerSuppliesTypeOffset =
150
(sizeof(prtMarkerSuppliesType) /
151
sizeof(prtMarkerSuppliesType[0]));
152
/* Offset to supply index */
153
static const int prtMarkerSuppliesSupplyUnit[] =
154
{ CUPS_OID_prtMarkerSuppliesSupplyUnit, -1 },
155
/* Units OID */
156
prtMarkerSuppliesSupplyUnitOffset =
157
(sizeof(prtMarkerSuppliesSupplyUnit) /
158
sizeof(prtMarkerSuppliesSupplyUnit[0]));
159
/* Offset to supply index */
160
161
static const backend_state_t printer_states[] =
162
{
163
/* { CUPS_TC_lowPaper, "media-low-report" }, */
164
{ CUPS_TC_noPaper | CUPS_TC_inputTrayEmpty, "media-empty-warning" },
165
/* { CUPS_TC_lowToner, "toner-low-report" }, */ /* now use prtMarkerSupplies */
166
/* { CUPS_TC_noToner, "toner-empty-warning" }, */ /* now use prtMarkerSupplies */
167
{ CUPS_TC_doorOpen, "door-open-report" },
168
{ CUPS_TC_jammed, "media-jam-warning" },
169
/* { CUPS_TC_offline, "offline-report" }, */ /* unreliable */
170
/* { CUPS_TC_serviceRequested | CUPS_TC_overduePreventMaint, "service-needed-warning" }, */ /* unreliable */
171
{ CUPS_TC_inputTrayMissing, "input-tray-missing-warning" },
172
{ CUPS_TC_outputTrayMissing, "output-tray-missing-warning" },
173
{ CUPS_TC_markerSupplyMissing, "marker-supply-missing-warning" },
174
{ CUPS_TC_outputNearFull, "output-area-almost-full-report" },
175
{ CUPS_TC_outputFull, "output-area-full-warning" }
176
};
177
178
static const backend_state_t supply_states[] =
179
{
180
{ CUPS_DEVELOPER_LOW, "developer-low-report" },
181
{ CUPS_DEVELOPER_EMPTY, "developer-empty-warning" },
182
{ CUPS_MARKER_SUPPLY_LOW, "marker-supply-low-report" },
183
{ CUPS_MARKER_SUPPLY_EMPTY, "marker-supply-empty-warning" },
184
{ CUPS_OPC_NEAR_EOL, "opc-near-eol-report" },
185
{ CUPS_OPC_LIFE_OVER, "opc-life-over-warning" },
186
{ CUPS_TONER_LOW, "toner-low-report" },
187
{ CUPS_TONER_EMPTY, "toner-empty-warning" },
188
{ CUPS_WASTE_ALMOST_FULL, "waste-receptacle-almost-full-report" },
189
{ CUPS_WASTE_FULL, "waste-receptacle-full-warning" },
190
{ CUPS_CLEANER_NEAR_EOL, "cleaner-life-almost-over-report" },
191
{ CUPS_CLEANER_LIFE_OVER, "cleaner-life-over-warning" },
192
};
193
194
195
/*
196
* Local functions...
197
*/
198
199
static void backend_init_supplies(int snmp_fd, http_addr_t *addr);
200
static void backend_walk_cb(cups_snmp_t *packet, void *data);
201
static void utf16_to_utf8(cups_utf8_t *dst, const unsigned char *src,
202
size_t srcsize, size_t dstsize, int le);
203
204
205
/*
206
* 'backendSNMPSupplies()' - Get the current supplies for a device.
207
*/
208
209
int /* O - 0 on success, -1 on error */
210
backendSNMPSupplies(
211
int snmp_fd, /* I - SNMP socket */
212
http_addr_t *addr, /* I - Printer address */
213
int *page_count, /* O - Page count */
214
int *printer_state) /* O - Printer state */
215
{
216
if (!httpAddrEqual(addr, &current_addr))
217
backend_init_supplies(snmp_fd, addr);
218
else if (num_supplies > 0)
219
_cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
220
_cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel,
221
CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
222
223
if (page_count)
224
*page_count = -1;
225
226
if (printer_state)
227
*printer_state = -1;
228
229
if (num_supplies > 0)
230
{
231
int i, /* Looping var */
232
percent, /* Percent full */
233
new_state, /* New state value */
234
change_state, /* State change */
235
new_supply_state = 0; /* Supply state */
236
char value[CUPS_MAX_SUPPLIES * 4],
237
/* marker-levels value string */
238
*ptr; /* Pointer into value string */
239
cups_snmp_t packet; /* SNMP response packet */
240
241
/*
242
* Generate the marker-levels value string...
243
*/
244
245
for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
246
{
247
if (supplies[i].max_capacity > 0 && supplies[i].level >= 0)
248
percent = 100 * supplies[i].level / supplies[i].max_capacity;
249
else if (supplies[i].level >= 0 && supplies[i].level <= 100 &&
250
(quirks & CUPS_SNMP_CAPACITY))
251
percent = supplies[i].level;
252
else
253
percent = 50;
254
255
if (supplies[i].sclass == CUPS_TC_receptacleThatIsFilled)
256
percent = 100 - percent;
257
258
if (percent <= 5)
259
{
260
switch (supplies[i].type)
261
{
262
case CUPS_TC_toner :
263
case CUPS_TC_tonerCartridge :
264
if (percent <= 1)
265
new_supply_state |= CUPS_TONER_EMPTY;
266
else
267
new_supply_state |= CUPS_TONER_LOW;
268
break;
269
case CUPS_TC_ink :
270
case CUPS_TC_inkCartridge :
271
case CUPS_TC_inkRibbon :
272
case CUPS_TC_solidWax :
273
case CUPS_TC_ribbonWax :
274
if (percent <= 1)
275
new_supply_state |= CUPS_MARKER_SUPPLY_EMPTY;
276
else
277
new_supply_state |= CUPS_MARKER_SUPPLY_LOW;
278
break;
279
case CUPS_TC_developer :
280
if (percent <= 1)
281
new_supply_state |= CUPS_DEVELOPER_EMPTY;
282
else
283
new_supply_state |= CUPS_DEVELOPER_LOW;
284
break;
285
case CUPS_TC_coronaWire :
286
case CUPS_TC_fuser :
287
case CUPS_TC_opc :
288
case CUPS_TC_transferUnit :
289
if (percent <= 1)
290
new_supply_state |= CUPS_OPC_LIFE_OVER;
291
else
292
new_supply_state |= CUPS_OPC_NEAR_EOL;
293
break;
294
#if 0 /* Because no two vendors report waste containers the same, disable SNMP reporting of same */
295
case CUPS_TC_wasteInk :
296
case CUPS_TC_wastePaper :
297
case CUPS_TC_wasteToner :
298
case CUPS_TC_wasteWater :
299
case CUPS_TC_wasteWax :
300
if (percent <= 1)
301
new_supply_state |= CUPS_WASTE_FULL;
302
else
303
new_supply_state |= CUPS_WASTE_ALMOST_FULL;
304
break;
305
#endif /* 0 */
306
case CUPS_TC_cleanerUnit :
307
case CUPS_TC_fuserCleaningPad :
308
if (percent <= 1)
309
new_supply_state |= CUPS_CLEANER_LIFE_OVER;
310
else
311
new_supply_state |= CUPS_CLEANER_NEAR_EOL;
312
break;
313
}
314
}
315
316
if (i)
317
*ptr++ = ',';
318
319
if ((supplies[i].max_capacity > 0 || (quirks & CUPS_SNMP_CAPACITY)) &&
320
supplies[i].level >= 0)
321
snprintf(ptr, sizeof(value) - (size_t)(ptr - value), "%d", percent);
322
else
323
strlcpy(ptr, "-1", sizeof(value) - (size_t)(ptr - value));
324
}
325
326
fprintf(stderr, "ATTR: marker-levels=%s\n", value);
327
328
if (supply_state < 0)
329
change_state = 0xffff;
330
else
331
change_state = supply_state ^ new_supply_state;
332
333
fprintf(stderr, "DEBUG: new_supply_state=%x, change_state=%x\n",
334
new_supply_state, change_state);
335
336
for (i = 0;
337
i < (int)(sizeof(supply_states) / sizeof(supply_states[0]));
338
i ++)
339
if (change_state & supply_states[i].bit)
340
{
341
fprintf(stderr, "STATE: %c%s\n",
342
(new_supply_state & supply_states[i].bit) ? '+' : '-',
343
supply_states[i].keyword);
344
}
345
346
supply_state = new_supply_state;
347
348
/*
349
* Get the current printer status bits...
350
*/
351
352
if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
353
_cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
354
hrPrinterDetectedErrorState))
355
return (-1);
356
357
if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
358
packet.object_type != CUPS_ASN1_OCTET_STRING)
359
return (-1);
360
361
if (packet.object_value.string.num_bytes == 2)
362
new_state = (packet.object_value.string.bytes[0] << 8) |
363
packet.object_value.string.bytes[1];
364
else if (packet.object_value.string.num_bytes == 1)
365
new_state = (packet.object_value.string.bytes[0] << 8);
366
else
367
new_state = 0;
368
369
if (current_state < 0)
370
change_state = 0xffff;
371
else
372
change_state = current_state ^ new_state;
373
374
fprintf(stderr, "DEBUG: new_state=%x, change_state=%x\n", new_state,
375
change_state);
376
377
for (i = 0;
378
i < (int)(sizeof(printer_states) / sizeof(printer_states[0]));
379
i ++)
380
if (change_state & printer_states[i].bit)
381
{
382
fprintf(stderr, "STATE: %c%s\n",
383
(new_state & printer_states[i].bit) ? '+' : '-',
384
printer_states[i].keyword);
385
}
386
387
current_state = new_state;
388
389
/*
390
* Get the current printer state...
391
*/
392
393
if (printer_state)
394
{
395
if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
396
_cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
397
hrPrinterStatus))
398
return (-1);
399
400
if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
401
packet.object_type != CUPS_ASN1_INTEGER)
402
return (-1);
403
404
*printer_state = packet.object_value.integer;
405
}
406
407
/*
408
* Get the current page count...
409
*/
410
411
if (page_count)
412
{
413
if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
414
_cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1,
415
prtMarkerLifeCount))
416
return (-1);
417
418
if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
419
packet.object_type != CUPS_ASN1_COUNTER)
420
return (-1);
421
422
*page_count = packet.object_value.counter;
423
}
424
425
return (0);
426
}
427
else
428
return (-1);
429
}
430
431
432
/*
433
* 'backend_init_supplies()' - Initialize the supplies list.
434
*/
435
436
static void
437
backend_init_supplies(
438
int snmp_fd, /* I - SNMP socket */
439
http_addr_t *addr) /* I - Printer address */
440
{
441
int i, /* Looping var */
442
type; /* Current marker type */
443
const char *community; /* SNMP community name */
444
cups_file_t *cachefile; /* Cache file */
445
const char *cachedir; /* CUPS_CACHEDIR value */
446
char addrstr[1024], /* Address string */
447
cachefilename[1024], /* Cache filename */
448
description[CUPS_SNMP_MAX_STRING],
449
/* Device description string */
450
value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 4 + 3)],
451
/* Value string */
452
*ptr, /* Pointer into value string */
453
*name_ptr; /* Pointer into name string */
454
cups_snmp_t packet; /* SNMP response packet */
455
ppd_file_t *ppd; /* PPD file for this queue */
456
ppd_attr_t *ppdattr; /* cupsSNMPSupplies attribute */
457
static const char * const types[] = /* Supply types */
458
{
459
"other",
460
"unknown",
461
"toner",
462
"waste-toner",
463
"ink",
464
"ink-cartridge",
465
"ink-ribbon",
466
"waste-ink",
467
"opc",
468
"developer",
469
"fuser-oil",
470
"solid-wax",
471
"ribbon-wax",
472
"waste-wax",
473
"fuser",
474
"corona-wire",
475
"fuser-oil-wick",
476
"cleaner-unit",
477
"fuser-cleaning-pad",
478
"transfer-unit",
479
"toner-cartridge",
480
"fuser-oiler",
481
"water",
482
"waste-water",
483
"glue-water-additive",
484
"waste-paper",
485
"binding-supply",
486
"banding-supply",
487
"stitching-wire",
488
"shrink-wrap",
489
"paper-wrap",
490
"staples",
491
"inserts",
492
"covers"
493
};
494
495
496
/*
497
* Reset state information...
498
*/
499
500
current_addr = *addr;
501
current_state = -1;
502
num_supplies = -1;
503
charset = -1;
504
505
memset(supplies, 0, sizeof(supplies));
506
507
/*
508
* See if we should be getting supply levels via SNMP...
509
*/
510
511
community = _cupsSNMPDefaultCommunity();
512
if (!*community)
513
return;
514
515
if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL ||
516
((ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL &&
517
ppdattr->value && _cups_strcasecmp(ppdattr->value, "true")))
518
{
519
ppdClose(ppd);
520
return;
521
}
522
523
if ((ppdattr = ppdFindAttr(ppd, "cupsSNMPQuirks", NULL)) != NULL)
524
{
525
if (!_cups_strcasecmp(ppdattr->value, "capacity"))
526
quirks |= CUPS_SNMP_CAPACITY;
527
}
528
529
ppdClose(ppd);
530
531
/*
532
* Get the device description...
533
*/
534
535
if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
536
community, CUPS_ASN1_GET_REQUEST, 1,
537
hrDeviceDescr))
538
return;
539
540
if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
541
packet.object_type != CUPS_ASN1_OCTET_STRING)
542
{
543
strlcpy(description, "Unknown", sizeof(description));
544
num_supplies = 0;
545
}
546
else
547
strlcpy(description, (char *)packet.object_value.string.bytes,
548
sizeof(description));
549
550
fprintf(stderr, "DEBUG2: hrDeviceDesc=\"%s\"\n", description);
551
552
/*
553
* See if we have already queried this device...
554
*/
555
556
httpAddrString(addr, addrstr, sizeof(addrstr));
557
558
if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL)
559
cachedir = CUPS_CACHEDIR;
560
561
snprintf(cachefilename, sizeof(cachefilename), "%s/%s.snmp", cachedir,
562
addrstr);
563
564
if ((cachefile = cupsFileOpen(cachefilename, "r")) != NULL)
565
{
566
/*
567
* Yes, read the cache file:
568
*
569
* 3 num_supplies charset
570
* device description
571
* supply structures...
572
*/
573
574
if (cupsFileGets(cachefile, value, sizeof(value)))
575
{
576
if (sscanf(value, "3 %d%d", &num_supplies, &charset) == 2 &&
577
num_supplies <= CUPS_MAX_SUPPLIES &&
578
cupsFileGets(cachefile, value, sizeof(value)))
579
{
580
if (!strcmp(description, value))
581
cupsFileRead(cachefile, (char *)supplies,
582
(size_t)num_supplies * sizeof(backend_supplies_t));
583
else
584
{
585
num_supplies = -1;
586
charset = -1;
587
}
588
}
589
else
590
{
591
num_supplies = -1;
592
charset = -1;
593
}
594
}
595
596
cupsFileClose(cachefile);
597
}
598
599
/*
600
* If the cache information isn't correct, scan for supplies...
601
*/
602
603
if (charset < 0)
604
{
605
/*
606
* Get the configured character set...
607
*/
608
609
int oid[CUPS_SNMP_MAX_OID]; /* OID for character set */
610
611
612
if (!_cupsSNMPWrite(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
613
community, CUPS_ASN1_GET_REQUEST, 1,
614
prtGeneralCurrentLocalization))
615
return;
616
617
if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
618
packet.object_type != CUPS_ASN1_INTEGER)
619
{
620
fprintf(stderr,
621
"DEBUG: prtGeneralCurrentLocalization type is %x, expected %x!\n",
622
packet.object_type, CUPS_ASN1_INTEGER);
623
return;
624
}
625
626
fprintf(stderr, "DEBUG2: prtGeneralCurrentLocalization=%d\n",
627
packet.object_value.integer);
628
629
_cupsSNMPCopyOID(oid, prtLocalizationCharacterSet, CUPS_SNMP_MAX_OID);
630
oid[prtLocalizationCharacterSetOffset - 2] = packet.object_value.integer;
631
632
633
if (!_cupsSNMPWrite(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
634
community, CUPS_ASN1_GET_REQUEST, 1,
635
oid))
636
return;
637
638
if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) ||
639
packet.object_type != CUPS_ASN1_INTEGER)
640
{
641
fprintf(stderr,
642
"DEBUG: prtLocalizationCharacterSet type is %x, expected %x!\n",
643
packet.object_type, CUPS_ASN1_INTEGER);
644
return;
645
}
646
647
fprintf(stderr, "DEBUG2: prtLocalizationCharacterSet=%d\n",
648
packet.object_value.integer);
649
charset = packet.object_value.integer;
650
}
651
652
if (num_supplies < 0)
653
{
654
/*
655
* Walk the printer configuration information...
656
*/
657
658
_cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
659
community, prtMarkerSuppliesEntry,
660
CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
661
}
662
663
/*
664
* Save the cached information...
665
*/
666
667
if (num_supplies < 0)
668
num_supplies = 0;
669
670
if ((cachefile = cupsFileOpen(cachefilename, "w")) != NULL)
671
{
672
cupsFilePrintf(cachefile, "3 %d %d\n", num_supplies, charset);
673
cupsFilePrintf(cachefile, "%s\n", description);
674
675
if (num_supplies > 0)
676
cupsFileWrite(cachefile, (char *)supplies,
677
(size_t)num_supplies * sizeof(backend_supplies_t));
678
679
cupsFileClose(cachefile);
680
}
681
682
if (num_supplies <= 0)
683
return;
684
685
/*
686
* Get the colors...
687
*/
688
689
for (i = 0; i < num_supplies; i ++)
690
strlcpy(supplies[i].color, "none", sizeof(supplies[i].color));
691
692
_cupsSNMPWalk(snmp_fd, &current_addr, CUPS_SNMP_VERSION_1,
693
community, prtMarkerColorantValue,
694
CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL);
695
696
/*
697
* Output the marker-colors attribute...
698
*/
699
700
for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
701
{
702
if (i)
703
*ptr++ = ',';
704
705
strlcpy(ptr, supplies[i].color, sizeof(value) - (size_t)(ptr - value));
706
}
707
708
fprintf(stderr, "ATTR: marker-colors=%s\n", value);
709
710
/*
711
* Output the marker-names attribute (the double quoting is necessary to deal
712
* with embedded quotes and commas in the marker names...)
713
*/
714
715
for (i = 0, ptr = value; i < num_supplies; i ++)
716
{
717
if (i)
718
*ptr++ = ',';
719
720
*ptr++ = '\'';
721
*ptr++ = '\"';
722
for (name_ptr = supplies[i].name; *name_ptr;)
723
{
724
if (*name_ptr == '\\' || *name_ptr == '\"' || *name_ptr == '\'')
725
{
726
*ptr++ = '\\';
727
*ptr++ = '\\';
728
*ptr++ = '\\';
729
}
730
731
*ptr++ = *name_ptr++;
732
}
733
*ptr++ = '\"';
734
*ptr++ = '\'';
735
}
736
737
*ptr = '\0';
738
739
fprintf(stderr, "ATTR: marker-names=%s\n", value);
740
741
/*
742
* Output the marker-types attribute...
743
*/
744
745
for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr))
746
{
747
if (i)
748
*ptr++ = ',';
749
750
type = supplies[i].type;
751
752
if (type < CUPS_TC_other || type > CUPS_TC_covers)
753
strlcpy(ptr, "unknown", sizeof(value) - (size_t)(ptr - value));
754
else
755
strlcpy(ptr, types[type - CUPS_TC_other], sizeof(value) - (size_t)(ptr - value));
756
}
757
758
fprintf(stderr, "ATTR: marker-types=%s\n", value);
759
}
760
761
762
/*
763
* 'backend_walk_cb()' - Interpret the supply value responses.
764
*/
765
766
static void
767
backend_walk_cb(cups_snmp_t *packet, /* I - SNMP packet */
768
void *data) /* I - User data (unused) */
769
{
770
int i, j, k; /* Looping vars */
771
static const char * const colors[][2] =
772
{ /* Standard color names */
773
{ "black", "#000000" },
774
{ "blue", "#0000FF" },
775
{ "brown", "#A52A2A" },
776
{ "cyan", "#00FFFF" },
777
{ "dark-gray", "#404040" },
778
{ "dark gray", "#404040" },
779
{ "dark-yellow", "#FFCC00" },
780
{ "dark yellow", "#FFCC00" },
781
{ "gold", "#FFD700" },
782
{ "gray", "#808080" },
783
{ "green", "#00FF00" },
784
{ "light-black", "#606060" },
785
{ "light black", "#606060" },
786
{ "light-cyan", "#E0FFFF" },
787
{ "light cyan", "#E0FFFF" },
788
{ "light-gray", "#D3D3D3" },
789
{ "light gray", "#D3D3D3" },
790
{ "light-magenta", "#FF77FF" },
791
{ "light magenta", "#FF77FF" },
792
{ "magenta", "#FF00FF" },
793
{ "orange", "#FFA500" },
794
{ "red", "#FF0000" },
795
{ "silver", "#C0C0C0" },
796
{ "white", "#FFFFFF" },
797
{ "yellow", "#FFFF00" }
798
};
799
800
801
(void)data;
802
803
if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerColorantValue) &&
804
packet->object_type == CUPS_ASN1_OCTET_STRING)
805
{
806
/*
807
* Get colorant...
808
*/
809
810
i = packet->object_name[prtMarkerColorantValueOffset];
811
812
fprintf(stderr, "DEBUG2: prtMarkerColorantValue.1.%d = \"%s\"\n", i,
813
(char *)packet->object_value.string.bytes);
814
815
for (j = 0; j < num_supplies; j ++)
816
if (supplies[j].colorant == i)
817
{
818
for (k = 0; k < (int)(sizeof(colors) / sizeof(colors[0])); k ++)
819
if (!_cups_strcasecmp(colors[k][0],
820
(char *)packet->object_value.string.bytes))
821
{
822
strlcpy(supplies[j].color, colors[k][1], sizeof(supplies[j].color));
823
break;
824
}
825
}
826
}
827
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesColorantIndex))
828
{
829
/*
830
* Get colorant index...
831
*/
832
833
i = packet->object_name[prtMarkerSuppliesColorantIndexOffset];
834
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
835
packet->object_type != CUPS_ASN1_INTEGER)
836
return;
837
838
fprintf(stderr, "DEBUG2: prtMarkerSuppliesColorantIndex.1.%d = %d\n", i,
839
packet->object_value.integer);
840
841
if (i > num_supplies)
842
num_supplies = i;
843
844
supplies[i - 1].colorant = packet->object_value.integer;
845
}
846
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesDescription))
847
{
848
/*
849
* Get supply name/description...
850
*/
851
852
i = packet->object_name[prtMarkerSuppliesDescriptionOffset];
853
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
854
packet->object_type != CUPS_ASN1_OCTET_STRING)
855
return;
856
857
if (i > num_supplies)
858
num_supplies = i;
859
860
switch (charset)
861
{
862
case CUPS_TC_csASCII :
863
case CUPS_TC_csUTF8 :
864
case CUPS_TC_csUnicodeASCII :
865
strlcpy(supplies[i - 1].name,
866
(char *)packet->object_value.string.bytes,
867
sizeof(supplies[0].name));
868
break;
869
870
case CUPS_TC_csISOLatin1 :
871
case CUPS_TC_csUnicodeLatin1 :
872
cupsCharsetToUTF8((cups_utf8_t *)supplies[i - 1].name,
873
(char *)packet->object_value.string.bytes,
874
sizeof(supplies[0].name), CUPS_ISO8859_1);
875
break;
876
877
case CUPS_TC_csShiftJIS :
878
case CUPS_TC_csWindows31J : /* Close enough for our purposes */
879
cupsCharsetToUTF8((cups_utf8_t *)supplies[i - 1].name,
880
(char *)packet->object_value.string.bytes,
881
sizeof(supplies[0].name), CUPS_JIS_X0213);
882
break;
883
884
case CUPS_TC_csUCS4 :
885
case CUPS_TC_csUTF32 :
886
case CUPS_TC_csUTF32BE :
887
case CUPS_TC_csUTF32LE :
888
cupsUTF32ToUTF8((cups_utf8_t *)supplies[i - 1].name,
889
(cups_utf32_t *)packet->object_value.string.bytes,
890
sizeof(supplies[0].name));
891
break;
892
893
case CUPS_TC_csUnicode :
894
case CUPS_TC_csUTF16BE :
895
case CUPS_TC_csUTF16LE :
896
utf16_to_utf8((cups_utf8_t *)supplies[i - 1].name,
897
packet->object_value.string.bytes,
898
packet->object_value.string.num_bytes,
899
sizeof(supplies[0].name), charset == CUPS_TC_csUTF16LE);
900
break;
901
902
default :
903
/*
904
* If we get here, the printer is using an unknown character set and
905
* we just want to copy characters that look like ASCII...
906
*/
907
908
{
909
char *src, *dst; /* Pointers into strings */
910
911
/*
912
* Loop safe because both the object_value and supplies char arrays
913
* are CUPS_SNMP_MAX_STRING elements long.
914
*/
915
916
for (src = (char *)packet->object_value.string.bytes,
917
dst = supplies[i - 1].name;
918
*src;
919
src ++)
920
{
921
if ((*src & 0x80) || *src < ' ' || *src == 0x7f)
922
*dst++ = '?';
923
else
924
*dst++ = *src;
925
}
926
927
*dst = '\0';
928
}
929
break;
930
}
931
932
fprintf(stderr, "DEBUG2: prtMarkerSuppliesDescription.1.%d = \"%s\"\n", i,
933
supplies[i - 1].name);
934
935
}
936
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesLevel))
937
{
938
/*
939
* Get level...
940
*/
941
942
i = packet->object_name[prtMarkerSuppliesLevelOffset];
943
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
944
packet->object_type != CUPS_ASN1_INTEGER)
945
return;
946
947
fprintf(stderr, "DEBUG2: prtMarkerSuppliesLevel.1.%d = %d\n", i,
948
packet->object_value.integer);
949
950
if (i > num_supplies)
951
num_supplies = i;
952
953
supplies[i - 1].level = packet->object_value.integer;
954
}
955
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity) &&
956
!(quirks & CUPS_SNMP_CAPACITY))
957
{
958
/*
959
* Get max capacity...
960
*/
961
962
i = packet->object_name[prtMarkerSuppliesMaxCapacityOffset];
963
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
964
packet->object_type != CUPS_ASN1_INTEGER)
965
return;
966
967
fprintf(stderr, "DEBUG2: prtMarkerSuppliesMaxCapacity.1.%d = %d\n", i,
968
packet->object_value.integer);
969
970
if (i > num_supplies)
971
num_supplies = i;
972
973
if (supplies[i - 1].max_capacity == 0 &&
974
packet->object_value.integer > 0)
975
supplies[i - 1].max_capacity = packet->object_value.integer;
976
}
977
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesClass))
978
{
979
/*
980
* Get marker class...
981
*/
982
983
i = packet->object_name[prtMarkerSuppliesClassOffset];
984
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
985
packet->object_type != CUPS_ASN1_INTEGER)
986
return;
987
988
fprintf(stderr, "DEBUG2: prtMarkerSuppliesClass.1.%d = %d\n", i,
989
packet->object_value.integer);
990
991
if (i > num_supplies)
992
num_supplies = i;
993
994
supplies[i - 1].sclass = packet->object_value.integer;
995
}
996
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesType))
997
{
998
/*
999
* Get marker type...
1000
*/
1001
1002
i = packet->object_name[prtMarkerSuppliesTypeOffset];
1003
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
1004
packet->object_type != CUPS_ASN1_INTEGER)
1005
return;
1006
1007
fprintf(stderr, "DEBUG2: prtMarkerSuppliesType.1.%d = %d\n", i,
1008
packet->object_value.integer);
1009
1010
if (i > num_supplies)
1011
num_supplies = i;
1012
1013
supplies[i - 1].type = packet->object_value.integer;
1014
}
1015
else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesSupplyUnit))
1016
{
1017
/*
1018
* Get units for capacity...
1019
*/
1020
1021
i = packet->object_name[prtMarkerSuppliesSupplyUnitOffset];
1022
if (i < 1 || i > CUPS_MAX_SUPPLIES ||
1023
packet->object_type != CUPS_ASN1_INTEGER)
1024
return;
1025
1026
fprintf(stderr, "DEBUG2: prtMarkerSuppliesSupplyUnit.1.%d = %d\n", i,
1027
packet->object_value.integer);
1028
1029
if (i > num_supplies)
1030
num_supplies = i;
1031
1032
if (packet->object_value.integer == CUPS_TC_percent)
1033
supplies[i - 1].max_capacity = 100;
1034
}
1035
}
1036
1037
1038
/*
1039
* 'utf16_to_utf8()' - Convert UTF-16 text to UTF-8.
1040
*/
1041
1042
static void
1043
utf16_to_utf8(
1044
cups_utf8_t *dst, /* I - Destination buffer */
1045
const unsigned char *src, /* I - Source string */
1046
size_t srcsize, /* I - Size of source string */
1047
size_t dstsize, /* I - Size of destination buffer */
1048
int le) /* I - Source is little-endian? */
1049
{
1050
cups_utf32_t ch, /* Current character */
1051
temp[CUPS_SNMP_MAX_STRING],
1052
/* UTF-32 string */
1053
*ptr; /* Pointer into UTF-32 string */
1054
1055
1056
for (ptr = temp; srcsize >= 2;)
1057
{
1058
if (le)
1059
ch = (cups_utf32_t)(src[0] | (src[1] << 8));
1060
else
1061
ch = (cups_utf32_t)((src[0] << 8) | src[1]);
1062
1063
src += 2;
1064
srcsize -= 2;
1065
1066
if (ch >= 0xd800 && ch <= 0xdbff && srcsize >= 2)
1067
{
1068
/*
1069
* Multi-word UTF-16 char...
1070
*/
1071
1072
cups_utf32_t lch; /* Lower word */
1073
1074
1075
if (le)
1076
lch = (cups_utf32_t)(src[0] | (src[1] << 8));
1077
else
1078
lch = (cups_utf32_t)((src[0] << 8) | src[1]);
1079
1080
if (lch >= 0xdc00 && lch <= 0xdfff)
1081
{
1082
src += 2;
1083
srcsize -= 2;
1084
1085
ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
1086
}
1087
}
1088
1089
if (ptr < (temp + CUPS_SNMP_MAX_STRING - 1))
1090
*ptr++ = ch;
1091
}
1092
1093
*ptr = '\0';
1094
1095
cupsUTF32ToUTF8(dst, temp, (int)dstsize);
1096
}
1097
1098