/*
- * "$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.
*
- * 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"
- * 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/".
+ * Copyright © 2008-2018 by Apple Inc.
*
- * This file is subject to the Apple OS-Developed Software exception.
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more
+ * information.
*/
/*
#define _CUPS_NO_DEPRECATED
#include <cups/cups-private.h>
-#ifdef WIN32
+#ifdef _WIN32
# include <process.h>
# include <sys/timeb.h>
#else
# include <sys/wait.h>
-#endif /* WIN32 */
+#endif /* _WIN32 */
#include <regex.h>
#ifdef HAVE_DNSSD
# include <dns_sd.h>
# define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX
#endif /* HAVE_DNSSD */
-#ifndef WIN32
+#ifndef _WIN32
extern char **environ; /* Process environment variables */
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
/*
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 */
*/
#ifdef HAVE_DNSSD
-static void DNSSD_API 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 DNSSD_API 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)));
+static void DNSSD_API browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) _CUPS_NONNULL(1,5,6,7,8);
+static void DNSSD_API browse_local_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) _CUPS_NONNULL(1,5,6,7,8);
#elif defined(HAVE_AVAHI)
static void browse_callback(AvahiServiceBrowser *browser,
AvahiIfIndex interface,
ippfind_expr_t *expressions);
static int exec_program(ippfind_srv_t *service, int num_args,
char **args);
-static ippfind_srv_t *get_service(cups_array_t *services,
- const char *serviceName,
- const char *regtype,
- const char *replyDomain)
- __attribute__((nonnull(1,2,3,4)));
+static ippfind_srv_t *get_service(cups_array_t *services, const char *serviceName, const char *regtype, const char *replyDomain) _CUPS_NONNULL(1,2,3,4);
static double get_time(void);
static int list_service(ippfind_srv_t *service);
static ippfind_expr_t *new_expr(ippfind_op_t op, int invert,
const char *value, const char *regex,
char **args);
#ifdef HAVE_DNSSD
-static void DNSSD_API resolve_callback(DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *fullName,
- const char *hostTarget, uint16_t port,
- uint16_t txtLen,
- const unsigned char *txtRecord,
- void *context)
- __attribute__((nonnull(1,5,6,9, 10)));
+static void DNSSD_API resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullName, const char *hostTarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context) _CUPS_NONNULL(1,5,6,9, 10);
#elif defined(HAVE_AVAHI)
static int poll_callback(struct pollfd *pollfds,
unsigned int num_pollfds, int timeout,
void *context);
#endif /* HAVE_DNSSD */
static void set_service_uri(ippfind_srv_t *service);
-static void show_usage(void) __attribute__((noreturn));
-static void show_version(void) __attribute__((noreturn));
+static void show_usage(void) _CUPS_NORETURN;
+static void show_version(void) _CUPS_NORETURN;
/*
"IS_REMOTE",
"DOMAIN_REGEX",
"NAME_REGEX",
+ "NAME_LITERAL",
"HOST_REGEX",
"PORT_RANGE",
"PATH_REGEX",
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 ++;
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)
*domain; /* Domain, if any */
strlcpy(buf, search, sizeof(buf));
- if (buf[0] == '_')
+
+ if (!strncmp(buf, "_http._", 7) || !strncmp(buf, "_https._", 8) || !strncmp(buf, "_ipp._", 6) || !strncmp(buf, "_ipps._", 7))
{
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;
service = get_service(services, name, regtype, domain);
+ if (getenv("IPPFIND_DEBUG"))
+ fprintf(stderr, "Resolving name=\"%s\", regtype=\"%s\", domain=\"%s\"\n", name, regtype, domain);
+
#ifdef HAVE_DNSSD
service->ref = dnssd_ref;
err = DNSServiceResolve(&(service->ref),
* Browse for services of the given type...
*/
+ if (getenv("IPPFIND_DEBUG"))
+ fprintf(stderr, "Browsing for regtype=\"%s\", domain=\"%s\"\n", regtype, domain);
+
#ifdef HAVE_DNSSD
DNSServiceRef ref; /* Browse reference */
_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);
}
}
case kDNSServiceErr_PollingMode :
return ("Service polling mode error.");
-#ifndef WIN32
+#ifndef _WIN32
case kDNSServiceErr_Timeout :
return ("Service timeout.");
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
}
# elif defined(HAVE_AVAHI)
eval_expr(ippfind_srv_t *service, /* I - Service */
ippfind_expr_t *expressions) /* I - Expressions */
{
- int logic, /* Logical operation */
- result; /* Result of current expression */
+ ippfind_op_t logic; /* Logical operation */
+ int result; /* Result of current expression */
ippfind_expr_t *expression; /* Current expression */
const char *val; /* TXT value */
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);
int i, /* Looping var */
myenvc, /* Number of environment variables */
status; /* Exit status of program */
-#ifndef WIN32
+#ifndef _WIN32
char program[1024]; /* Program to execute */
int pid; /* Process ID */
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
/*
else if (!strcmp(keyword, "service_path"))
strlcpy(tptr, service->resource, sizeof(temp) - (size_t)(tptr - temp));
else if (!strcmp(keyword, "service_port"))
- strlcpy(tptr, port + 20, sizeof(temp) - (size_t)(tptr - temp));
+ strlcpy(tptr, port + 21, sizeof(temp) - (size_t)(tptr - temp));
else if (!strcmp(keyword, "service_scheme"))
strlcpy(tptr, scheme + 22, sizeof(temp) - (size_t)(tptr - temp));
else if (!strncmp(keyword, "txt_", 4))
myargv[i] = strdup(args[i]);
}
-#ifdef WIN32
+#ifdef _WIN32
if (getenv("IPPFIND_DEBUG"))
{
printf("\nProgram:\n %s\n", args[0]);
while (wait(&status) != pid)
;
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
/*
* Free memory...
if (getenv("IPPFIND_DEBUG"))
{
-#ifdef WIN32
+#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 */
+#endif /* _WIN32 */
}
return (status == 0);
static double
get_time(void)
{
-#ifdef WIN32
+#ifdef _WIN32
struct _timeb curtime; /* Current Windows time */
_ftime(&curtime);
return (0.0);
else
return (curtime.tv_sec + 0.000001 * curtime.tv_usec);
-#endif /* WIN32 */
+#endif /* _WIN32 */
}
ippDelete(response);
httpClose(http);
- _cupsLangPrintf(stdout, "%s %s %s %s", service->uri,
- ippEnumString("printer-state", pstate),
- paccepting ? "accepting-jobs" : "not-accepting-jobs",
- preasons);
+ _cupsLangPrintf(stdout, "%s %s %s %s", service->uri, ippEnumString("printer-state", (int)pstate), paccepting ? "accepting-jobs" : "not-accepting-jobs", preasons);
}
else if (!strncmp(service->regtype, "_http._tcp", 10) ||
!strncmp(service->regtype, "_https._tcp", 11))
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)
{
/*
"... [expression]\n"
" ippfind --help\n"
" ippfind --version"));
- _cupsLangPuts(stderr, "");
_cupsLangPuts(stderr, _("Options:"));
- _cupsLangPuts(stderr, _(" -4 Connect using IPv4."));
- _cupsLangPuts(stderr, _(" -6 Connect using IPv6."));
- _cupsLangPuts(stderr, _(" -T seconds Set the browse timeout in "
- "seconds."));
- _cupsLangPuts(stderr, _(" -V version Set default IPP "
- "version."));
- _cupsLangPuts(stderr, _(" --help Show this help."));
- _cupsLangPuts(stderr, _(" --version Show program version."));
- _cupsLangPuts(stderr, "");
+ _cupsLangPuts(stderr, _("-4 Connect using IPv4"));
+ _cupsLangPuts(stderr, _("-6 Connect using IPv6"));
+ _cupsLangPuts(stderr, _("-T seconds Set the browse timeout in seconds"));
+ _cupsLangPuts(stderr, _("-V version Set default IPP version"));
+ _cupsLangPuts(stderr, _("--version Show program version"));
_cupsLangPuts(stderr, _("Expressions:"));
- _cupsLangPuts(stderr, _(" -P number[-number] Match port to number or range."));
- _cupsLangPuts(stderr, _(" -d regex Match domain to regular expression."));
- _cupsLangPuts(stderr, _(" -h regex Match hostname to regular expression."));
- _cupsLangPuts(stderr, _(" -l List attributes."));
- _cupsLangPuts(stderr, _(" -n regex Match service name to regular expression."));
- _cupsLangPuts(stderr, _(" -p Print URI if true."));
- _cupsLangPuts(stderr, _(" -q Quietly report match via exit code."));
- _cupsLangPuts(stderr, _(" -r True if service is remote."));
- _cupsLangPuts(stderr, _(" -s Print service name if true."));
- _cupsLangPuts(stderr, _(" -t key True if the TXT record contains the key."));
- _cupsLangPuts(stderr, _(" -u regex Match URI to regular expression."));
- _cupsLangPuts(stderr, _(" -x utility [argument ...] ;\n"
- " Execute program if true."));
- _cupsLangPuts(stderr, _(" --domain regex Match domain to regular expression."));
- _cupsLangPuts(stderr, _(" --exec utility [argument ...] ;\n"
- " Execute program if true."));
- _cupsLangPuts(stderr, _(" --host regex Match hostname to regular expression."));
- _cupsLangPuts(stderr, _(" --ls List attributes."));
- _cupsLangPuts(stderr, _(" --local True if service is local."));
- _cupsLangPuts(stderr, _(" --name regex Match service name to regular expression."));
- _cupsLangPuts(stderr, _(" --path regex Match resource path to regular expression."));
- _cupsLangPuts(stderr, _(" --port number[-number] Match port to number or range."));
- _cupsLangPuts(stderr, _(" --print Print URI if true."));
- _cupsLangPuts(stderr, _(" --print-name Print service name if true."));
- _cupsLangPuts(stderr, _(" --quiet Quietly report match via exit code."));
- _cupsLangPuts(stderr, _(" --remote True if service is remote."));
- _cupsLangPuts(stderr, _(" --txt key True if the TXT record contains the key."));
- _cupsLangPuts(stderr, _(" --txt-* regex Match TXT record key to regular expression."));
- _cupsLangPuts(stderr, _(" --uri regex Match URI to regular expression."));
- _cupsLangPuts(stderr, "");
+ _cupsLangPuts(stderr, _("-P number[-number] Match port to number or range"));
+ _cupsLangPuts(stderr, _("-d regex Match domain to regular expression"));
+ _cupsLangPuts(stderr, _("-h regex Match hostname to regular expression"));
+ _cupsLangPuts(stderr, _("-l List attributes"));
+ _cupsLangPuts(stderr, _("-n regex Match service name to regular expression"));
+ _cupsLangPuts(stderr, _("-p Print URI if true"));
+ _cupsLangPuts(stderr, _("-q Quietly report match via exit code"));
+ _cupsLangPuts(stderr, _("-r True if service is remote"));
+ _cupsLangPuts(stderr, _("-s Print service name if true"));
+ _cupsLangPuts(stderr, _("-t key True if the TXT record contains the key"));
+ _cupsLangPuts(stderr, _("-u regex Match URI to regular expression"));
+ _cupsLangPuts(stderr, _("-x utility [argument ...] ;\n"
+ " Execute program if true"));
+ _cupsLangPuts(stderr, _("--domain regex Match domain to regular expression"));
+ _cupsLangPuts(stderr, _("--exec utility [argument ...] ;\n"
+ " Execute program if true"));
+ _cupsLangPuts(stderr, _("--host regex Match hostname to regular expression"));
+ _cupsLangPuts(stderr, _("--ls List attributes"));
+ _cupsLangPuts(stderr, _("--local True if service is local"));
+ _cupsLangPuts(stderr, _("--name regex Match service name to regular expression"));
+ _cupsLangPuts(stderr, _("--path regex Match resource path to regular expression"));
+ _cupsLangPuts(stderr, _("--port number[-number] Match port to number or range"));
+ _cupsLangPuts(stderr, _("--print Print URI if true"));
+ _cupsLangPuts(stderr, _("--print-name Print service name if true"));
+ _cupsLangPuts(stderr, _("--quiet Quietly report match via exit code"));
+ _cupsLangPuts(stderr, _("--remote True if service is remote"));
+ _cupsLangPuts(stderr, _("--txt key True if the TXT record contains the key"));
+ _cupsLangPuts(stderr, _("--txt-* regex Match TXT record key to regular expression"));
+ _cupsLangPuts(stderr, _("--uri regex Match URI to regular expression"));
_cupsLangPuts(stderr, _("Modifiers:"));
- _cupsLangPuts(stderr, _(" ( expressions ) Group expressions."));
- _cupsLangPuts(stderr, _(" ! expression Unary NOT of expression."));
- _cupsLangPuts(stderr, _(" --not expression Unary NOT of expression."));
- _cupsLangPuts(stderr, _(" --false Always false."));
- _cupsLangPuts(stderr, _(" --true Always true."));
- _cupsLangPuts(stderr, _(" expression expression Logical AND."));
- _cupsLangPuts(stderr, _(" expression --and expression\n"
- " Logical AND."));
- _cupsLangPuts(stderr, _(" expression --or expression\n"
- " Logical OR."));
- _cupsLangPuts(stderr, "");
+ _cupsLangPuts(stderr, _("( expressions ) Group expressions"));
+ _cupsLangPuts(stderr, _("! expression Unary NOT of expression"));
+ _cupsLangPuts(stderr, _("--not expression Unary NOT of expression"));
+ _cupsLangPuts(stderr, _("--false Always false"));
+ _cupsLangPuts(stderr, _("--true Always true"));
+ _cupsLangPuts(stderr, _("expression expression Logical AND"));
+ _cupsLangPuts(stderr, _("expression --and expression\n"
+ " Logical AND"));
+ _cupsLangPuts(stderr, _("expression --or expression\n"
+ " Logical OR"));
_cupsLangPuts(stderr, _("Substitutions:"));
- _cupsLangPuts(stderr, _(" {} URI"));
- _cupsLangPuts(stderr, _(" {service_domain} Domain name"));
- _cupsLangPuts(stderr, _(" {service_hostname} Fully-qualified domain name"));
- _cupsLangPuts(stderr, _(" {service_name} Service instance name"));
- _cupsLangPuts(stderr, _(" {service_port} Port number"));
- _cupsLangPuts(stderr, _(" {service_regtype} DNS-SD registration type"));
- _cupsLangPuts(stderr, _(" {service_scheme} URI scheme"));
- _cupsLangPuts(stderr, _(" {service_uri} URI"));
- _cupsLangPuts(stderr, _(" {txt_*} Value of TXT record key"));
- _cupsLangPuts(stderr, "");
+ _cupsLangPuts(stderr, _("{} URI"));
+ _cupsLangPuts(stderr, _("{service_domain} Domain name"));
+ _cupsLangPuts(stderr, _("{service_hostname} Fully-qualified domain name"));
+ _cupsLangPuts(stderr, _("{service_name} Service instance name"));
+ _cupsLangPuts(stderr, _("{service_port} Port number"));
+ _cupsLangPuts(stderr, _("{service_regtype} DNS-SD registration type"));
+ _cupsLangPuts(stderr, _("{service_scheme} URI scheme"));
+ _cupsLangPuts(stderr, _("{service_uri} URI"));
+ _cupsLangPuts(stderr, _("{txt_*} Value of TXT record key"));
_cupsLangPuts(stderr, _("Environment Variables:"));
- _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_DOMAIN Domain name"));
- _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_HOSTNAME\n"
- " Fully-qualified domain name"));
- _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_NAME Service instance name"));
- _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_PORT Port number"));
- _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_REGTYPE DNS-SD registration type"));
- _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_SCHEME URI scheme"));
- _cupsLangPuts(stderr, _(" IPPFIND_SERVICE_URI URI"));
- _cupsLangPuts(stderr, _(" IPPFIND_TXT_* Value of TXT record key"));
+ _cupsLangPuts(stderr, _("IPPFIND_SERVICE_DOMAIN Domain name"));
+ _cupsLangPuts(stderr, _("IPPFIND_SERVICE_HOSTNAME\n"
+ " Fully-qualified domain name"));
+ _cupsLangPuts(stderr, _("IPPFIND_SERVICE_NAME Service instance name"));
+ _cupsLangPuts(stderr, _("IPPFIND_SERVICE_PORT Port number"));
+ _cupsLangPuts(stderr, _("IPPFIND_SERVICE_REGTYPE DNS-SD registration type"));
+ _cupsLangPuts(stderr, _("IPPFIND_SERVICE_SCHEME URI scheme"));
+ _cupsLangPuts(stderr, _("IPPFIND_SERVICE_URI URI"));
+ _cupsLangPuts(stderr, _("IPPFIND_TXT_* Value of TXT record key"));
exit(IPPFIND_EXIT_TRUE);
}
exit(IPPFIND_EXIT_TRUE);
}
-
-
-/*
- * End of "$Id$".
- */