blob: 19d9dffce9aba804d810e9846f0ab558701a0992 [file] [log] [blame]
/*
* Scheduler notification tester for CUPS.
*
* Copyright 2007-2014 by Apple Inc.
* Copyright 2006-2007 by Easy Software Products.
*
* Licensed under Apache License v2.0. See the file "LICENSE" for more information.
*/
/*
* Include necessary headers...
*/
#include <cups/cups.h>
#include <cups/debug-private.h>
#include <cups/string-private.h>
#include <signal.h>
#include <cups/ipp-private.h> /* TODO: Update so we don't need this */
/*
* Local globals...
*/
static int terminate = 0;
/*
* Local functions...
*/
static void print_attributes(ipp_t *ipp, int indent);
static void sigterm_handler(int sig);
static void usage(void) _CUPS_NORETURN;
/*
* 'main()' - Subscribe to the .
*/
int
main(int argc, /* I - Number of command-line arguments */
char *argv[]) /* I - Command-line arguments */
{
int i; /* Looping var */
const char *uri; /* URI to use */
int num_events; /* Number of events */
const char *events[100]; /* Events */
int subscription_id, /* notify-subscription-id */
sequence_number, /* notify-sequence-number */
interval; /* Interval between polls */
http_t *http; /* HTTP connection */
ipp_t *request, /* IPP request */
*response; /* IPP response */
ipp_attribute_t *attr; /* Current attribute */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action; /* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
/*
* Parse command-line...
*/
num_events = 0;
uri = NULL;
for (i = 1; i < argc; i ++)
if (!strcmp(argv[i], "-E"))
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
else if (!strcmp(argv[i], "-e"))
{
i ++;
if (i >= argc || num_events >= 100)
usage();
events[num_events] = argv[i];
num_events ++;
}
else if (!strcmp(argv[i], "-h"))
{
i ++;
if (i >= argc)
usage();
cupsSetServer(argv[i]);
}
else if (uri || strncmp(argv[i], "ipp://", 6))
usage();
else
uri = argv[i];
if (!uri)
usage();
if (num_events == 0)
{
events[0] = "all";
num_events = 1;
}
/*
* Connect to the server...
*/
if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption())) == NULL)
{
perror(cupsServer());
return (1);
}
/*
* Catch CTRL-C and SIGTERM...
*/
#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
sigset(SIGINT, sigterm_handler);
sigset(SIGTERM, sigterm_handler);
#elif defined(HAVE_SIGACTION)
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_handler = sigterm_handler;
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
#else
signal(SIGINT, sigterm_handler);
signal(SIGTERM, sigterm_handler);
#endif /* HAVE_SIGSET */
/*
* Create the subscription...
*/
if (strstr(uri, "/jobs/"))
{
request = ippNewRequest(IPP_CREATE_JOB_SUBSCRIPTION);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
}
else
{
request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
uri);
}
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
NULL, cupsUser());
ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events",
num_events, NULL, events);
ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
"notify-pull-method", NULL, "ippget");
response = cupsDoRequest(http, request, uri);
if (cupsLastError() >= IPP_BAD_REQUEST)
{
fprintf(stderr, "Create-%s-Subscription: %s\n",
strstr(uri, "/jobs") ? "Job" : "Printer", cupsLastErrorString());
ippDelete(response);
httpClose(http);
return (1);
}
if ((attr = ippFindAttribute(response, "notify-subscription-id",
IPP_TAG_INTEGER)) == NULL)
{
fputs("ERROR: No notify-subscription-id in response!\n", stderr);
ippDelete(response);
httpClose(http);
return (1);
}
subscription_id = attr->values[0].integer;
printf("Create-%s-Subscription: notify-subscription-id=%d\n",
strstr(uri, "/jobs/") ? "Job" : "Printer", subscription_id);
ippDelete(response);
/*
* Monitor for events...
*/
sequence_number = 0;
while (!terminate)
{
/*
* Get the current events...
*/
printf("\nGet-Notifications(%d,%d):", subscription_id, sequence_number);
fflush(stdout);
request = ippNewRequest(IPP_GET_NOTIFICATIONS);
if (strstr(uri, "/jobs/"))
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
else
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
uri);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
"requesting-user-name", NULL, cupsUser());
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
"notify-subscription-ids", subscription_id);
if (sequence_number)
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
"notify-sequence-numbers", sequence_number + 1);
response = cupsDoRequest(http, request, uri);
printf(" %s\n", ippErrorString(cupsLastError()));
if (cupsLastError() >= IPP_BAD_REQUEST)
fprintf(stderr, "Get-Notifications: %s\n", cupsLastErrorString());
else if (response)
{
print_attributes(response, 0);
for (attr = ippFindAttribute(response, "notify-sequence-number",
IPP_TAG_INTEGER);
attr;
attr = ippFindNextAttribute(response, "notify-sequence-number",
IPP_TAG_INTEGER))
if (attr->values[0].integer > sequence_number)
sequence_number = attr->values[0].integer;
}
if ((attr = ippFindAttribute(response, "notify-get-interval",
IPP_TAG_INTEGER)) != NULL &&
attr->values[0].integer > 0)
interval = attr->values[0].integer;
else
interval = 5;
ippDelete(response);
sleep((unsigned)interval);
}
/*
* Cancel the subscription...
*/
printf("\nCancel-Subscription:");
fflush(stdout);
request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION);
if (strstr(uri, "/jobs/"))
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
else
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
uri);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
NULL, cupsUser());
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
"notify-subscription-id", subscription_id);
ippDelete(cupsDoRequest(http, request, uri));
printf(" %s\n", ippErrorString(cupsLastError()));
if (cupsLastError() >= IPP_BAD_REQUEST)
fprintf(stderr, "Cancel-Subscription: %s\n", cupsLastErrorString());
/*
* Close the connection and return...
*/
httpClose(http);
return (0);
}
/*
* 'print_attributes()' - Print the attributes in a request...
*/
static void
print_attributes(ipp_t *ipp, /* I - IPP request */
int indent) /* I - Indentation */
{
int i; /* Looping var */
ipp_tag_t group; /* Current group */
ipp_attribute_t *attr; /* Current attribute */
_ipp_value_t *val; /* Current value */
static const char * const tags[] = /* Value/group tag strings */
{
"reserved-00",
"operation-attributes-tag",
"job-attributes-tag",
"end-of-attributes-tag",
"printer-attributes-tag",
"unsupported-attributes-tag",
"subscription-attributes-tag",
"event-attributes-tag",
"reserved-08",
"reserved-09",
"reserved-0A",
"reserved-0B",
"reserved-0C",
"reserved-0D",
"reserved-0E",
"reserved-0F",
"unsupported",
"default",
"unknown",
"no-value",
"reserved-14",
"not-settable",
"delete-attr",
"admin-define",
"reserved-18",
"reserved-19",
"reserved-1A",
"reserved-1B",
"reserved-1C",
"reserved-1D",
"reserved-1E",
"reserved-1F",
"reserved-20",
"integer",
"boolean",
"enum",
"reserved-24",
"reserved-25",
"reserved-26",
"reserved-27",
"reserved-28",
"reserved-29",
"reserved-2a",
"reserved-2b",
"reserved-2c",
"reserved-2d",
"reserved-2e",
"reserved-2f",
"octetString",
"dateTime",
"resolution",
"rangeOfInteger",
"begCollection",
"textWithLanguage",
"nameWithLanguage",
"endCollection",
"reserved-38",
"reserved-39",
"reserved-3a",
"reserved-3b",
"reserved-3c",
"reserved-3d",
"reserved-3e",
"reserved-3f",
"reserved-40",
"textWithoutLanguage",
"nameWithoutLanguage",
"reserved-43",
"keyword",
"uri",
"uriScheme",
"charset",
"naturalLanguage",
"mimeMediaType",
"memberName"
};
for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next)
{
if ((attr->group_tag == IPP_TAG_ZERO && indent <= 8) || !attr->name)
{
group = IPP_TAG_ZERO;
putchar('\n');
continue;
}
if (group != attr->group_tag)
{
group = attr->group_tag;
putchar('\n');
for (i = 4; i < indent; i ++)
putchar(' ');
printf("%s:\n\n", tags[group]);
}
for (i = 0; i < indent; i ++)
putchar(' ');
printf("%s (", attr->name);
if (attr->num_values > 1)
printf("1setOf ");
printf("%s):", tags[attr->value_tag]);
switch (attr->value_tag)
{
case IPP_TAG_ENUM :
case IPP_TAG_INTEGER :
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
printf(" %d", val->integer);
putchar('\n');
break;
case IPP_TAG_BOOLEAN :
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
printf(" %s", val->boolean ? "true" : "false");
putchar('\n');
break;
case IPP_TAG_RANGE :
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
printf(" %d-%d", val->range.lower, val->range.upper);
putchar('\n');
break;
case IPP_TAG_DATE :
{
char vstring[256]; /* Formatted time */
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
printf(" (%s)", _cupsStrDate(vstring, sizeof(vstring), ippDateToTime(val->date)));
}
putchar('\n');
break;
case IPP_TAG_RESOLUTION :
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
printf(" %dx%d%s", val->resolution.xres, val->resolution.yres,
val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
putchar('\n');
break;
case IPP_TAG_STRING :
case IPP_TAG_TEXTLANG :
case IPP_TAG_NAMELANG :
case IPP_TAG_TEXT :
case IPP_TAG_NAME :
case IPP_TAG_KEYWORD :
case IPP_TAG_URI :
case IPP_TAG_URISCHEME :
case IPP_TAG_CHARSET :
case IPP_TAG_LANGUAGE :
case IPP_TAG_MIMETYPE :
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
printf(" \"%s\"", val->string.text);
putchar('\n');
break;
case IPP_TAG_BEGIN_COLLECTION :
putchar('\n');
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
{
if (i)
putchar('\n');
print_attributes(val->collection, indent + 4);
}
break;
default :
printf("UNKNOWN (%d values)\n", attr->num_values);
break;
}
}
}
/*
* 'sigterm_handler()' - Flag when the user hits CTRL-C...
*/
static void
sigterm_handler(int sig) /* I - Signal number (unused) */
{
(void)sig;
terminate = 1;
}
/*
* 'usage()' - Show program usage...
*/
static void
usage(void)
{
puts("Usage: testsub [-E] [-e event ... -e eventN] [-h hostname] URI");
exit(0);
}