/*
- * "$Id$"
+ * Utility to find IPP printers via Bonjour/DNS-SD and optionally run
+ * commands such as IPP and Bonjour conformance tests. This tool is
+ * inspired by the UNIX "find" command, thus its name.
*
- * Utility to find IPP printers via Bonjour/DNS-SD and optionally run
- * commands such as IPP and Bonjour conformance tests. This tool is
- * inspired by the UNIX "find" command, thus its name.
+ * Copyright © 2008-2018 by Apple Inc.
*
- * Copyright 2008-2013 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"
- * which should have been included with this file. If this file is
- * 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.
- * browse_callback() - Browse devices.
- * client_callback() - Avahi client callback function.
- * compare_services() - Compare two devices.
- * dnssd_error_string() - Return an error string for an error code.
- * eval_expr() - Evaluate the expressions against the specified
- * service.
- * exec_program() - Execute a program for a service.
- * get_service() - Create or update a device.
- * get_time() - Get the current time-of-day in seconds.
- * list_service() - List the contents of a service.
- * new_expr() - Create a new expression.
- * poll_callback() - Wait for input on the specified file
- * descriptors.
- * resolve_callback() - Process resolve data.
- * set_service_uri() - Set the URI of the service.
- * show_usage() - Show program usage.
- * show_version() - Show program version.
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more
+ * information.
*/
/*
IPPFIND_OP_IS_REMOTE, /* Is a remote service */
IPPFIND_OP_DOMAIN_REGEX, /* Domain matches regular expression */
IPPFIND_OP_NAME_REGEX, /* Name matches regular expression */
+ IPPFIND_OP_NAME_LITERAL, /* Name matches literal string */
IPPFIND_OP_HOST_REGEX, /* Hostname matches regular expression */
IPPFIND_OP_PORT_RANGE, /* Port matches range */
IPPFIND_OP_PATH_REGEX, /* Path matches regular expression */
*child; /* Child expressions */
ippfind_op_t op; /* Operation code (see above) */
int invert; /* Invert the result */
- char *key; /* TXT record key */
+ char *name; /* TXT record key or literal name */
regex_t re; /* Regular expression for matching */
int range[2]; /* Port number range */
int num_args; /* Number of arguments for exec */
{
int i, /* Looping var */
have_output = 0,/* Have output expression */
- status = IPPFIND_EXIT_TRUE;
+ status = IPPFIND_EXIT_FALSE;
/* Exit status */
const char *opt, /* Option character */
*search; /* Current browse/resolve string */
"IS_REMOTE",
"DOMAIN_REGEX",
"NAME_REGEX",
+ "NAME_LITERAL",
"HOST_REGEX",
"PORT_RANGE",
"PATH_REGEX",
* Parse command-line...
*/
+ if (getenv("IPPFIND_DEBUG"))
+ for (i = 1; i < argc; i ++)
+ fprintf(stderr, "argv[%d]=\"%s\"\n", i, argv[i]);
+
for (i = 1; i < argc; i ++)
{
if (argv[i][0] == '-')
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
+ else if (!strcmp(argv[i], "--literal-name"))
+ {
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr, _("ippfind: Missing name after %s."), "--literal-name");
+ show_usage();
+ }
+
+ if ((temp = new_expr(IPPFIND_OP_NAME_LITERAL, invert, argv[i], NULL, NULL)) == NULL)
+ return (IPPFIND_EXIT_MEMORY);
+ }
else if (!strcmp(argv[i], "--name"))
{
i ++;
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
- else if (!strncmp(argv[i], "--txt-", 5))
+ else if (!strncmp(argv[i], "--txt-", 6))
{
- const char *key = argv[i] + 5;/* TXT key */
+ const char *key = argv[i] + 6;/* TXT key */
i ++;
if (i >= argc)
address_family = AF_INET6;
break;
+ case 'N' : /* Literal name */
+ i ++;
+ if (i >= argc)
+ {
+ _cupsLangPrintf(stderr, _("ippfind: Missing name after %s."), "-N");
+ show_usage();
+ }
+
+ if ((temp = new_expr(IPPFIND_OP_NAME_LITERAL, invert, argv[i], NULL, NULL)) == NULL)
+ return (IPPFIND_EXIT_MEMORY);
+ break;
+
case 'P' :
i ++;
if (i >= argc)
"ippfind");
show_usage();
}
- show_usage();
if (!strcmp(argv[i], "1.1"))
ipp_version = 11;
_cupsLangPrintf(stderr, _("%s: Unknown option \"-%c\"."),
"ippfind", *opt);
show_usage();
- break;
}
if (temp)
*domain; /* Domain, if any */
strlcpy(buf, search, sizeof(buf));
- if (buf[0] == '_')
+ if ((regtype = strstr(buf, "._")) != NULL)
{
- regtype = buf;
- }
- else if ((regtype = strstr(buf, "._")) != NULL)
- {
- name = buf;
- *regtype++ = '\0';
+ if (strcmp(regtype, "._tcp"))
+ {
+ /*
+ * "something._protocol._tcp" -> search for something with the given
+ * protocol...
+ */
+
+ name = buf;
+ *regtype++ = '\0';
+ }
+ else
+ {
+ /*
+ * "_protocol._tcp" -> search for everything with the given protocol...
+ */
+
+ /* name = NULL; */
+ regtype = buf;
+ }
}
else
{
+ /*
+ * "something" -> search for something with IPP protocol...
+ */
+
name = buf;
regtype = "_ipp._tcp";
}
for (domain = regtype; *domain; domain ++)
+ {
if (*domain == '.' && domain[1] != '_')
{
- *domain++ = '\0';
- break;
+ *domain++ = '\0';
+ break;
}
+ }
if (!*domain)
domain = NULL;
_cupsLangPrintf(stderr, _("ippfind: Unable to browse or resolve: %s"),
dnssd_error_string(err));
- if (name)
- printf("name=\"%s\"\n", name);
-
- printf("regtype=\"%s\"\n", regtype);
-
- if (domain)
- printf("domain=\"%s\"\n", domain);
-
return (IPPFIND_EXIT_BONJOUR);
}
}
service->ref = NULL;
}
- if (!eval_expr(service, expressions))
- status = IPPFIND_EXIT_FALSE;
+ if (eval_expr(service, expressions))
+ status = IPPFIND_EXIT_TRUE;
service->is_processed = 1;
}
* Only process "add" data...
*/
+ (void)sdRef;
+ (void)interfaceIndex;
+
if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
return;
* Only process "add" data...
*/
+ (void)sdRef;
+ (void)interfaceIndex;
+
if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
return;
case IPPFIND_OP_NAME_REGEX :
result = !regexec(&(expression->re), service->name, 0, NULL, 0);
break;
+ case IPPFIND_OP_NAME_LITERAL :
+ result = !_cups_strcasecmp(expression->name, service->name);
+ break;
case IPPFIND_OP_HOST_REGEX :
result = !regexec(&(expression->re), service->host, 0, NULL, 0);
break;
result = !regexec(&(expression->re), service->resource, 0, NULL, 0);
break;
case IPPFIND_OP_TXT_EXISTS :
- result = cupsGetOption(expression->key, service->num_txt,
+ result = cupsGetOption(expression->name, service->num_txt,
service->txt) != NULL;
break;
case IPPFIND_OP_TXT_REGEX :
- val = cupsGetOption(expression->key, service->num_txt,
+ val = cupsGetOption(expression->name, service->num_txt,
service->txt);
if (val)
result = !regexec(&(expression->re), val, 0, NULL, 0);
else
result = 0;
+
+ if (getenv("IPPFIND_DEBUG"))
+ printf("TXT_REGEX of \"%s\": %d\n", val, result);
break;
case IPPFIND_OP_URI_REGEX :
result = !regexec(&(expression->re), service->uri, 0, NULL, 0);
snprintf(txt[i], sizeof(txt[i]), "IPPFIND_TXT_%s=%s", service->txt[i].name,
service->txt[i].value);
for (ptr = txt[i] + 12; *ptr && *ptr != '='; ptr ++)
- *ptr = _cups_toupper(*ptr);
+ *ptr = (char)_cups_toupper(*ptr);
}
for (i = 0, myenvc = 7 + service->num_txt; environ[i]; i ++)
if (strncmp(environ[i], "IPPFIND_", 8))
myenvc ++;
- if ((myenvp = calloc(sizeof(char *), myenvc + 1)) == NULL)
+ if ((myenvp = calloc(sizeof(char *), (size_t)(myenvc + 1))) == NULL)
{
_cupsLangPuts(stderr, _("ippfind: Out of memory."));
exit(IPPFIND_EXIT_MEMORY);
* Allocate and copy command-line arguments...
*/
- if ((myargv = calloc(sizeof(char *), num_args + 1)) == NULL)
+ if ((myargv = calloc(sizeof(char *), (size_t)(num_args + 1))) == NULL)
{
_cupsLangPuts(stderr, _("ippfind: Out of memory."));
exit(IPPFIND_EXIT_MEMORY);
*kptr = '\0';
if (!keyword[0] || !strcmp(keyword, "service_uri"))
- strlcpy(tptr, service->uri, sizeof(temp) - (tptr - temp));
+ strlcpy(tptr, service->uri, sizeof(temp) - (size_t)(tptr - temp));
else if (!strcmp(keyword, "service_domain"))
- strlcpy(tptr, service->domain, sizeof(temp) - (tptr - temp));
+ strlcpy(tptr, service->domain, sizeof(temp) - (size_t)(tptr - temp));
else if (!strcmp(keyword, "service_hostname"))
- strlcpy(tptr, service->host, sizeof(temp) - (tptr - temp));
+ strlcpy(tptr, service->host, sizeof(temp) - (size_t)(tptr - temp));
else if (!strcmp(keyword, "service_name"))
- strlcpy(tptr, service->name, sizeof(temp) - (tptr - temp));
+ strlcpy(tptr, service->name, sizeof(temp) - (size_t)(tptr - temp));
else if (!strcmp(keyword, "service_path"))
- strlcpy(tptr, service->resource, sizeof(temp) - (tptr - temp));
+ strlcpy(tptr, service->resource, sizeof(temp) - (size_t)(tptr - temp));
else if (!strcmp(keyword, "service_port"))
- strlcpy(tptr, port + 20, sizeof(temp) - (tptr - temp));
+ strlcpy(tptr, port + 21, sizeof(temp) - (size_t)(tptr - temp));
else if (!strcmp(keyword, "service_scheme"))
- strlcpy(tptr, scheme + 22, sizeof(temp) - (tptr - temp));
+ strlcpy(tptr, scheme + 22, sizeof(temp) - (size_t)(tptr - temp));
else if (!strncmp(keyword, "txt_", 4))
{
- if ((ptr = (char *)cupsGetOption(keyword + 4, service->num_txt,
- service->txt)) != NULL)
- strlcpy(tptr, strdup(ptr), sizeof(temp) - (tptr - temp));
+ const char *val = cupsGetOption(keyword + 4, service->num_txt, service->txt);
+ if (val)
+ strlcpy(tptr, val, sizeof(temp) - (size_t)(tptr - temp));
else
*tptr = '\0';
}
}
#ifdef WIN32
+ if (getenv("IPPFIND_DEBUG"))
+ {
+ printf("\nProgram:\n %s\n", args[0]);
+ puts("\nArguments:");
+ for (i = 0; i < num_args; i ++)
+ printf(" %s\n", myargv[i]);
+ puts("\nEnvironment:");
+ for (i = 0; i < myenvc; i ++)
+ printf(" %s\n", myenvp[i]);
+ }
+
status = _spawnvpe(_P_WAIT, args[0], myargv, myenvp);
#else
for (i = 0; i < num_args; i ++)
free(myargv[i]);
+ free(myargv);
+ free(myenvp);
+
/*
* Return whether the program succeeded or crashed...
*/
+ if (getenv("IPPFIND_DEBUG"))
+ {
+#ifdef WIN32
+ printf("Exit Status: %d\n", status);
+#else
+ if (WIFEXITED(status))
+ printf("Exit Status: %d\n", WEXITSTATUS(status));
+ else
+ printf("Terminating Signal: %d\n", WTERMSIG(status));
+#endif /* WIN32 */
+ }
+
return (status == 0);
}
if ((attr = ippFindAttribute(response, "printer-state",
IPP_TAG_ENUM)) != NULL)
- pstate = ippGetInteger(attr, 0);
+ pstate = (ipp_pstate_t)ippGetInteger(attr, 0);
else
pstate = IPP_PSTATE_STOPPED;
i ++, ptr += strlen(ptr))
{
*ptr++ = ',';
- strlcpy(ptr, ippGetString(attr, i, NULL), end - ptr + 1);
+ strlcpy(ptr, ippGetString(attr, i, NULL), (size_t)(end - ptr + 1));
}
}
else
_cupsLangPrintf(stdout, "%s available", service->uri);
httpAddrFreeList(addrlist);
-#ifdef WIN32
- closesocket(sock);
-#else
- close(sock);
-#endif /* WIN32 */
+ httpAddrClose(NULL, sock);
}
else
{
temp->op = op;
temp->invert = invert;
- if (op == IPPFIND_OP_TXT_EXISTS || op == IPPFIND_OP_TXT_REGEX)
- temp->key = (char *)value;
+ if (op == IPPFIND_OP_TXT_EXISTS || op == IPPFIND_OP_TXT_REGEX || op == IPPFIND_OP_NAME_LITERAL)
+ temp->name = (char *)value;
else if (op == IPPFIND_OP_PORT_RANGE)
{
/*
break;
temp->num_args = num_args;
- temp->args = malloc(num_args * sizeof(char *));
- memcpy(temp->args, args, num_args * sizeof(char *));
+ temp->args = malloc((size_t)num_args * sizeof(char *));
+ memcpy(temp->args, args, (size_t)num_args * sizeof(char *));
}
return (temp);
* Only process "add" data...
*/
- if (errorCode != kDNSServiceErr_NoError)
+ (void)sdRef;
+ (void)flags;
+ (void)interfaceIndex;
+ (void)fullName;
+
+ if (errorCode != kDNSServiceErr_NoError)
{
_cupsLangPrintf(stderr, _("ippfind: Unable to browse or resolve: %s"),
dnssd_error_string(errorCode));
service->host = strdup(hostTarget);
service->port = ntohs(port);
+ value = service->host + strlen(service->host) - 1;
+ if (value >= service->host && *value == '.')
+ *value = '\0';
+
/*
* Loop through the TXT key/value pairs and add them to an array...
*/
service->host = strdup(hostTarget);
service->port = port;
+ value = service->host + strlen(service->host) - 1;
+ if (value >= service->host && *value == '.')
+ *value = '\0';
+
/*
* Loop through the TXT key/value pairs and add them to an array...
*/
exit(IPPFIND_EXIT_TRUE);
}
-
-
-/*
- * End of "$Id$".
- */