static void read_snmp_response(int fd) /* I - SNMP socket file descriptor */ { char addrname[256]; /* Source address name */ cups_snmp_t packet; /* Decoded packet */ snmp_cache_t key, /* Search key */ *device; /* Matching device */ /* * Read the response data... */ if (!_cupsSNMPRead(fd, &packet, -1.0)) { fprintf(stderr, "ERROR: Unable to read data from socket: %s\n", strerror(errno)); return; } if (HostNameLookups) httpAddrLookup(&(packet.address), addrname, sizeof(addrname)); else httpAddrString(&(packet.address), addrname, sizeof(addrname)); debug_printf("DEBUG: %.3f Received data from %s...\n", run_time(), addrname); /* * Look for the response status code in the SNMP message header... */ if (packet.error) { fprintf(stderr, "ERROR: Bad SNMP packet from %s: %s\n", addrname, packet.error); return; } debug_printf("DEBUG: community=\"%s\"\n", packet.community); debug_printf("DEBUG: request-id=%d\n", packet.request_id); debug_printf("DEBUG: error-status=%d\n", packet.error_status); if (packet.error_status && packet.request_id != DEVICE_TYPE) return; /* * Find a matching device in the cache... */ key.addrname = addrname; device = (snmp_cache_t *)cupsArrayFind(Devices, &key); /* * Process the message... */ switch (packet.request_id) { case DEVICE_TYPE : /* * Got the device type response... */ if (device) { debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n", addrname); return; } /* * Add the device and request the device data... */ add_cache(&(packet.address), addrname, NULL, NULL, NULL); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_DESCRIPTION, DescriptionOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_ID, DeviceIdOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_URI, UriOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_LOCATION, LocationOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_PRODUCT, LexmarkProductOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_PRODUCT, LexmarkProductOID2); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_ID, LexmarkDeviceIdOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_PRODUCT, XeroxProductOID); break; case DEVICE_DESCRIPTION : if (device && packet.object_type == CUPS_ASN1_OCTET_STRING) { /* * Update an existing cache entry... */ char make_model[256]; /* Make and model */ if (strchr((char *)packet.object_value.string.bytes, ':') && strchr((char *)packet.object_value.string.bytes, ';')) { /* * Description is the IEEE-1284 device ID... */ char *ptr; /* Pointer into device ID */ for (ptr = (char *)packet.object_value.string.bytes; *ptr; ptr ++) if (*ptr == '\n') *ptr = ';'; /* A lot of bad printers put a newline */ if (!device->id) device->id = strdup((char *)packet.object_value.string.bytes); backendGetMakeModel((char *)packet.object_value.string.bytes, make_model, sizeof(make_model)); if (device->info) free(device->info); device->info = strdup(make_model); } else { /* * Description is plain text... */ fix_make_model(make_model, (char *)packet.object_value.string.bytes, sizeof(make_model)); if (device->info) free(device->info); device->info = strdup((char *)packet.object_value.string.bytes); } if (!device->make_and_model) device->make_and_model = strdup(make_model); } break; case DEVICE_ID : if (device && packet.object_type == CUPS_ASN1_OCTET_STRING && (!device->id || strlen(device->id) < packet.object_value.string.num_bytes)) { /* * Update an existing cache entry... */ char make_model[256]; /* Make and model */ char *ptr; /* Pointer into device ID */ for (ptr = (char *)packet.object_value.string.bytes; *ptr; ptr ++) if (*ptr == '\n') *ptr = ';'; /* A lot of bad printers put a newline */ if (device->id) free(device->id); device->id = strdup((char *)packet.object_value.string.bytes); /* * Convert the ID to a make and model string... */ backendGetMakeModel((char *)packet.object_value.string.bytes, make_model, sizeof(make_model)); if (device->make_and_model) free(device->make_and_model); device->make_and_model = strdup(make_model); } break; case DEVICE_LOCATION : if (device && packet.object_type == CUPS_ASN1_OCTET_STRING && !device->location) device->location = strdup((char *)packet.object_value.string.bytes); break; case DEVICE_PRODUCT : if (device && packet.object_type == CUPS_ASN1_OCTET_STRING && !device->id) { /* * Update an existing cache entry... */ if (!device->info) device->info = strdup((char *)packet.object_value.string.bytes); if (device->make_and_model) free(device->make_and_model); device->make_and_model = strdup((char *)packet.object_value.string.bytes); } break; case DEVICE_URI : if (device && packet.object_type == CUPS_ASN1_OCTET_STRING && !device->uri && packet.object_value.string.num_bytes > 3) { /* * Update an existing cache entry... */ char scheme[32], /* URI scheme */ userpass[256], /* Username:password in URI */ hostname[256], /* Hostname in URI */ resource[1024]; /* Resource path in URI */ int port; /* Port number in URI */ if (!strncmp((char *)packet.object_value.string.bytes, "lpr:", 4)) { /* * We want "lpd://..." for the URI... */ packet.object_value.string.bytes[2] = 'd'; } if (httpSeparateURI(HTTP_URI_CODING_ALL, (char *)packet.object_value.string.bytes, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) >= HTTP_URI_OK) device->uri = strdup((char *)packet.object_value.string.bytes); } break; } }
int /* O - Number of OIDs found or -1 on error */ _cupsSNMPWalk(int fd, /* I - SNMP socket */ http_addr_t *address, /* I - Address to query */ int version, /* I - SNMP version */ const char *community,/* I - Community name */ const int *prefix, /* I - OID prefix */ double timeout, /* I - Timeout for each response in seconds */ cups_snmp_cb_t cb, /* I - Function to call for each response */ void *data) /* I - User data pointer that is passed to the callback function */ { int count = 0; /* Number of OIDs found */ int request_id = 0; /* Current request ID */ cups_snmp_t packet; /* Current response packet */ int lastoid[CUPS_SNMP_MAX_OID]; /* Last OID we got */ /* * Range check input... */ DEBUG_printf(("4_cupsSNMPWalk(fd=%d, address=%p, version=%d, " "community=\"%s\", prefix=%p, timeout=%.1f, cb=%p, data=%p)", fd, address, version, community, prefix, timeout, cb, data)); if (fd < 0 || !address || version != CUPS_SNMP_VERSION_1 || !community || !prefix || !cb) { DEBUG_puts("5_cupsSNMPWalk: Returning -1"); return (-1); } /* * Copy the OID prefix and then loop until we have no more OIDs... */ _cupsSNMPCopyOID(packet.object_name, prefix, CUPS_SNMP_MAX_OID); lastoid[0] = -1; for (;;) { request_id ++; if (!_cupsSNMPWrite(fd, address, version, community, CUPS_ASN1_GET_NEXT_REQUEST, request_id, packet.object_name)) { DEBUG_puts("5_cupsSNMPWalk: Returning -1"); return (-1); } if (!_cupsSNMPRead(fd, &packet, timeout)) { DEBUG_puts("5_cupsSNMPWalk: Returning -1"); return (-1); } if (!_cupsSNMPIsOIDPrefixed(&packet, prefix) || _cupsSNMPIsOID(&packet, lastoid)) { DEBUG_printf(("5_cupsSNMPWalk: Returning %d", count)); return (count); } if (packet.error || packet.error_status) { DEBUG_printf(("5_cupsSNMPWalk: Returning %d", count > 0 ? count : -1)); return (count > 0 ? count : -1); } _cupsSNMPCopyOID(lastoid, packet.object_name, CUPS_SNMP_MAX_OID); count ++; (*cb)(&packet, data); } }
static void scan_devices(int ipv4, /* I - SNMP IPv4 socket */ int ipv6) /* I - SNMP IPv6 socket */ { int fd, /* File descriptor for this address */ busy; /* Are we busy processing something? */ char *address, /* Current address */ *community; /* Current community */ fd_set input; /* Input set for select() */ struct timeval timeout; /* Timeout for select() */ time_t endtime; /* End time for scan */ http_addrlist_t *addrs, /* List of addresses */ *addr; /* Current address */ snmp_cache_t *device; /* Current device */ char temp[1024]; /* Temporary address string */ gettimeofday(&StartTime, NULL); /* * First send all of the broadcast queries... */ for (address = (char *)cupsArrayFirst(Addresses); address; address = (char *)cupsArrayNext(Addresses)) { if (!strcmp(address, "@LOCAL")) addrs = get_interface_addresses(NULL); else if (!strncmp(address, "@IF(", 4)) { char ifname[255]; /* Interface name */ strlcpy(ifname, address + 4, sizeof(ifname)); if (ifname[0]) ifname[strlen(ifname) - 1] = '\0'; addrs = get_interface_addresses(ifname); } else addrs = httpAddrGetList(address, AF_UNSPEC, NULL); if (!addrs) { fprintf(stderr, "ERROR: Unable to scan \"%s\"!\n", address); continue; } for (community = (char *)cupsArrayFirst(Communities); community; community = (char *)cupsArrayNext(Communities)) { debug_printf("DEBUG: Scanning for devices in \"%s\" via \"%s\"...\n", community, address); for (addr = addrs; addr; addr = addr->next) { #ifdef AF_INET6 if (httpAddrFamily(&(addr->addr)) == AF_INET6) fd = ipv6; else #endif /* AF_INET6 */ fd = ipv4; debug_printf("DEBUG: Sending get request to %s...\n", httpAddrString(&(addr->addr), temp, sizeof(temp))); _cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community, CUPS_ASN1_GET_REQUEST, DEVICE_TYPE, DeviceTypeOID); } } httpAddrFreeList(addrs); } /* * Then read any responses that come in over the next 3 seconds... */ endtime = time(NULL) + MaxRunTime; FD_ZERO(&input); while (time(NULL) < endtime) { timeout.tv_sec = 2; timeout.tv_usec = 0; FD_SET(ipv4, &input); if (ipv6 >= 0) FD_SET(ipv6, &input); fd = ipv4 > ipv6 ? ipv4 : ipv6; if (select(fd + 1, &input, NULL, NULL, &timeout) < 0) { fprintf(stderr, "ERROR: %.3f select() for %d/%d failed: %s\n", run_time(), ipv4, ipv6, strerror(errno)); break; } busy = 0; if (FD_ISSET(ipv4, &input)) { read_snmp_response(ipv4); busy = 1; } if (ipv6 >= 0 && FD_ISSET(ipv6, &input)) { read_snmp_response(ipv6); busy = 1; } if (!busy) { /* * List devices with complete information... */ int sent_something = 0; for (device = (snmp_cache_t *)cupsArrayFirst(Devices); device; device = (snmp_cache_t *)cupsArrayNext(Devices)) if (!device->sent && device->info && device->make_and_model) { if (device->uri) list_device(device); else probe_device(device); device->sent = sent_something = 1; } if (!sent_something) break; } } debug_printf("DEBUG: %.3f Scan complete!\n", run_time()); }
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 int /* O - 1 on success, 0 on error */ show_oid(int fd, /* I - SNMP socket */ const char *community, /* I - Community name */ http_addr_t *addr, /* I - Address to query */ const char *s, /* I - OID to query */ int walk) /* I - Walk OIDs? */ { int i; /* Looping var */ int oid[CUPS_SNMP_MAX_OID]; /* OID */ cups_snmp_t packet; /* SNMP packet */ char temp[1024]; /* Temporary OID string */ if (!_cupsSNMPStringToOID(s, oid, sizeof(oid) / sizeof(oid[0]))) { puts("testsnmp: Bad OID"); return (0); } if (walk) { printf("_cupsSNMPWalk(%s): ", _cupsSNMPOIDToString(oid, temp, sizeof(temp))); if (_cupsSNMPWalk(fd, addr, CUPS_SNMP_VERSION_1, community, oid, 5.0, print_packet, NULL) < 0) { printf("FAIL (%s)\n", strerror(errno)); return (0); } } else { printf("_cupsSNMPWrite(%s): ", _cupsSNMPOIDToString(oid, temp, sizeof(temp))); if (!_cupsSNMPWrite(fd, addr, CUPS_SNMP_VERSION_1, community, CUPS_ASN1_GET_REQUEST, 1, oid)) { printf("FAIL (%s)\n", strerror(errno)); return (0); } puts("PASS"); fputs("_cupsSNMPRead(5.0): ", stdout); if (!_cupsSNMPRead(fd, &packet, 5.0)) { puts("FAIL (timeout)"); return (0); } if (!_cupsSNMPIsOID(&packet, oid)) { printf("FAIL (bad OID %d", packet.object_name[0]); for (i = 1; packet.object_name[i] >= 0; i ++) printf(".%d", packet.object_name[i]); puts(")"); return (0); } if (packet.error) { printf("FAIL (%s)\n", packet.error); return (0); } puts("PASS"); print_packet(&packet, NULL); } return (1); }
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 - 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); }