/*
- * "$Id$"
+ * "$Id: dnssd.c 12660 2015-05-22 19:09:57Z msweet $"
*
- * DNS-SD discovery backend for CUPS.
+ * DNS-SD discovery backend for CUPS.
*
- * Copyright 2008-2012 by Apple Inc.
+ * Copyright 2008-2015 by Apple Inc.
*
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * "LICENSE" which should have been included with this file. If this
- * file is missing or damaged, see the license at "http://www.cups.org/".
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * "LICENSE" which should have been included with this file. If this
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * main() - Browse for printers.
- * browse_callback() - Browse devices.
- * browse_local_callback() - Browse local devices.
- * client_callback() - Avahi client callback function.
- * compare_devices() - Compare two devices.
- * exec_backend() - Execute the backend that corresponds to the
- * resolved service name.
- * device_type() - Get DNS-SD type enumeration from string.
- * get_device() - Create or update a device.
- * query_callback() - Process query data.
- * find_device() - Find a device from its name and domain.
- * sigterm_handler() - Handle termination signals.
- * unquote() - Unquote a name string.
+ * This file is subject to the Apple OS-Developed Software exception.
*/
/*
*domain, /* Domain name */
*fullName, /* Full name */
*make_and_model, /* Make and model from TXT record */
- *device_id; /* 1284 device ID from TXT record */
+ *device_id, /* 1284 device ID from TXT record */
+ *uuid; /* UUID from TXT record */
cups_devtype_t type; /* Device registration type */
int priority, /* Priority associated with type */
cups_shared, /* CUPS shared printer? */
static AvahiSimplePoll *simple_poll = NULL;
/* Poll information */
static int got_data = 0; /* Got data from poll? */
+static int browsers = 0; /* Number of running browsers */
#endif /* HAVE_AVAHI */
#endif /* HAVE_AVAHI */
static int compare_devices(cups_device_t *a, cups_device_t *b);
-static void exec_backend(char **argv);
+static void exec_backend(char **argv) __attribute__((noreturn));
static cups_device_t *get_device(cups_array_t *devices,
const char *serviceName,
const char *regtype,
#ifdef HAVE_AVAHI
if ((simple_poll = avahi_simple_poll_new()) == NULL)
{
- fputs("DEBUG: Unable to create avahi simple poll object.\n", stderr);
- return (1);
+ fputs("DEBUG: Unable to create Avahi simple poll object.\n", stderr);
+ return (0);
}
avahi_simple_poll_set_func(simple_poll, poll_callback, NULL);
0, client_callback, simple_poll, &error);
if (!client)
{
- fputs("DEBUG: Unable to create avahi client.\n", stderr);
- return (1);
+ fputs("DEBUG: Unable to create Avahi client.\n", stderr);
+ return (0);
}
+ browsers = 6;
avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC,
"_fax-ipp._tcp", NULL, 0,
{
unquote(uriName, best->fullName, sizeof(uriName));
- httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri),
- "dnssd", NULL, uriName, 0,
- best->cups_shared ? "/cups" : "/");
+ if (best->uuid)
+ httpAssembleURIf(HTTP_URI_CODING_ALL, device_uri,
+ sizeof(device_uri), "dnssd", NULL, uriName, 0,
+ best->cups_shared ? "/cups?uuid=%s" : "/?uuid=%s",
+ best->uuid);
+ else
+ 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);
{
unquote(uriName, best->fullName, sizeof(uriName));
- httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri),
- "dnssd", NULL, uriName, 0,
- best->cups_shared ? "/cups" : "/");
+ if (best->uuid)
+ httpAssembleURIf(HTTP_URI_CODING_ALL, device_uri,
+ sizeof(device_uri), "dnssd", NULL, uriName, 0,
+ best->cups_shared ? "/cups?uuid=%s" : "/?uuid=%s",
+ best->uuid);
+ else
+ 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);
fprintf(stderr, "DEBUG: sent=%d, count=%d\n", sent, count);
+#ifdef HAVE_AVAHI
+ if (sent == cupsArrayCount(devices) && browsers == 0)
+#else
if (sent == cupsArrayCount(devices))
+#endif /* HAVE_AVAHI */
break;
}
}
"interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
"regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
sdRef, flags, interfaceIndex, errorCode,
- serviceName ? serviceName : "(null)",
- regtype ? regtype : "(null)",
- replyDomain ? replyDomain : "(null)",
- context);
+ serviceName, regtype, replyDomain, context);
/*
* Only process "add" data...
"interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
"regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
sdRef, flags, interfaceIndex, errorCode,
- serviceName ? serviceName : "(null)",
- regtype ? regtype : "(null)",
- replyDomain ? replyDomain : "(null)",
- context);
+ serviceName, regtype, replyDomain, context);
/*
* Only process "add" data...
break;
case AVAHI_BROWSER_REMOVE:
- case AVAHI_BROWSER_ALL_FOR_NOW:
case AVAHI_BROWSER_CACHE_EXHAUSTED:
break;
+
+ case AVAHI_BROWSER_ALL_FOR_NOW:
+ browsers--;
+ break;
}
}
* 'device_type()' - Get DNS-SD type enumeration from string.
*/
-static int
-device_type(const char *regtype)
+static cups_devtype_t /* O - Device type */
+device_type(const char *regtype) /* I - Service registration type */
{
#ifdef HAVE_AVAHI
if (!strcmp(regtype, "_ipp._tcp"))
replyDomain);
#else /* HAVE_AVAHI */
avahi_service_name_join(fullName, kDNSServiceMaxDomainName,
- serviceName, regtype, replyDomain);
+ serviceName, regtype, replyDomain);
#endif /* HAVE_DNSSD */
free(device->fullName);
* Yes, add the device...
*/
- fprintf(stderr, "DEBUG: Found \"%s.%s%s\"...\n", serviceName, regtype,
- replyDomain);
+#ifdef HAVE_DNSSD
+ DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
+#else /* HAVE_AVAHI */
+ avahi_service_name_join(fullName, kDNSServiceMaxDomainName,
+ serviceName, regtype, replyDomain);
+#endif /* HAVE_DNSSD */
device = calloc(sizeof(cups_device_t), 1);
device->name = strdup(serviceName);
value[256], /* Value string */
make_and_model[512], /* Manufacturer and model */
model[256], /* Model */
+ pdl[256], /* PDL */
device_id[2048]; /* 1284 device ID */
device_id[0] = '\0';
make_and_model[0] = '\0';
+ pdl[0] = '\0';
- strcpy(model, "Unknown");
+ strlcpy(model, "Unknown", sizeof(model));
for (data = rdata, dataend = data + rdlen;
data < dataend;
datanext = data + datalen;
for (ptr = key; data < datanext && *data != '='; data ++)
- *ptr++ = *data;
+ *ptr++ = (char)*data;
*ptr = '\0';
if (data < datanext && *data == '=')
data ++;
if (data < datanext)
- memcpy(value, data, datanext - data);
+ memcpy(value, data, (size_t)(datanext - data));
value[datanext - data] = '\0';
fprintf(stderr, "DEBUG2: query_callback: \"%s=%s\".\n",
*/
ptr = device_id + strlen(device_id);
- snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%s:%s;",
- key + 4, value);
+ snprintf(ptr, sizeof(device_id) - (size_t)(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);
+ strlcpy(make_and_model, value, sizeof(make_and_model));
else if (!_cups_strcasecmp(key, "usb_MDL") || !_cups_strcasecmp(key, "usb_MODEL"))
- strcpy(model, value);
+ strlcpy(model, value, sizeof(model));
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);
+ strlcpy(model, value + 1, sizeof(model));
}
else
- strcpy(model, value);
+ strlcpy(model, value, sizeof(model));
}
else if (!_cups_strcasecmp(key, "ty"))
{
- strcpy(model, value);
+ strlcpy(model, value, sizeof(model));
if ((ptr = strchr(model, ',')) != NULL)
*ptr = '\0';
}
+ else if (!_cups_strcasecmp(key, "pdl"))
+ strlcpy(pdl, value, sizeof(pdl));
else if (!_cups_strcasecmp(key, "priority"))
device->priority = atoi(value);
else if ((device->type == CUPS_DEVICE_IPP ||
if (device->type == CUPS_DEVICE_PRINTER)
device->sent = 1;
}
+ else if (!_cups_strcasecmp(key, "UUID"))
+ device->uuid = strdup(value);
}
if (device->device_id)
* Assume the first word is the make...
*/
- memcpy(make_and_model, model, ptr - model);
+ memcpy(make_and_model, model, (size_t)(ptr - model));
make_and_model[ptr - model] = '\0';
snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s",
}
}
+ if (device_id[0] &&
+ !strstr(device_id, "CMD:") &&
+ !strstr(device_id, "COMMAND SET:") &&
+ (strstr(pdl, "application/pdf") ||
+ strstr(pdl, "application/postscript") ||
+ strstr(pdl, "application/vnd.hp-PCL") ||
+ strstr(pdl, "image/")))
+ {
+ value[0] = '\0';
+ if (strstr(pdl, "application/pdf"))
+ strlcat(value, ",PDF", sizeof(value));
+ if (strstr(pdl, "application/postscript"))
+ strlcat(value, ",PS", sizeof(value));
+ if (strstr(pdl, "application/vnd.hp-PCL"))
+ strlcat(value, ",PCL", sizeof(value));
+ for (ptr = strstr(pdl, "image/"); ptr; ptr = strstr(ptr, "image/"))
+ {
+ char *valptr = value + strlen(value);
+ /* Pointer into value */
+
+ if (valptr < (value + sizeof(value) - 1))
+ *valptr++ = ',';
+
+ ptr += 6;
+ while (isalnum(*ptr & 255) || *ptr == '-' || *ptr == '.')
+ {
+ if (isalnum(*ptr & 255) && valptr < (value + sizeof(value) - 1))
+ *valptr++ = (char)toupper(*ptr++ & 255);
+ else
+ break;
+ }
+
+ *valptr = '\0';
+ }
+
+ ptr = device_id + strlen(device_id);
+ snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "CMD:%s;", value + 1);
+ }
+
if (device_id[0])
device->device_id = strdup(device_id);
else
/*
- * End of "$Id$".
+ * End of "$Id: dnssd.c 12660 2015-05-22 19:09:57Z msweet $".
*/