#include "backend-private.h"
#include <cups/array.h>
#ifdef HAVE_DNSSD
# include <dns_sd.h>
#endif
#ifdef HAVE_AVAHI
# include <avahi-client/client.h>
# include <avahi-client/lookup.h>
# include <avahi-common/simple-watch.h>
# include <avahi-common/domain.h>
# include <avahi-common/error.h>
# include <avahi-common/malloc.h>
#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX
#endif
typedef enum
{
CUPS_DEVICE_PRINTER = 0,
CUPS_DEVICE_IPPS,
CUPS_DEVICE_IPP,
CUPS_DEVICE_FAX_IPP,
CUPS_DEVICE_PDL_DATASTREAM,
CUPS_DEVICE_RIOUSBPRINT
} cups_devtype_t;
typedef struct
{
#ifdef HAVE_DNSSD
DNSServiceRef ref;
#endif
#ifdef HAVE_AVAHI
AvahiRecordBrowser *ref;
#endif
char *name,
*domain,
*fullName,
*make_and_model,
*device_id;
cups_devtype_t type;
int priority,
cups_shared,
sent;
} cups_device_t;
static int job_canceled = 0;
#ifdef HAVE_AVAHI
static AvahiSimplePoll *simple_poll = NULL;
static int got_data = 0;
#endif
#ifdef HAVE_DNSSD
static void browse_callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *serviceName,
const char *regtype,
const char *replyDomain, void *context)
__attribute__((nonnull(1,5,6,7,8)));
static void browse_local_callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *serviceName,
const char *regtype,
const char *replyDomain,
void *context)
__attribute__((nonnull(1,5,6,7,8)));
#endif
#ifdef HAVE_AVAHI
static void browse_callback(AvahiServiceBrowser *browser,
AvahiIfIndex interface,
AvahiProtocol protocol,
AvahiBrowserEvent event,
const char *serviceName,
const char *regtype,
const char *replyDomain,
AvahiLookupResultFlags flags,
void *context);
static void client_callback(AvahiClient *client,
AvahiClientState state,
void *context);
#endif
static int compare_devices(cups_device_t *a, cups_device_t *b);
static void exec_backend(char **argv);
static cups_device_t *get_device(cups_array_t *devices,
const char *serviceName,
const char *regtype,
const char *replyDomain)
__attribute__((nonnull(1,2,3,4)));
#ifdef HAVE_DNSSD
static void query_callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *fullName, uint16_t rrtype,
uint16_t rrclass, uint16_t rdlen,
const void *rdata, uint32_t ttl,
void *context)
__attribute__((nonnull(1,5,9,11)));
#elif defined(HAVE_AVAHI)
static int poll_callback(struct pollfd *pollfds,
unsigned int num_pollfds, int timeout,
void *context);
static void query_callback(AvahiRecordBrowser *browser,
AvahiIfIndex interface,
AvahiProtocol protocol,
AvahiBrowserEvent event,
const char *name, uint16_t rrclass,
uint16_t rrtype, const void *rdata,
size_t rdlen,
AvahiLookupResultFlags flags,
void *context);
#endif
static void sigterm_handler(int sig);
static void unquote(char *dst, const char *src, size_t dstsize)
__attribute__((nonnull(1,2)));
int
main(int argc,
char *argv[])
{
const char *name;
cups_array_t *devices;
cups_device_t *device;
char uriName[1024];
#ifdef HAVE_DNSSD
int fd;
fd_set input;
struct timeval timeout;
DNSServiceRef main_ref,
fax_ipp_ref,
ipp_ref,
ipp_tls_ref,
ipps_ref,
local_fax_ipp_ref,
local_ipp_ref,
local_ipp_tls_ref,
local_ipps_ref,
local_printer_ref,
pdl_datastream_ref,
printer_ref,
riousbprint_ref;
#endif
#ifdef HAVE_AVAHI
AvahiClient *client;
int error;
#endif
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action;
#endif
setbuf(stderr, NULL);
#ifdef HAVE_SIGSET
sigset(SIGTERM, sigterm_handler);
#elif defined(HAVE_SIGACTION)
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_handler = sigterm_handler;
sigaction(SIGTERM, &action, NULL);
#else
signal(SIGTERM, sigterm_handler);
#endif
if (argc >= 6)
exec_backend(argv);
else if (argc != 1)
{
_cupsLangPrintf(stderr,
_("Usage: %s job-id user title copies options [file]"),
argv[0]);
return (1);
}
if ((name = strrchr(argv[0], '/')) != NULL)
name ++;
else
name = argv[0];
if (strcmp(name, "dnssd"))
return (0);
devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL);
#ifdef HAVE_DNSSD
if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError)
{
perror("ERROR: Unable to create service connection");
return (1);
}
fd = DNSServiceRefSockFD(main_ref);
fax_ipp_ref = main_ref;
DNSServiceBrowse(&fax_ipp_ref, kDNSServiceFlagsShareConnection, 0,
"_fax-ipp._tcp", NULL, browse_callback, devices);
ipp_ref = main_ref;
DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0,
"_ipp._tcp", NULL, browse_callback, devices);
ipp_tls_ref = main_ref;
DNSServiceBrowse(&ipp_tls_ref, kDNSServiceFlagsShareConnection, 0,
"_ipp-tls._tcp", NULL, browse_callback, devices);
ipps_ref = main_ref;
DNSServiceBrowse(&ipps_ref, kDNSServiceFlagsShareConnection, 0,
"_ipps._tcp", NULL, browse_callback, devices);
local_fax_ipp_ref = main_ref;
DNSServiceBrowse(&local_fax_ipp_ref, kDNSServiceFlagsShareConnection,
kDNSServiceInterfaceIndexLocalOnly,
"_fax-ipp._tcp", NULL, browse_local_callback, devices);
local_ipp_ref = main_ref;
DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection,
kDNSServiceInterfaceIndexLocalOnly,
"_ipp._tcp", NULL, browse_local_callback, devices);
local_ipp_tls_ref = main_ref;
DNSServiceBrowse(&local_ipp_tls_ref, kDNSServiceFlagsShareConnection,
kDNSServiceInterfaceIndexLocalOnly,
"_ipp-tls._tcp", NULL, browse_local_callback, devices);
local_ipps_ref = main_ref;
DNSServiceBrowse(&local_ipps_ref, kDNSServiceFlagsShareConnection,
kDNSServiceInterfaceIndexLocalOnly,
"_ipps._tcp", NULL, browse_local_callback, devices);
local_printer_ref = main_ref;
DNSServiceBrowse(&local_printer_ref, kDNSServiceFlagsShareConnection,
kDNSServiceInterfaceIndexLocalOnly,
"_printer._tcp", NULL, browse_local_callback, devices);
pdl_datastream_ref = main_ref;
DNSServiceBrowse(&pdl_datastream_ref, kDNSServiceFlagsShareConnection, 0,
"_pdl-datastream._tcp", NULL, browse_callback, devices);
printer_ref = main_ref;
DNSServiceBrowse(&printer_ref, kDNSServiceFlagsShareConnection, 0,
"_printer._tcp", NULL, browse_callback, devices);
riousbprint_ref = main_ref;
DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0,
"_riousbprint._tcp", NULL, browse_callback, devices);
#endif
#ifdef HAVE_AVAHI
if ((simple_poll = avahi_simple_poll_new()) == NULL)
{
fputs("DEBUG: Unable to create Avahi simple poll object.\n", stderr);
return (1);
}
avahi_simple_poll_set_func(simple_poll, poll_callback, NULL);
client = avahi_client_new(avahi_simple_poll_get(simple_poll),
0, client_callback, simple_poll, &error);
if (!client)
{
fputs("DEBUG: Unable to create Avahi client.\n", stderr);
return (1);
}
avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC,
"_fax-ipp._tcp", NULL, 0,
browse_callback, devices);
avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC,
"_ipp._tcp", NULL, 0,
browse_callback, devices);
avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC,
"_ipp-tls._tcp", NULL, 0,
browse_callback, devices);
avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC,
"_ipps._tcp", NULL, 0,
browse_callback, devices);
avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC,
"_pdl-datastream._tcp",
NULL, 0,
browse_callback,
devices);
avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC,
"_printer._tcp", NULL, 0,
browse_callback, devices);
#endif
while (!job_canceled)
{
int announce = 0;
#ifdef HAVE_DNSSD
FD_ZERO(&input);
FD_SET(fd, &input);
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
if (select(fd + 1, &input, NULL, NULL, &timeout) < 0)
continue;
if (FD_ISSET(fd, &input))
{
DNSServiceProcessResult(main_ref);
}
else
announce = 1;
#elif defined(HAVE_AVAHI)
got_data = 0;
if ((error = avahi_simple_poll_iterate(simple_poll, 500)) > 0)
{
break;
}
if (!got_data)
announce = 1;
#endif
if (announce)
{
#ifdef HAVE_DNSSD
DNSServiceErrorType status;
#endif
cups_device_t *best;
char device_uri[1024];
int count;
int sent;
for (device = (cups_device_t *)cupsArrayFirst(devices),
best = NULL, count = 0, sent = 0;
device;
device = (cups_device_t *)cupsArrayNext(devices))
{
if (device->sent)
sent ++;
if (device->ref)
count ++;
if (!device->ref && !device->sent)
{
if (count < 50)
{
fprintf(stderr, "DEBUG: Querying \"%s\"...\n", device->fullName);
#ifdef HAVE_DNSSD
device->ref = main_ref;
status = DNSServiceQueryRecord(&(device->ref),
kDNSServiceFlagsShareConnection,
0, device->fullName,
kDNSServiceType_TXT,
kDNSServiceClass_IN, query_callback,
device);
if (status != kDNSServiceErr_NoError)
fprintf(stderr,
"ERROR: Unable to query \"%s\" for TXT records: %d\n",
device->fullName, status);
else
count ++;
#else
if ((device->ref = avahi_record_browser_new(client, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC,
device->fullName,
AVAHI_DNS_CLASS_IN,
AVAHI_DNS_TYPE_TXT,
0,
query_callback,
device)) == NULL)
fprintf(stderr,
"ERROR: Unable to query \"%s\" for TXT records: %s\n",
device->fullName,
avahi_strerror(avahi_client_errno(client)));
else
count ++;
#endif
}
}
else if (!device->sent)
{
#ifdef HAVE_DNSSD
DNSServiceRefDeallocate(device->ref);
#else
avahi_record_browser_free(device->ref);
#endif
device->ref = NULL;
if (!best)
best = device;
else if (_cups_strcasecmp(best->name, device->name) ||
_cups_strcasecmp(best->domain, device->domain))
{
unquote(uriName, best->fullName, sizeof(uriName));
httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri),
"dnssd", NULL, uriName, 0,
best->cups_shared ? "/cups" : "/");
cupsBackendReport("network", device_uri, best->make_and_model,
best->name, best->device_id, NULL);
best->sent = 1;
best = device;
sent ++;
}
else if (best->priority > device->priority ||
(best->priority == device->priority &&
best->type < device->type))
{
best->sent = 1;
best = device;
sent ++;
}
else
{
device->sent = 1;
sent ++;
}
}
}
if (best)
{
unquote(uriName, best->fullName, sizeof(uriName));
httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri),
"dnssd", NULL, uriName, 0,
best->cups_shared ? "/cups" : "/");
cupsBackendReport("network", device_uri, best->make_and_model,
best->name, best->device_id, NULL);
best->sent = 1;
sent ++;
}
fprintf(stderr, "DEBUG: sent=%d, count=%d\n", sent, count);
if (sent == cupsArrayCount(devices))
break;
}
}
return (CUPS_BACKEND_OK);
}
#ifdef HAVE_DNSSD
static void
browse_callback(
DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *serviceName,
const char *regtype,
const char *replyDomain,
void *context)
{
fprintf(stderr, "DEBUG2: browse_callback(sdRef=%p, flags=%x, "
"interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
"regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
sdRef, flags, interfaceIndex, errorCode,
serviceName, regtype, replyDomain, context);
if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
return;
get_device((cups_array_t *)context, serviceName, regtype, replyDomain);
}
static void
browse_local_callback(
DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *serviceName,
const char *regtype,
const char *replyDomain,
void *context)
{
cups_device_t *device;
fprintf(stderr, "DEBUG2: browse_local_callback(sdRef=%p, flags=%x, "
"interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
"regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
sdRef, flags, interfaceIndex, errorCode,
serviceName, regtype, replyDomain, context);
if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
return;
device = get_device((cups_array_t *)context, serviceName, regtype,
replyDomain);
fprintf(stderr, "DEBUG: Hiding local printer \"%s\"...\n",
device->fullName);
device->sent = 1;
}
#endif
#ifdef HAVE_AVAHI
static void
browse_callback(
AvahiServiceBrowser *browser,
AvahiIfIndex interface,
AvahiProtocol protocol,
AvahiBrowserEvent event,
const char *name,
const char *type,
const char *domain,
AvahiLookupResultFlags flags,
void *context)
{
AvahiClient *client = avahi_service_browser_get_client(browser);
(void)interface;
(void)protocol;
(void)context;
switch (event)
{
case AVAHI_BROWSER_FAILURE:
fprintf(stderr, "DEBUG: browse_callback: %s\n",
avahi_strerror(avahi_client_errno(client)));
avahi_simple_poll_quit(simple_poll);
break;
case AVAHI_BROWSER_NEW:
if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
{
fprintf(stderr, "DEBUG: Ignoring local service %s.\n", name);
}
else
{
get_device((cups_array_t *)context, name, type, domain);
}
break;
case AVAHI_BROWSER_REMOVE:
case AVAHI_BROWSER_ALL_FOR_NOW:
case AVAHI_BROWSER_CACHE_EXHAUSTED:
break;
}
}
static void
client_callback(
AvahiClient *client,
AvahiClientState state,
void *context)
{
(void)client;
(void)context;
if (state == AVAHI_CLIENT_FAILURE)
{
fputs("DEBUG: Avahi connection failed.\n", stderr);
avahi_simple_poll_quit(simple_poll);
}
}
#endif
static int
compare_devices(cups_device_t *a,
cups_device_t *b)
{
return (strcmp(a->name, b->name));
}
static void
exec_backend(char **argv)
{
const char *resolved_uri,
*cups_serverbin;
char scheme[1024],
*ptr,
filename[1024];
job_canceled = -1;
while ((resolved_uri = cupsBackendDeviceURI(argv)) == NULL)
{
_cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer."));
sleep(10);
if (getenv("CLASS") != NULL)
exit(CUPS_BACKEND_FAILED);
}
strlcpy(scheme, resolved_uri, sizeof(scheme));
if ((ptr = strchr(scheme, ':')) != NULL)
*ptr = '\0';
if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
cups_serverbin = CUPS_SERVERBIN;
snprintf(filename, sizeof(filename), "%s/backend/%s", cups_serverbin, scheme);
setenv("DEVICE_URI", resolved_uri, 1);
argv[0] = (char *)resolved_uri;
fprintf(stderr, "DEBUG: Executing backend \"%s\"...\n", filename);
execv(filename, argv);
fprintf(stderr, "ERROR: Unable to execute backend \"%s\": %s\n", filename,
strerror(errno));
exit(CUPS_BACKEND_STOP);
}
static int
device_type(const char *regtype)
{
#ifdef HAVE_AVAHI
if (!strcmp(regtype, "_ipp._tcp"))
return (CUPS_DEVICE_IPP);
else if (!strcmp(regtype, "_ipps._tcp") ||
!strcmp(regtype, "_ipp-tls._tcp"))
return (CUPS_DEVICE_IPPS);
else if (!strcmp(regtype, "_fax-ipp._tcp"))
return (CUPS_DEVICE_FAX_IPP);
else if (!strcmp(regtype, "_printer._tcp"))
return (CUPS_DEVICE_PDL_DATASTREAM);
#else
if (!strcmp(regtype, "_ipp._tcp."))
return (CUPS_DEVICE_IPP);
else if (!strcmp(regtype, "_ipps._tcp.") ||
!strcmp(regtype, "_ipp-tls._tcp."))
return (CUPS_DEVICE_IPPS);
else if (!strcmp(regtype, "_fax-ipp._tcp."))
return (CUPS_DEVICE_FAX_IPP);
else if (!strcmp(regtype, "_printer._tcp."))
return (CUPS_DEVICE_PRINTER);
else if (!strcmp(regtype, "_pdl-datastream._tcp."))
return (CUPS_DEVICE_PDL_DATASTREAM);
#endif
return (CUPS_DEVICE_RIOUSBPRINT);
}
static cups_device_t *
get_device(cups_array_t *devices,
const char *serviceName,
const char *regtype,
const char *replyDomain)
{
cups_device_t key,
*device;
char fullName[kDNSServiceMaxDomainName];
key.name = (char *)serviceName;
key.type = device_type(regtype);
for (device = cupsArrayFind(devices, &key);
device;
device = cupsArrayNext(devices))
if (_cups_strcasecmp(device->name, key.name))
break;
else if (device->type == key.type)
{
if (!_cups_strcasecmp(device->domain, "local.") &&
_cups_strcasecmp(device->domain, replyDomain))
{
free(device->domain);
device->domain = strdup(replyDomain);
#ifdef HAVE_DNSSD
DNSServiceConstructFullName(fullName, device->name, regtype,
replyDomain);
#else
avahi_service_name_join(fullName, kDNSServiceMaxDomainName,
serviceName, regtype, replyDomain);
#endif
free(device->fullName);
device->fullName = strdup(fullName);
}
return (device);
}
fprintf(stderr, "DEBUG: Found \"%s.%s%s\"...\n", serviceName, regtype,
replyDomain);
device = calloc(sizeof(cups_device_t), 1);
device->name = strdup(serviceName);
device->domain = strdup(replyDomain);
device->type = key.type;
device->priority = 50;
cupsArrayAdd(devices, device);
#ifdef HAVE_DNSSD
DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
#else
avahi_service_name_join(fullName, kDNSServiceMaxDomainName,
serviceName, regtype, replyDomain);
#endif
device->fullName = strdup(fullName);
return (device);
}
#ifdef HAVE_AVAHI
static int
poll_callback(
struct pollfd *pollfds,
unsigned int num_pollfds,
int timeout,
void *context)
{
int val;
(void)timeout;
(void)context;
val = poll(pollfds, num_pollfds, 500);
if (val < 0)
fprintf(stderr, "DEBUG: poll_callback: %s\n", strerror(errno));
else if (val > 0)
got_data = 1;
return (val);
}
#endif
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
# ifdef HAVE_DNSSD
static void
query_callback(
DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *fullName,
uint16_t rrtype,
uint16_t rrclass,
uint16_t rdlen,
const void *rdata,
uint32_t ttl,
void *context)
{
# else
static void
query_callback(
AvahiRecordBrowser *browser,
AvahiIfIndex interfaceIndex,
AvahiProtocol protocol,
AvahiBrowserEvent event,
const char *fullName,
uint16_t rrclass,
uint16_t rrtype,
const void *rdata,
size_t rdlen,
AvahiLookupResultFlags flags,
void *context)
{
AvahiClient *client = avahi_record_browser_get_client(browser);
# endif
char *ptr;
cups_device_t *device = (cups_device_t *)context;
const uint8_t *data,
*datanext,
*dataend;
uint8_t datalen;
char key[256],
value[256],
make_and_model[512],
model[256],
device_id[2048];
# ifdef HAVE_DNSSD
fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, "
"interfaceIndex=%d, errorCode=%d, fullName=\"%s\", "
"rrtype=%u, rrclass=%u, rdlen=%u, rdata=%p, ttl=%u, "
"context=%p)\n",
sdRef, flags, interfaceIndex, errorCode,
fullName ? fullName : "(null)", rrtype, rrclass, rdlen, rdata, ttl,
context);
if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
return;
# else
fprintf(stderr, "DEBUG2: query_callback(browser=%p, interfaceIndex=%d, "
"protocol=%d, event=%d, fullName=\"%s\", rrclass=%u, "
"rrtype=%u, rdata=%p, rdlen=%u, flags=%x, context=%p)\n",
browser, interfaceIndex, protocol, event,
fullName ? fullName : "(null)", rrclass, rrtype, rdata,
(unsigned)rdlen, flags, context);
if (event != AVAHI_BROWSER_NEW)
{
if (event == AVAHI_BROWSER_FAILURE)
fprintf(stderr, "ERROR: %s\n",
avahi_strerror(avahi_client_errno(client)));
return;
}
# endif
device_id[0] = '\0';
make_and_model[0] = '\0';
strcpy(model, "Unknown");
for (data = rdata, dataend = data + rdlen;
data < dataend;
data = datanext)
{
datalen = *data++;
if (!datalen || (data + datalen) > dataend)
break;
datanext = data + datalen;
for (ptr = key; data < datanext && *data != '='; data ++)
*ptr++ = *data;
*ptr = '\0';
if (data < datanext && *data == '=')
{
data ++;
if (data < datanext)
memcpy(value, data, datanext - data);
value[datanext - data] = '\0';
fprintf(stderr, "DEBUG2: query_callback: \"%s=%s\".\n",
key, value);
}
else
{
fprintf(stderr, "DEBUG2: query_callback: \"%s\" with no value.\n",
key);
continue;
}
if (!_cups_strncasecmp(key, "usb_", 4))
{
ptr = device_id + strlen(device_id);
snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%s:%s;",
key + 4, value);
}
if (!_cups_strcasecmp(key, "usb_MFG") || !_cups_strcasecmp(key, "usb_MANU") ||
!_cups_strcasecmp(key, "usb_MANUFACTURER"))
strcpy(make_and_model, value);
else if (!_cups_strcasecmp(key, "usb_MDL") || !_cups_strcasecmp(key, "usb_MODEL"))
strcpy(model, value);
else if (!_cups_strcasecmp(key, "product") && !strstr(value, "Ghostscript"))
{
if (value[0] == '(')
{
if ((ptr = value + strlen(value) - 1) > value && *ptr == ')')
*ptr = '\0';
strcpy(model, value + 1);
}
else
strcpy(model, value);
}
else if (!_cups_strcasecmp(key, "ty"))
{
strcpy(model, value);
if ((ptr = strchr(model, ',')) != NULL)
*ptr = '\0';
}
else if (!_cups_strcasecmp(key, "priority"))
device->priority = atoi(value);
else if ((device->type == CUPS_DEVICE_IPP ||
device->type == CUPS_DEVICE_IPPS ||
device->type == CUPS_DEVICE_PRINTER) &&
!_cups_strcasecmp(key, "printer-type"))
{
device->cups_shared = 1;
if (device->type == CUPS_DEVICE_PRINTER)
device->sent = 1;
}
}
if (device->device_id)
free(device->device_id);
if (!device_id[0] && strcmp(model, "Unknown"))
{
if (make_and_model[0])
snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;",
make_and_model, model);
else if (!_cups_strncasecmp(model, "designjet ", 10))
snprintf(device_id, sizeof(device_id), "MFG:HP;MDL:%s", model + 10);
else if (!_cups_strncasecmp(model, "stylus ", 7))
snprintf(device_id, sizeof(device_id), "MFG:EPSON;MDL:%s", model + 7);
else if ((ptr = strchr(model, ' ')) != NULL)
{
memcpy(make_and_model, model, ptr - model);
make_and_model[ptr - model] = '\0';
snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s",
make_and_model, ptr + 1);
}
}
if (device_id[0])
device->device_id = strdup(device_id);
else
device->device_id = NULL;
if (device->make_and_model)
free(device->make_and_model);
if (make_and_model[0])
{
strlcat(make_and_model, " ", sizeof(make_and_model));
strlcat(make_and_model, model, sizeof(make_and_model));
device->make_and_model = strdup(make_and_model);
}
else
device->make_and_model = strdup(model);
}
#endif
static void
sigterm_handler(int sig)
{
(void)sig;
if (job_canceled)
exit(CUPS_BACKEND_OK);
else
job_canceled = 1;
}
static void
unquote(char *dst,
const char *src,
size_t dstsize)
{
char *dstend = dst + dstsize - 1;
while (*src && dst < dstend)
{
if (*src == '\\')
{
src ++;
if (isdigit(src[0] & 255) && isdigit(src[1] & 255) &&
isdigit(src[2] & 255))
{
*dst++ = ((((src[0] - '0') * 10) + src[1] - '0') * 10) + src[2] - '0';
src += 3;
}
else
*dst++ = *src++;
}
else
*dst++ = *src ++;
}
*dst = '\0';
}