2 * Scheduler notification tester for CUPS.
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 2006-2007 by Easy Software Products.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
11 * Include necessary headers...
14 #include <cups/cups.h>
15 #include <cups/debug-private.h>
16 #include <cups/string-private.h>
18 #include <cups/ipp-private.h> /* TODO: Update so we don't need this */
25 static int terminate
= 0;
32 static void print_attributes(ipp_t
*ipp
, int indent
);
33 static void sigterm_handler(int sig
);
34 static void usage(void) _CUPS_NORETURN
;
38 * 'main()' - Subscribe to the .
42 main(int argc
, /* I - Number of command-line arguments */
43 char *argv
[]) /* I - Command-line arguments */
45 int i
; /* Looping var */
46 const char *uri
; /* URI to use */
47 int num_events
; /* Number of events */
48 const char *events
[100]; /* Events */
49 int subscription_id
, /* notify-subscription-id */
50 sequence_number
, /* notify-sequence-number */
51 interval
; /* Interval between polls */
52 http_t
*http
; /* HTTP connection */
53 ipp_t
*request
, /* IPP request */
54 *response
; /* IPP response */
55 ipp_attribute_t
*attr
; /* Current attribute */
56 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
57 struct sigaction action
; /* Actions for POSIX signals */
58 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
62 * Parse command-line...
68 for (i
= 1; i
< argc
; i
++)
69 if (!strcmp(argv
[i
], "-E"))
70 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED
);
71 else if (!strcmp(argv
[i
], "-e"))
74 if (i
>= argc
|| num_events
>= 100)
77 events
[num_events
] = argv
[i
];
80 else if (!strcmp(argv
[i
], "-h"))
86 cupsSetServer(argv
[i
]);
88 else if (uri
|| strncmp(argv
[i
], "ipp://", 6))
103 * Connect to the server...
106 if ((http
= httpConnectEncrypt(cupsServer(), ippPort(),
107 cupsEncryption())) == NULL
)
109 perror(cupsServer());
114 * Catch CTRL-C and SIGTERM...
117 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
118 sigset(SIGINT
, sigterm_handler
);
119 sigset(SIGTERM
, sigterm_handler
);
120 #elif defined(HAVE_SIGACTION)
121 memset(&action
, 0, sizeof(action
));
123 sigemptyset(&action
.sa_mask
);
124 action
.sa_handler
= sigterm_handler
;
125 sigaction(SIGINT
, &action
, NULL
);
126 sigaction(SIGTERM
, &action
, NULL
);
128 signal(SIGINT
, sigterm_handler
);
129 signal(SIGTERM
, sigterm_handler
);
130 #endif /* HAVE_SIGSET */
133 * Create the subscription...
136 if (strstr(uri
, "/jobs/"))
138 request
= ippNewRequest(IPP_CREATE_JOB_SUBSCRIPTION
);
139 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
143 request
= ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION
);
144 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
,
148 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
151 ippAddStrings(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
, "notify-events",
152 num_events
, NULL
, events
);
153 ippAddString(request
, IPP_TAG_SUBSCRIPTION
, IPP_TAG_KEYWORD
,
154 "notify-pull-method", NULL
, "ippget");
156 response
= cupsDoRequest(http
, request
, uri
);
157 if (cupsLastError() >= IPP_BAD_REQUEST
)
159 fprintf(stderr
, "Create-%s-Subscription: %s\n",
160 strstr(uri
, "/jobs") ? "Job" : "Printer", cupsLastErrorString());
166 if ((attr
= ippFindAttribute(response
, "notify-subscription-id",
167 IPP_TAG_INTEGER
)) == NULL
)
169 fputs("ERROR: No notify-subscription-id in response!\n", stderr
);
175 subscription_id
= attr
->values
[0].integer
;
177 printf("Create-%s-Subscription: notify-subscription-id=%d\n",
178 strstr(uri
, "/jobs/") ? "Job" : "Printer", subscription_id
);
183 * Monitor for events...
191 * Get the current events...
194 printf("\nGet-Notifications(%d,%d):", subscription_id
, sequence_number
);
197 request
= ippNewRequest(IPP_GET_NOTIFICATIONS
);
199 if (strstr(uri
, "/jobs/"))
200 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
202 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
,
205 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
206 "requesting-user-name", NULL
, cupsUser());
208 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
209 "notify-subscription-ids", subscription_id
);
211 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
212 "notify-sequence-numbers", sequence_number
+ 1);
214 response
= cupsDoRequest(http
, request
, uri
);
216 printf(" %s\n", ippErrorString(cupsLastError()));
218 if (cupsLastError() >= IPP_BAD_REQUEST
)
219 fprintf(stderr
, "Get-Notifications: %s\n", cupsLastErrorString());
222 print_attributes(response
, 0);
224 for (attr
= ippFindAttribute(response
, "notify-sequence-number",
227 attr
= ippFindNextAttribute(response
, "notify-sequence-number",
229 if (attr
->values
[0].integer
> sequence_number
)
230 sequence_number
= attr
->values
[0].integer
;
233 if ((attr
= ippFindAttribute(response
, "notify-get-interval",
234 IPP_TAG_INTEGER
)) != NULL
&&
235 attr
->values
[0].integer
> 0)
236 interval
= attr
->values
[0].integer
;
241 sleep((unsigned)interval
);
245 * Cancel the subscription...
248 printf("\nCancel-Subscription:");
251 request
= ippNewRequest(IPP_CANCEL_SUBSCRIPTION
);
253 if (strstr(uri
, "/jobs/"))
254 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
256 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
,
259 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
262 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
263 "notify-subscription-id", subscription_id
);
265 ippDelete(cupsDoRequest(http
, request
, uri
));
267 printf(" %s\n", ippErrorString(cupsLastError()));
269 if (cupsLastError() >= IPP_BAD_REQUEST
)
270 fprintf(stderr
, "Cancel-Subscription: %s\n", cupsLastErrorString());
273 * Close the connection and return...
283 * 'print_attributes()' - Print the attributes in a request...
287 print_attributes(ipp_t
*ipp
, /* I - IPP request */
288 int indent
) /* I - Indentation */
290 int i
; /* Looping var */
291 ipp_tag_t group
; /* Current group */
292 ipp_attribute_t
*attr
; /* Current attribute */
293 _ipp_value_t
*val
; /* Current value */
294 static const char * const tags
[] = /* Value/group tag strings */
297 "operation-attributes-tag",
298 "job-attributes-tag",
299 "end-of-attributes-tag",
300 "printer-attributes-tag",
301 "unsupported-attributes-tag",
302 "subscription-attributes-tag",
303 "event-attributes-tag",
361 "textWithoutLanguage",
362 "nameWithoutLanguage",
374 for (group
= IPP_TAG_ZERO
, attr
= ipp
->attrs
; attr
; attr
= attr
->next
)
376 if ((attr
->group_tag
== IPP_TAG_ZERO
&& indent
<= 8) || !attr
->name
)
378 group
= IPP_TAG_ZERO
;
383 if (group
!= attr
->group_tag
)
385 group
= attr
->group_tag
;
388 for (i
= 4; i
< indent
; i
++)
391 printf("%s:\n\n", tags
[group
]);
394 for (i
= 0; i
< indent
; i
++)
397 printf("%s (", attr
->name
);
398 if (attr
->num_values
> 1)
400 printf("%s):", tags
[attr
->value_tag
]);
402 switch (attr
->value_tag
)
405 case IPP_TAG_INTEGER
:
406 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
407 printf(" %d", val
->integer
);
411 case IPP_TAG_BOOLEAN
:
412 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
413 printf(" %s", val
->boolean
? "true" : "false");
418 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
419 printf(" %d-%d", val
->range
.lower
, val
->range
.upper
);
425 char vstring
[256]; /* Formatted time */
427 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
428 printf(" (%s)", _cupsStrDate(vstring
, sizeof(vstring
), ippDateToTime(val
->date
)));
433 case IPP_TAG_RESOLUTION
:
434 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
435 printf(" %dx%d%s", val
->resolution
.xres
, val
->resolution
.yres
,
436 val
->resolution
.units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
440 case IPP_TAG_STRING
:
441 case IPP_TAG_TEXTLANG
:
442 case IPP_TAG_NAMELANG
:
445 case IPP_TAG_KEYWORD
:
447 case IPP_TAG_URISCHEME
:
448 case IPP_TAG_CHARSET
:
449 case IPP_TAG_LANGUAGE
:
450 case IPP_TAG_MIMETYPE
:
451 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
452 printf(" \"%s\"", val
->string
.text
);
456 case IPP_TAG_BEGIN_COLLECTION
:
459 for (i
= 0, val
= attr
->values
; i
< attr
->num_values
; i
++, val
++)
463 print_attributes(val
->collection
, indent
+ 4);
468 printf("UNKNOWN (%d values)\n", attr
->num_values
);
476 * 'sigterm_handler()' - Flag when the user hits CTRL-C...
480 sigterm_handler(int sig
) /* I - Signal number (unused) */
489 * 'usage()' - Show program usage...
495 puts("Usage: testsub [-E] [-e event ... -e eventN] [-h hostname] URI");