int /* O - -1 on error, 0 on success */ backendNetworkSideCB( int print_fd, /* I - Print file or -1 */ int device_fd, /* I - Device file or -1 */ int snmp_fd, /* I - SNMP socket */ http_addr_t *addr, /* I - Address of device */ int use_bc) /* I - Use back-channel data? */ { cups_sc_command_t command; /* Request command */ cups_sc_status_t status; /* Request/response status */ char data[65536]; /* Request/response data */ int datalen; /* Request/response data size */ const char *device_id; /* 1284DEVICEID env var */ datalen = sizeof(data); if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) return (-1); switch (command) { case CUPS_SC_CMD_DRAIN_OUTPUT : /* * Our sockets disable the Nagle algorithm and data is sent immediately. */ if (device_fd < 0) status = CUPS_SC_STATUS_NOT_IMPLEMENTED; else if (backendDrainOutput(print_fd, device_fd)) status = CUPS_SC_STATUS_IO_ERROR; else status = CUPS_SC_STATUS_OK; datalen = 0; break; case CUPS_SC_CMD_GET_BIDI : status = CUPS_SC_STATUS_OK; data[0] = (char)use_bc; datalen = 1; break; case CUPS_SC_CMD_SNMP_GET : case CUPS_SC_CMD_SNMP_GET_NEXT : fprintf(stderr, "DEBUG: CUPS_SC_CMD_SNMP_%s: %d (%s)\n", command == CUPS_SC_CMD_SNMP_GET ? "GET" : "GET_NEXT", datalen, data); if (datalen < 2) { status = CUPS_SC_STATUS_BAD_MESSAGE; datalen = 0; break; } if (snmp_fd >= 0) { char *dataptr; /* Pointer into data */ cups_snmp_t packet; /* Packet from printer */ const char *snmp_value; /* CUPS_SNMP_VALUE env var */ if ((snmp_value = getenv("CUPS_SNMP_VALUE")) != NULL) { const char *snmp_count; /* CUPS_SNMP_COUNT env var */ int count; /* Repetition count */ if ((snmp_count = getenv("CUPS_SNMP_COUNT")) != NULL) { if ((count = atoi(snmp_count)) <= 0) count = 1; } else count = 1; for (dataptr = data + strlen(data) + 1; count > 0 && dataptr < (data + sizeof(data) - 1); count --, dataptr += strlen(dataptr)) strlcpy(dataptr, snmp_value, sizeof(data) - (size_t)(dataptr - data)); fprintf(stderr, "DEBUG: Returning %s %s\n", data, data + strlen(data) + 1); status = CUPS_SC_STATUS_OK; datalen = (int)(dataptr - data); break; } if (!_cupsSNMPStringToOID(data, packet.object_name, CUPS_SNMP_MAX_OID)) { status = CUPS_SC_STATUS_BAD_MESSAGE; datalen = 0; break; } status = CUPS_SC_STATUS_IO_ERROR; datalen = 0; if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), command == CUPS_SC_CMD_SNMP_GET ? CUPS_ASN1_GET_REQUEST : CUPS_ASN1_GET_NEXT_REQUEST, 1, packet.object_name)) { if (_cupsSNMPRead(snmp_fd, &packet, 1.0)) { size_t i; /* Looping var */ if (!_cupsSNMPOIDToString(packet.object_name, data, sizeof(data))) { fputs("DEBUG: Bad OID returned!\n", stderr); break; } datalen = (int)strlen(data) + 1; dataptr = data + datalen; switch (packet.object_type) { case CUPS_ASN1_BOOLEAN : snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%d", packet.object_value.boolean); datalen += (int)strlen(dataptr); break; case CUPS_ASN1_INTEGER : snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%d", packet.object_value.integer); datalen += (int)strlen(dataptr); break; case CUPS_ASN1_BIT_STRING : case CUPS_ASN1_OCTET_STRING : if (packet.object_value.string.num_bytes < (sizeof(data) - (size_t)(dataptr - data))) i = packet.object_value.string.num_bytes; else i = sizeof(data) - (size_t)(dataptr - data); memcpy(dataptr, packet.object_value.string.bytes, i); datalen += (int)i; break; case CUPS_ASN1_OID : _cupsSNMPOIDToString(packet.object_value.oid, dataptr, sizeof(data) - (size_t)(dataptr - data)); datalen += (int)strlen(dataptr); break; case CUPS_ASN1_HEX_STRING : for (i = 0; i < packet.object_value.string.num_bytes && dataptr < (data + sizeof(data) - 3); i ++, dataptr += 2) sprintf(dataptr, "%02X", packet.object_value.string.bytes[i]); datalen += (int)strlen(dataptr); break; case CUPS_ASN1_COUNTER : snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.counter); datalen += (int)strlen(dataptr); break; case CUPS_ASN1_GAUGE : snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.gauge); datalen += (int)strlen(dataptr); break; case CUPS_ASN1_TIMETICKS : snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.timeticks); datalen += (int)strlen(dataptr); break; default : fprintf(stderr, "DEBUG: Unknown OID value type %02X.\n", packet.object_type); case CUPS_ASN1_NULL_VALUE : dataptr[0] = '\0'; break; } fprintf(stderr, "DEBUG: Returning %s %s\n", data, data + datalen); status = CUPS_SC_STATUS_OK; } else fputs("DEBUG: SNMP read error...\n", stderr); } else fputs("DEBUG: SNMP write error...\n", stderr); break; } status = CUPS_SC_STATUS_NOT_IMPLEMENTED; datalen = 0; break; case CUPS_SC_CMD_GET_CONNECTED : status = CUPS_SC_STATUS_OK; data[0] = device_fd != -1; datalen = 1; break; case CUPS_SC_CMD_GET_DEVICE_ID : if (snmp_fd >= 0) { cups_snmp_t packet; /* Packet from printer */ static const int ppmPrinterIEEE1284DeviceId[] = { CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 }; status = CUPS_SC_STATUS_IO_ERROR; datalen = 0; if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, ppmPrinterIEEE1284DeviceId)) { if (_cupsSNMPRead(snmp_fd, &packet, 1.0) && packet.object_type == CUPS_ASN1_OCTET_STRING) { strlcpy(data, (char *)packet.object_value.string.bytes, sizeof(data)); datalen = (int)strlen(data); status = CUPS_SC_STATUS_OK; } } break; } if ((device_id = getenv("1284DEVICEID")) != NULL) { strlcpy(data, device_id, sizeof(data)); datalen = (int)strlen(data); status = CUPS_SC_STATUS_OK; break; } default : status = CUPS_SC_STATUS_NOT_IMPLEMENTED; datalen = 0; break; } return (cupsSideChannelWrite(command, status, data, datalen, 1.0)); }
static void backend_init_supplies( int snmp_fd, /* I - SNMP socket */ http_addr_t *addr) /* I - Printer address */ { int i, /* Looping var */ type; /* Current marker type */ cups_file_t *cachefile; /* Cache file */ const char *cachedir; /* CUPS_CACHEDIR value */ char addrstr[1024], /* Address string */ cachefilename[1024], /* Cache filename */ description[CUPS_SNMP_MAX_STRING], /* Device description string */ value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 4 + 3)], /* Value string */ *ptr, /* Pointer into value string */ *name_ptr; /* Pointer into name string */ cups_snmp_t packet; /* SNMP response packet */ ppd_file_t *ppd; /* PPD file for this queue */ ppd_attr_t *ppdattr; /* cupsSNMPSupplies attribute */ static const char * const types[] = /* Supply types */ { "other", "unknown", "toner", "waste-toner", "ink", "ink-cartridge", "ink-ribbon", "waste-ink", "opc", "developer", "fuser-oil", "solid-wax", "ribbon-wax", "waste-wax", "fuser", "corona-wire", "fuser-oil-wick", "cleaner-unit", "fuser-cleaning-pad", "transfer-unit", "toner-cartridge", "fuser-oiler", "water", "waste-water", "glue-water-additive", "waste-paper", "binding-supply", "banding-supply", "stitching-wire", "shrink-wrap", "paper-wrap", "staples", "inserts", "covers" }; /* * Reset state information... */ current_addr = *addr; current_state = -1; num_supplies = -1; charset = -1; memset(supplies, 0, sizeof(supplies)); /* * See if we should be getting supply levels via SNMP... */ if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL || ((ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL && ppdattr->value && _cups_strcasecmp(ppdattr->value, "true"))) { ppdClose(ppd); return; } if ((ppdattr = ppdFindAttr(ppd, "cupsSNMPQuirks", NULL)) != NULL) { if (!_cups_strcasecmp(ppdattr->value, "capacity")) quirks |= CUPS_SNMP_CAPACITY; } ppdClose(ppd); /* * Get the device description... */ if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, hrDeviceDescr)) return; if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) || packet.object_type != CUPS_ASN1_OCTET_STRING) { strlcpy(description, "Unknown", sizeof(description)); num_supplies = 0; } else strlcpy(description, (char *)packet.object_value.string.bytes, sizeof(description)); fprintf(stderr, "DEBUG2: hrDeviceDesc=\"%s\"\n", description); /* * See if we have already queried this device... */ httpAddrString(addr, addrstr, sizeof(addrstr)); if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL) cachedir = CUPS_CACHEDIR; snprintf(cachefilename, sizeof(cachefilename), "%s/%s.snmp", cachedir, addrstr); if ((cachefile = cupsFileOpen(cachefilename, "r")) != NULL) { /* * Yes, read the cache file: * * 3 num_supplies charset * device description * supply structures... */ if (cupsFileGets(cachefile, value, sizeof(value))) { if (sscanf(value, "3 %d%d", &num_supplies, &charset) == 2 && num_supplies <= CUPS_MAX_SUPPLIES && cupsFileGets(cachefile, value, sizeof(value))) { if (!strcmp(description, value)) cupsFileRead(cachefile, (char *)supplies, (size_t)num_supplies * sizeof(backend_supplies_t)); else { num_supplies = -1; charset = -1; } } else { num_supplies = -1; charset = -1; } } cupsFileClose(cachefile); } /* * If the cache information isn't correct, scan for supplies... */ if (charset < 0) { /* * Get the configured character set... */ int oid[CUPS_SNMP_MAX_OID]; /* OID for character set */ if (!_cupsSNMPWrite(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, prtGeneralCurrentLocalization)) return; if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) || packet.object_type != CUPS_ASN1_INTEGER) { fprintf(stderr, "DEBUG: prtGeneralCurrentLocalization type is %x, expected %x!\n", packet.object_type, CUPS_ASN1_INTEGER); return; } fprintf(stderr, "DEBUG2: prtGeneralCurrentLocalization=%d\n", packet.object_value.integer); _cupsSNMPCopyOID(oid, prtLocalizationCharacterSet, CUPS_SNMP_MAX_OID); oid[prtLocalizationCharacterSetOffset - 2] = packet.object_value.integer; if (!_cupsSNMPWrite(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, oid)) return; if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) || packet.object_type != CUPS_ASN1_INTEGER) { fprintf(stderr, "DEBUG: prtLocalizationCharacterSet type is %x, expected %x!\n", packet.object_type, CUPS_ASN1_INTEGER); return; } fprintf(stderr, "DEBUG2: prtLocalizationCharacterSet=%d\n", packet.object_value.integer); charset = packet.object_value.integer; } if (num_supplies < 0) { /* * Walk the printer configuration information... */ _cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry, CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL); } /* * Save the cached information... */ if (num_supplies < 0) num_supplies = 0; if ((cachefile = cupsFileOpen(cachefilename, "w")) != NULL) { cupsFilePrintf(cachefile, "3 %d %d\n", num_supplies, charset); cupsFilePrintf(cachefile, "%s\n", description); if (num_supplies > 0) cupsFileWrite(cachefile, (char *)supplies, (size_t)num_supplies * sizeof(backend_supplies_t)); cupsFileClose(cachefile); } if (num_supplies <= 0) return; /* * Get the colors... */ for (i = 0; i < num_supplies; i ++) strlcpy(supplies[i].color, "none", sizeof(supplies[i].color)); _cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), prtMarkerColorantValue, CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL); /* * Output the marker-colors attribute... */ for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr)) { if (i) *ptr++ = ','; strlcpy(ptr, supplies[i].color, sizeof(value) - (size_t)(ptr - value)); } fprintf(stderr, "ATTR: marker-colors=%s\n", value); /* * Output the marker-names attribute (the double quoting is necessary to deal * with embedded quotes and commas in the marker names...) */ for (i = 0, ptr = value; i < num_supplies; i ++) { if (i) *ptr++ = ','; *ptr++ = '\''; *ptr++ = '\"'; for (name_ptr = supplies[i].name; *name_ptr;) { if (*name_ptr == '\\' || *name_ptr == '\"' || *name_ptr == '\'') { *ptr++ = '\\'; *ptr++ = '\\'; *ptr++ = '\\'; } *ptr++ = *name_ptr++; } *ptr++ = '\"'; *ptr++ = '\''; } *ptr = '\0'; fprintf(stderr, "ATTR: marker-names=%s\n", value); /* * Output the marker-types attribute... */ for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr)) { if (i) *ptr++ = ','; type = supplies[i].type; if (type < CUPS_TC_other || type > CUPS_TC_covers) strlcpy(ptr, "unknown", sizeof(value) - (size_t)(ptr - value)); else strlcpy(ptr, types[type - CUPS_TC_other], sizeof(value) - (size_t)(ptr - value)); } fprintf(stderr, "ATTR: marker-types=%s\n", value); }
int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ int fd = -1; /* SNMP socket */ http_addrlist_t *host = NULL; /* Address of host */ int walk = 0; /* Walk OIDs? */ char *oid = NULL; /* Last OID shown */ const char *community; /* Community name */ fputs("_cupsSNMPDefaultCommunity: ", stdout); if ((community = _cupsSNMPDefaultCommunity()) == NULL) { puts("FAIL (NULL community name)"); return (1); } printf("PASS (%s)\n", community); /* * Query OIDs from the command-line... */ for (i = 1; i < argc; i ++) if (!strcmp(argv[i], "-c")) { i ++; if (i >= argc) usage(); else community = argv[i]; } else if (!strcmp(argv[i], "-d")) _cupsSNMPSetDebug(10); else if (!strcmp(argv[i], "-w")) walk = 1; else if (!host) { if ((host = httpAddrGetList(argv[i], AF_UNSPEC, "161")) == NULL) { printf("testsnmp: Unable to find \"%s\"!\n", argv[1]); return (1); } if (fd < 0) { fputs("_cupsSNMPOpen: ", stdout); if ((fd = _cupsSNMPOpen(host->addr.addr.sa_family)) < 0) { printf("FAIL (%s)\n", strerror(errno)); return (1); } puts("PASS"); } } else if (!show_oid(fd, community, &(host->addr), argv[i], walk)) return (1); else oid = argv[i]; if (!host) usage(); if (!oid) { if (!show_oid(fd, community, &(host->addr), walk ? ".1.3.6.1.2.1.43" : ".1.3.6.1.2.1.43.10.2.1.4.1.1", walk)) return (1); } return (0); }
int /* O - 0 on success, -1 on error */ backendSNMPSupplies( int snmp_fd, /* I - SNMP socket */ http_addr_t *addr, /* I - Printer address */ int *page_count, /* O - Page count */ int *printer_state) /* O - Printer state */ { if (!httpAddrEqual(addr, ¤t_addr)) backend_init_supplies(snmp_fd, addr); else if (num_supplies > 0) _cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), prtMarkerSuppliesLevel, CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL); if (page_count) *page_count = -1; if (printer_state) *printer_state = -1; if (num_supplies > 0) { int i, /* Looping var */ percent, /* Percent full */ new_state, /* New state value */ change_state, /* State change */ new_supply_state = 0; /* Supply state */ char value[CUPS_MAX_SUPPLIES * 4], /* marker-levels value string */ *ptr; /* Pointer into value string */ cups_snmp_t packet; /* SNMP response packet */ /* * Generate the marker-levels value string... */ for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr)) { if (supplies[i].max_capacity > 0 && supplies[i].level >= 0) percent = 100 * supplies[i].level / supplies[i].max_capacity; else if (supplies[i].level >= 0 && supplies[i].level <= 100 && (quirks & CUPS_SNMP_CAPACITY)) percent = supplies[i].level; else percent = 50; if (supplies[i].sclass == CUPS_TC_receptacleThatIsFilled) percent = 100 - percent; if (percent <= 5) { switch (supplies[i].type) { case CUPS_TC_toner : case CUPS_TC_tonerCartridge : if (percent <= 1) new_supply_state |= CUPS_TONER_EMPTY; else new_supply_state |= CUPS_TONER_LOW; break; case CUPS_TC_ink : case CUPS_TC_inkCartridge : case CUPS_TC_inkRibbon : case CUPS_TC_solidWax : case CUPS_TC_ribbonWax : if (percent <= 1) new_supply_state |= CUPS_MARKER_SUPPLY_EMPTY; else new_supply_state |= CUPS_MARKER_SUPPLY_LOW; break; case CUPS_TC_developer : if (percent <= 1) new_supply_state |= CUPS_DEVELOPER_EMPTY; else new_supply_state |= CUPS_DEVELOPER_LOW; break; case CUPS_TC_coronaWire : case CUPS_TC_fuser : case CUPS_TC_opc : case CUPS_TC_transferUnit : if (percent <= 1) new_supply_state |= CUPS_OPC_LIFE_OVER; else new_supply_state |= CUPS_OPC_NEAR_EOL; break; #if 0 /* Because no two vendors report waste containers the same, disable SNMP reporting of same */ case CUPS_TC_wasteInk : case CUPS_TC_wastePaper : case CUPS_TC_wasteToner : case CUPS_TC_wasteWater : case CUPS_TC_wasteWax : if (percent <= 1) new_supply_state |= CUPS_WASTE_FULL; else new_supply_state |= CUPS_WASTE_ALMOST_FULL; break; #endif /* 0 */ case CUPS_TC_cleanerUnit : case CUPS_TC_fuserCleaningPad : if (percent <= 1) new_supply_state |= CUPS_CLEANER_LIFE_OVER; else new_supply_state |= CUPS_CLEANER_NEAR_EOL; break; } } if (i) *ptr++ = ','; if ((supplies[i].max_capacity > 0 || (quirks & CUPS_SNMP_CAPACITY)) && supplies[i].level >= 0) snprintf(ptr, sizeof(value) - (size_t)(ptr - value), "%d", percent); else strlcpy(ptr, "-1", sizeof(value) - (size_t)(ptr - value)); } fprintf(stderr, "ATTR: marker-levels=%s\n", value); if (supply_state < 0) change_state = 0xffff; else change_state = supply_state ^ new_supply_state; fprintf(stderr, "DEBUG: new_supply_state=%x, change_state=%x\n", new_supply_state, change_state); for (i = 0; i < (int)(sizeof(supply_states) / sizeof(supply_states[0])); i ++) if (change_state & supply_states[i].bit) { fprintf(stderr, "STATE: %c%s\n", (new_supply_state & supply_states[i].bit) ? '+' : '-', supply_states[i].keyword); } supply_state = new_supply_state; /* * Get the current printer status bits... */ if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, hrPrinterDetectedErrorState)) return (-1); if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) || packet.object_type != CUPS_ASN1_OCTET_STRING) return (-1); if (packet.object_value.string.num_bytes == 2) new_state = (packet.object_value.string.bytes[0] << 8) | packet.object_value.string.bytes[1]; else if (packet.object_value.string.num_bytes == 1) new_state = (packet.object_value.string.bytes[0] << 8); else new_state = 0; if (current_state < 0) change_state = 0xffff; else change_state = current_state ^ new_state; fprintf(stderr, "DEBUG: new_state=%x, change_state=%x\n", new_state, change_state); for (i = 0; i < (int)(sizeof(printer_states) / sizeof(printer_states[0])); i ++) if (change_state & printer_states[i].bit) { fprintf(stderr, "STATE: %c%s\n", (new_state & printer_states[i].bit) ? '+' : '-', printer_states[i].keyword); } current_state = new_state; /* * Get the current printer state... */ if (printer_state) { if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, hrPrinterStatus)) return (-1); if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) || packet.object_type != CUPS_ASN1_INTEGER) return (-1); *printer_state = packet.object_value.integer; } /* * Get the current page count... */ if (page_count) { if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, prtMarkerLifeCount)) return (-1); if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) || packet.object_type != CUPS_ASN1_COUNTER) return (-1); *page_count = packet.object_value.counter; } return (0); } else return (-1); }