in tools/ippfind.c [152:1474]
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 /* HAVE_DNSSD */
static int compare_services(ippfind_srv_t *a, ippfind_srv_t *b);
static const char *dnssd_error_string(int error);
static int eval_expr(ippfind_srv_t *service,
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) _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) _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);
static void resolve_callback(AvahiServiceResolver *res,
AvahiIfIndex interface,
AvahiProtocol protocol,
AvahiResolverEvent event,
const char *serviceName,
const char *regtype,
const char *replyDomain,
const char *host_name,
const AvahiAddress *address,
uint16_t port,
AvahiStringList *txt,
AvahiLookupResultFlags flags,
void *context);
#endif /* HAVE_DNSSD */
static void set_service_uri(ippfind_srv_t *service);
static void show_usage(void) _CUPS_NORETURN;
static void show_version(void) _CUPS_NORETURN;
/*
* 'main()' - Browse for printers.
*/
int /* O - Exit status */
main(int argc, /* I - Number of command-line args */
char *argv[]) /* I - Command-line arguments */
{
int i, /* Looping var */
have_output = 0,/* Have output expression */
status = IPPFIND_EXIT_FALSE;
/* Exit status */
const char *opt, /* Option character */
*search; /* Current browse/resolve string */
cups_array_t *searches; /* Things to browse/resolve */
cups_array_t *services; /* Service array */
ippfind_srv_t *service; /* Current service */
ippfind_expr_t *expressions = NULL,
/* Expression tree */
*temp = NULL, /* New expression */
*parent = NULL, /* Parent expression */
*current = NULL,/* Current expression */
*parens[100]; /* Markers for parenthesis */
int num_parens = 0; /* Number of parenthesis */
ippfind_op_t logic = IPPFIND_OP_AND;
/* Logic for next expression */
int invert = 0; /* Invert expression? */
int err; /* DNS-SD error */
#ifdef HAVE_DNSSD
fd_set sinput; /* Input set for select() */
struct timeval stimeout; /* Timeout for select() */
#endif /* HAVE_DNSSD */
double endtime; /* End time */
static const char * const ops[] = /* Node operation names */
{
"NONE",
"AND",
"OR",
"TRUE",
"FALSE",
"IS_LOCAL",
"IS_REMOTE",
"DOMAIN_REGEX",
"NAME_REGEX",
"NAME_LITERAL",
"HOST_REGEX",
"PORT_RANGE",
"PATH_REGEX",
"TXT_EXISTS",
"TXT_REGEX",
"URI_REGEX",
"EXEC",
"LIST",
"PRINT_NAME",
"PRINT_URI",
"QUIET"
};
/*
* Initialize the locale...
*/
_cupsSetLocale(argv);
/*
* Create arrays to track services and things we want to browse/resolve...
*/
searches = cupsArrayNew(NULL, NULL);
services = cupsArrayNew((cups_array_func_t)compare_services, NULL);
/*
* 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] == '-')
{
if (argv[i][1] == '-')
{
/*
* Parse --option options...
*/
if (!strcmp(argv[i], "--and"))
{
if (logic == IPPFIND_OP_OR)
{
_cupsLangPuts(stderr, _("ippfind: Cannot use --and after --or."));
show_usage();
}
if (!current)
{
_cupsLangPuts(stderr,
_("ippfind: Missing expression before \"--and\"."));
show_usage();
}
temp = NULL;
}
else if (!strcmp(argv[i], "--domain"))
{
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing regular expression after %s."),
"--domain");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_DOMAIN_REGEX, invert, NULL, argv[i],
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
else if (!strcmp(argv[i], "--exec"))
{
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr, _("ippfind: Expected program after %s."),
"--exec");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_EXEC, invert, NULL, NULL,
argv + i)) == NULL)
return (IPPFIND_EXIT_MEMORY);
while (i < argc)
if (!strcmp(argv[i], ";"))
break;
else
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr, _("ippfind: Expected semi-colon after %s."),
"--exec");
show_usage();
}
have_output = 1;
}
else if (!strcmp(argv[i], "--false"))
{
if ((temp = new_expr(IPPFIND_OP_FALSE, invert, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
else if (!strcmp(argv[i], "--help"))
{
show_usage();
}
else if (!strcmp(argv[i], "--host"))
{
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing regular expression after %s."),
"--host");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_HOST_REGEX, invert, NULL, argv[i],
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
else if (!strcmp(argv[i], "--ls"))
{
if ((temp = new_expr(IPPFIND_OP_LIST, invert, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
have_output = 1;
}
else if (!strcmp(argv[i], "--local"))
{
if ((temp = new_expr(IPPFIND_OP_IS_LOCAL, invert, NULL, NULL,
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 ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing regular expression after %s."),
"--name");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_NAME_REGEX, invert, NULL, argv[i],
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
else if (!strcmp(argv[i], "--not"))
{
invert = 1;
}
else if (!strcmp(argv[i], "--or"))
{
if (!current)
{
_cupsLangPuts(stderr,
_("ippfind: Missing expression before \"--or\"."));
show_usage();
}
logic = IPPFIND_OP_OR;
if (parent && parent->op == IPPFIND_OP_OR)
{
/*
* Already setup to do "foo --or bar --or baz"...
*/
temp = NULL;
}
else if (!current->prev && parent)
{
/*
* Change parent node into an OR node...
*/
parent->op = IPPFIND_OP_OR;
temp = NULL;
}
else if (!current->prev)
{
/*
* Need to group "current" in a new OR node...
*/
if ((temp = new_expr(IPPFIND_OP_OR, 0, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
temp->parent = parent;
temp->child = current;
current->parent = temp;
if (parent)
parent->child = temp;
else
expressions = temp;
parent = temp;
temp = NULL;
}
else
{
/*
* Need to group previous expressions in an AND node, and then
* put that in an OR node...
*/
if ((temp = new_expr(IPPFIND_OP_AND, 0, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
while (current->prev)
{
current->parent = temp;
current = current->prev;
}
current->parent = temp;
temp->child = current;
current = temp;
if ((temp = new_expr(IPPFIND_OP_OR, 0, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
temp->parent = parent;
current->parent = temp;
if (parent)
parent->child = temp;
else
expressions = temp;
parent = temp;
temp = NULL;
}
}
else if (!strcmp(argv[i], "--path"))
{
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing regular expression after %s."),
"--path");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_PATH_REGEX, invert, NULL, argv[i],
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
else if (!strcmp(argv[i], "--port"))
{
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Expected port range after %s."),
"--port");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_PORT_RANGE, invert, argv[i], NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
else if (!strcmp(argv[i], "--print"))
{
if ((temp = new_expr(IPPFIND_OP_PRINT_URI, invert, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
have_output = 1;
}
else if (!strcmp(argv[i], "--print-name"))
{
if ((temp = new_expr(IPPFIND_OP_PRINT_NAME, invert, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
have_output = 1;
}
else if (!strcmp(argv[i], "--quiet"))
{
if ((temp = new_expr(IPPFIND_OP_QUIET, invert, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
have_output = 1;
}
else if (!strcmp(argv[i], "--remote"))
{
if ((temp = new_expr(IPPFIND_OP_IS_REMOTE, invert, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
else if (!strcmp(argv[i], "--true"))
{
if ((temp = new_expr(IPPFIND_OP_TRUE, invert, NULL, argv[i],
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
else if (!strcmp(argv[i], "--txt"))
{
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr, _("ippfind: Expected key name after %s."),
"--txt");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_TXT_EXISTS, invert, argv[i], NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
else if (!strncmp(argv[i], "--txt-", 6))
{
const char *key = argv[i] + 6;/* TXT key */
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing regular expression after %s."),
argv[i - 1]);
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_TXT_REGEX, invert, key, argv[i],
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
else if (!strcmp(argv[i], "--uri"))
{
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing regular expression after %s."),
"--uri");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_URI_REGEX, invert, NULL, argv[i],
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
}
else if (!strcmp(argv[i], "--version"))
{
show_version();
}
else
{
_cupsLangPrintf(stderr, _("%s: Unknown option \"%s\"."),
"ippfind", argv[i]);
show_usage();
}
if (temp)
{
/*
* Add new expression...
*/
if (logic == IPPFIND_OP_AND &&
current && current->prev &&
parent && parent->op != IPPFIND_OP_AND)
{
/*
* Need to re-group "current" in a new AND node...
*/
ippfind_expr_t *tempand; /* Temporary AND node */
if ((tempand = new_expr(IPPFIND_OP_AND, 0, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
/*
* Replace "current" with new AND node at the end of this list...
*/
current->prev->next = tempand;
tempand->prev = current->prev;
tempand->parent = parent;
/*
* Add "current to the new AND node...
*/
tempand->child = current;
current->parent = tempand;
current->prev = NULL;
parent = tempand;
}
/*
* Add the new node at current level...
*/
temp->parent = parent;
temp->prev = current;
if (current)
current->next = temp;
else if (parent)
parent->child = temp;
else
expressions = temp;
current = temp;
invert = 0;
logic = IPPFIND_OP_AND;
temp = NULL;
}
}
else
{
/*
* Parse -o options
*/
for (opt = argv[i] + 1; *opt; opt ++)
{
switch (*opt)
{
case '4' :
address_family = AF_INET;
break;
case '6' :
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)
{
_cupsLangPrintf(stderr,
_("ippfind: Expected port range after %s."),
"-P");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_PORT_RANGE, invert, argv[i],
NULL, NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
break;
case 'T' :
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("%s: Missing timeout for \"-T\"."),
"ippfind");
show_usage();
}
bonjour_timeout = atof(argv[i]);
break;
case 'V' :
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("%s: Missing version for \"-V\"."),
"ippfind");
show_usage();
}
if (!strcmp(argv[i], "1.1"))
ipp_version = 11;
else if (!strcmp(argv[i], "2.0"))
ipp_version = 20;
else if (!strcmp(argv[i], "2.1"))
ipp_version = 21;
else if (!strcmp(argv[i], "2.2"))
ipp_version = 22;
else
{
_cupsLangPrintf(stderr, _("%s: Bad version %s for \"-V\"."),
"ippfind", argv[i]);
show_usage();
}
break;
case 'd' :
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing regular expression after "
"%s."), "-d");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_DOMAIN_REGEX, invert, NULL,
argv[i], NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
break;
case 'h' :
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing regular expression after "
"%s."), "-h");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_HOST_REGEX, invert, NULL,
argv[i], NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
break;
case 'l' :
if ((temp = new_expr(IPPFIND_OP_LIST, invert, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
have_output = 1;
break;
case 'n' :
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing regular expression after "
"%s."), "-n");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_NAME_REGEX, invert, NULL,
argv[i], NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
break;
case 'p' :
if ((temp = new_expr(IPPFIND_OP_PRINT_URI, invert, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
have_output = 1;
break;
case 'q' :
if ((temp = new_expr(IPPFIND_OP_QUIET, invert, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
have_output = 1;
break;
case 'r' :
if ((temp = new_expr(IPPFIND_OP_IS_REMOTE, invert, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
break;
case 's' :
if ((temp = new_expr(IPPFIND_OP_PRINT_NAME, invert, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
have_output = 1;
break;
case 't' :
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing key name after %s."),
"-t");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_TXT_EXISTS, invert, argv[i],
NULL, NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
break;
case 'u' :
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing regular expression after "
"%s."), "-u");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_URI_REGEX, invert, NULL,
argv[i], NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
break;
case 'x' :
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing program after %s."),
"-x");
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_EXEC, invert, NULL, NULL,
argv + i)) == NULL)
return (IPPFIND_EXIT_MEMORY);
while (i < argc)
if (!strcmp(argv[i], ";"))
break;
else
i ++;
if (i >= argc)
{
_cupsLangPrintf(stderr,
_("ippfind: Missing semi-colon after %s."),
"-x");
show_usage();
}
have_output = 1;
break;
default :
_cupsLangPrintf(stderr, _("%s: Unknown option \"-%c\"."),
"ippfind", *opt);
show_usage();
}
if (temp)
{
/*
* Add new expression...
*/
if (logic == IPPFIND_OP_AND &&
current && current->prev &&
parent && parent->op != IPPFIND_OP_AND)
{
/*
* Need to re-group "current" in a new AND node...
*/
ippfind_expr_t *tempand; /* Temporary AND node */
if ((tempand = new_expr(IPPFIND_OP_AND, 0, NULL, NULL,
NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
/*
* Replace "current" with new AND node at the end of this list...
*/
current->prev->next = tempand;
tempand->prev = current->prev;
tempand->parent = parent;
/*
* Add "current to the new AND node...
*/
tempand->child = current;
current->parent = tempand;
current->prev = NULL;
parent = tempand;
}
/*
* Add the new node at current level...
*/
temp->parent = parent;
temp->prev = current;
if (current)
current->next = temp;
else if (parent)
parent->child = temp;
else
expressions = temp;
current = temp;
invert = 0;
logic = IPPFIND_OP_AND;
temp = NULL;
}
}
}
}
else if (!strcmp(argv[i], "("))
{
if (num_parens >= 100)
{
_cupsLangPuts(stderr, _("ippfind: Too many parenthesis."));
show_usage();
}
if ((temp = new_expr(IPPFIND_OP_AND, invert, NULL, NULL, NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
parens[num_parens++] = temp;
if (current)
{
temp->parent = current->parent;
current->next = temp;
temp->prev = current;
}
else
expressions = temp;
parent = temp;
current = NULL;
invert = 0;
logic = IPPFIND_OP_AND;
}
else if (!strcmp(argv[i], ")"))
{
if (num_parens <= 0)
{
_cupsLangPuts(stderr, _("ippfind: Missing open parenthesis."));
show_usage();
}
current = parens[--num_parens];
parent = current->parent;
invert = 0;
logic = IPPFIND_OP_AND;
}
else if (!strcmp(argv[i], "!"))
{
invert = 1;
}
else
{
/*
* _regtype._tcp[,subtype][.domain]
*
* OR
*
* service-name[._regtype._tcp[.domain]]
*/
cupsArrayAdd(searches, argv[i]);
}
}
if (num_parens > 0)
{
_cupsLangPuts(stderr, _("ippfind: Missing close parenthesis."));
show_usage();
}
if (!have_output)
{
/*
* Add an implicit --print-uri to the end...
*/
if ((temp = new_expr(IPPFIND_OP_PRINT_URI, 0, NULL, NULL, NULL)) == NULL)
return (IPPFIND_EXIT_MEMORY);
if (current)
{
while (current->parent)
current = current->parent;
current->next = temp;
temp->prev = current;
}
else
expressions = temp;
}
if (cupsArrayCount(searches) == 0)
{
/*
* Add an implicit browse for IPP printers ("_ipp._tcp")...
*/
cupsArrayAdd(searches, "_ipp._tcp");
}
if (getenv("IPPFIND_DEBUG"))
{
int indent = 4; /* Indentation */
puts("Expression tree:");
current = expressions;
while (current)
{
/*
* Print the current node...
*/
printf("%*s%s%s\n", indent, "", current->invert ? "!" : "",
ops[current->op]);
/*
* Advance to the next node...
*/
if (current->child)
{
current = current->child;
indent += 4;
}
else if (current->next)
current = current->next;
else if (current->parent)
{
while (current->parent)
{
indent -= 4;
current = current->parent;
if (current->next)
break;
}
current = current->next;
}
else
current = NULL;
}
puts("\nSearch items:");
for (search = (const char *)cupsArrayFirst(searches);
search;
search = (const char *)cupsArrayNext(searches))
printf(" %s\n", search);
}
/*
* Start up browsing/resolving...
*/
#ifdef HAVE_DNSSD
if ((err = DNSServiceCreateConnection(&dnssd_ref)) != kDNSServiceErr_NoError)
{
_cupsLangPrintf(stderr, _("ippfind: Unable to use Bonjour: %s"),
dnssd_error_string(err));
return (IPPFIND_EXIT_BONJOUR);
}
#elif defined(HAVE_AVAHI)
if ((avahi_poll = avahi_simple_poll_new()) == NULL)
{
_cupsLangPrintf(stderr, _("ippfind: Unable to use Bonjour: %s"),
strerror(errno));
return (IPPFIND_EXIT_BONJOUR);
}
avahi_simple_poll_set_func(avahi_poll, poll_callback, NULL);
avahi_client = avahi_client_new(avahi_simple_poll_get(avahi_poll),
0, client_callback, avahi_poll, &err);
if (!avahi_client)
{
_cupsLangPrintf(stderr, _("ippfind: Unable to use Bonjour: %s"),
dnssd_error_string(err));
return (IPPFIND_EXIT_BONJOUR);
}
#endif /* HAVE_DNSSD */
for (search = (const char *)cupsArrayFirst(searches);
search;
search = (const char *)cupsArrayNext(searches))
{
char buf[1024], /* Full name string */
*name = NULL, /* Service instance name */
*regtype, /* Registration type */
*domain; /* Domain, if any */
strlcpy(buf, search, sizeof(buf));
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)
{
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;
}
}
if (!*domain)
domain = NULL;
if (name)
{
/*
* Resolve the given service instance name, regtype, and domain...
*/
if (!domain)
domain = "local.";
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),
kDNSServiceFlagsShareConnection, 0, name,
regtype, domain, resolve_callback,
service);
#elif defined(HAVE_AVAHI)
service->ref = avahi_service_resolver_new(avahi_client, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC, name,
regtype, domain,
AVAHI_PROTO_UNSPEC, 0,
resolve_callback, service);
if (service->ref)
err = 0;
else
err = avahi_client_errno(avahi_client);
#endif /* HAVE_DNSSD */
}
else
{
/*
* 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 */
ref = dnssd_ref;
err = DNSServiceBrowse(&ref, kDNSServiceFlagsShareConnection, 0, regtype,
domain, browse_callback, services);
if (!err)
{
ref = dnssd_ref;
err = DNSServiceBrowse(&ref, kDNSServiceFlagsShareConnection,
kDNSServiceInterfaceIndexLocalOnly, regtype,
domain, browse_local_callback, services);
}
#elif defined(HAVE_AVAHI)
char *subtype, /* Sub-type, if any */
subtype_buf[256]; /* Sub-type buffer */
if ((subtype = strstr(regtype, ",_")) != NULL)
{
*subtype++ = '\0';
snprintf(subtype_buf, sizeof(subtype_buf), "%s._sub.%s", subtype, regtype);
regtype = subtype_buf;
}
if (avahi_service_browser_new(avahi_client, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC, regtype, domain, 0,
browse_callback, services))
err = 0;
else
err = avahi_client_errno(avahi_client);
#endif /* HAVE_DNSSD */
}
if (err)
{
_cupsLangPrintf(stderr, _("ippfind: Unable to browse or resolve: %s"),
dnssd_error_string(err));
return (IPPFIND_EXIT_BONJOUR);
}
}
/*
* Process browse/resolve requests...
*/
if (bonjour_timeout > 1.0)
endtime = get_time() + bonjour_timeout;
else
endtime = get_time() + 300.0;
while (get_time() < endtime)
{
int process = 0; /* Process services? */
#ifdef HAVE_DNSSD
int fd = DNSServiceRefSockFD(dnssd_ref);
/* File descriptor for DNS-SD */
FD_ZERO(&sinput);
FD_SET(fd, &sinput);
stimeout.tv_sec = 0;
stimeout.tv_usec = 500000;
if (select(fd + 1, &sinput, NULL, NULL, &stimeout) < 0)
continue;
if (FD_ISSET(fd, &sinput))
{
/*
* Process responses...
*/
DNSServiceProcessResult(dnssd_ref);
}
else
{
/*
* Time to process services...
*/
process = 1;
}
#elif defined(HAVE_AVAHI)
avahi_got_data = 0;
if (avahi_simple_poll_iterate(avahi_poll, 500) > 0)
{
/*
* We've been told to exit the loop. Perhaps the connection to
* Avahi failed.
*/
return (IPPFIND_EXIT_BONJOUR);
}
if (!avahi_got_data)
{
/*
* Time to process services...
*/
process = 1;
}
#endif /* HAVE_DNSSD */
if (process)
{
/*
* Process any services that we have found...
*/
int active = 0, /* Number of active resolves */
resolved = 0, /* Number of resolved services */
processed = 0; /* Number of processed services */
for (service = (ippfind_srv_t *)cupsArrayFirst(services);
service;
service = (ippfind_srv_t *)cupsArrayNext(services))
{
if (service->is_processed)
processed ++;
if (service->is_resolved)
resolved ++;
if (!service->ref && !service->is_resolved)
{
/*
* Found a service, now resolve it (but limit to 50 active resolves...)
*/
if (active < 50)
{
#ifdef HAVE_DNSSD
service->ref = dnssd_ref;
err = DNSServiceResolve(&(service->ref),
kDNSServiceFlagsShareConnection, 0,
service->name, service->regtype,
service->domain, resolve_callback,
service);
#elif defined(HAVE_AVAHI)
service->ref = avahi_service_resolver_new(avahi_client,
AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC,
service->name,
service->regtype,
service->domain,
AVAHI_PROTO_UNSPEC, 0,
resolve_callback,
service);
if (service->ref)
err = 0;
else
err = avahi_client_errno(avahi_client);
#endif /* HAVE_DNSSD */
if (err)
{
_cupsLangPrintf(stderr,
_("ippfind: Unable to browse or resolve: %s"),
dnssd_error_string(err));
return (IPPFIND_EXIT_BONJOUR);
}
active ++;
}
}
else if (service->is_resolved && !service->is_processed)
{
/*
* Resolved, not process this service against the expressions...
*/
if (service->ref)
{
#ifdef HAVE_DNSSD
DNSServiceRefDeallocate(service->ref);
#else
avahi_service_resolver_free(service->ref);
#endif /* HAVE_DNSSD */
service->ref = NULL;
}
if (eval_expr(service, expressions))
status = IPPFIND_EXIT_TRUE;
service->is_processed = 1;
}
else if (service->ref)
active ++;
}
/*
* If we have processed all services we have discovered, then we are done.
*/
if (processed == cupsArrayCount(services) && bonjour_timeout <= 1.0)
break;
}
}
if (bonjour_error)
return (IPPFIND_EXIT_BONJOUR);
else
return (status);
}