]>
Commit | Line | Data |
---|---|---|
07725fee | 1 | /* |
7e86f2f6 | 2 | * Scheduler notification tester for CUPS. |
07725fee | 3 | * |
7e86f2f6 MS |
4 | * Copyright 2007-2014 by Apple Inc. |
5 | * Copyright 2006-2007 by Easy Software Products. | |
07725fee | 6 | * |
7e86f2f6 MS |
7 | * These coded instructions, statements, and computer programs are the |
8 | * property of Apple Inc. and are protected by Federal copyright | |
9 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
10 | * which should have been included with this file. If this file is | |
11 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
07725fee | 12 | */ |
13 | ||
14 | /* | |
15 | * Include necessary headers... | |
16 | */ | |
17 | ||
18 | #include <cups/cups.h> | |
71e16022 MS |
19 | #include <cups/debug-private.h> |
20 | #include <cups/string-private.h> | |
07725fee | 21 | #include <signal.h> |
a2326b5b | 22 | #include <cups/ipp-private.h> /* TODO: Update so we don't need this */ |
07725fee | 23 | |
24 | ||
25 | /* | |
26 | * Local globals... | |
27 | */ | |
28 | ||
29 | static int terminate = 0; | |
30 | ||
31 | ||
32 | /* | |
33 | * Local functions... | |
34 | */ | |
35 | ||
f899b121 | 36 | static void print_attributes(ipp_t *ipp, int indent); |
07725fee | 37 | static void sigterm_handler(int sig); |
85dda01c | 38 | static void usage(void) __attribute__((noreturn)); |
07725fee | 39 | |
40 | ||
41 | /* | |
42 | * 'main()' - Subscribe to the . | |
43 | */ | |
44 | ||
45 | int | |
46 | main(int argc, /* I - Number of command-line arguments */ | |
47 | char *argv[]) /* I - Command-line arguments */ | |
48 | { | |
49 | int i; /* Looping var */ | |
50 | const char *uri; /* URI to use */ | |
51 | int num_events; /* Number of events */ | |
52 | const char *events[100]; /* Events */ | |
53 | int subscription_id, /* notify-subscription-id */ | |
54 | sequence_number, /* notify-sequence-number */ | |
55 | interval; /* Interval between polls */ | |
56 | http_t *http; /* HTTP connection */ | |
57 | ipp_t *request, /* IPP request */ | |
58 | *response; /* IPP response */ | |
59 | ipp_attribute_t *attr; /* Current attribute */ | |
60 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) | |
61 | struct sigaction action; /* Actions for POSIX signals */ | |
62 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
63 | ||
64 | ||
65 | /* | |
66 | * Parse command-line... | |
67 | */ | |
68 | ||
69 | num_events = 0; | |
70 | uri = NULL; | |
71 | ||
72 | for (i = 1; i < argc; i ++) | |
73 | if (!strcmp(argv[i], "-E")) | |
74 | cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); | |
75 | else if (!strcmp(argv[i], "-e")) | |
76 | { | |
77 | i ++; | |
78 | if (i >= argc || num_events >= 100) | |
79 | usage(); | |
80 | ||
81 | events[num_events] = argv[i]; | |
82 | num_events ++; | |
83 | } | |
84 | else if (!strcmp(argv[i], "-h")) | |
85 | { | |
86 | i ++; | |
87 | if (i >= argc) | |
88 | usage(); | |
89 | ||
90 | cupsSetServer(argv[i]); | |
91 | } | |
92 | else if (uri || strncmp(argv[i], "ipp://", 6)) | |
93 | usage(); | |
94 | else | |
95 | uri = argv[i]; | |
96 | ||
97 | if (!uri) | |
98 | usage(); | |
99 | ||
100 | if (num_events == 0) | |
101 | { | |
102 | events[0] = "all"; | |
103 | num_events = 1; | |
104 | } | |
105 | ||
106 | /* | |
107 | * Connect to the server... | |
108 | */ | |
109 | ||
110 | if ((http = httpConnectEncrypt(cupsServer(), ippPort(), | |
111 | cupsEncryption())) == NULL) | |
112 | { | |
113 | perror(cupsServer()); | |
114 | return (1); | |
115 | } | |
116 | ||
117 | /* | |
118 | * Catch CTRL-C and SIGTERM... | |
119 | */ | |
120 | ||
121 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ | |
122 | sigset(SIGINT, sigterm_handler); | |
123 | sigset(SIGTERM, sigterm_handler); | |
124 | #elif defined(HAVE_SIGACTION) | |
125 | memset(&action, 0, sizeof(action)); | |
126 | ||
127 | sigemptyset(&action.sa_mask); | |
128 | action.sa_handler = sigterm_handler; | |
129 | sigaction(SIGINT, &action, NULL); | |
130 | sigaction(SIGTERM, &action, NULL); | |
131 | #else | |
132 | signal(SIGINT, sigterm_handler); | |
133 | signal(SIGTERM, sigterm_handler); | |
134 | #endif /* HAVE_SIGSET */ | |
135 | ||
136 | /* | |
137 | * Create the subscription... | |
138 | */ | |
139 | ||
140 | if (strstr(uri, "/jobs/")) | |
141 | { | |
142 | request = ippNewRequest(IPP_CREATE_JOB_SUBSCRIPTION); | |
143 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri); | |
144 | } | |
145 | else | |
146 | { | |
147 | request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION); | |
148 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, | |
149 | uri); | |
150 | } | |
151 | ||
152 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
153 | NULL, cupsUser()); | |
154 | ||
155 | ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events", | |
156 | num_events, NULL, events); | |
157 | ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, | |
158 | "notify-pull-method", NULL, "ippget"); | |
159 | ||
160 | response = cupsDoRequest(http, request, uri); | |
161 | if (cupsLastError() >= IPP_BAD_REQUEST) | |
162 | { | |
163 | fprintf(stderr, "Create-%s-Subscription: %s\n", | |
164 | strstr(uri, "/jobs") ? "Job" : "Printer", cupsLastErrorString()); | |
165 | ippDelete(response); | |
166 | httpClose(http); | |
167 | return (1); | |
168 | } | |
169 | ||
170 | if ((attr = ippFindAttribute(response, "notify-subscription-id", | |
171 | IPP_TAG_INTEGER)) == NULL) | |
172 | { | |
173 | fputs("ERROR: No notify-subscription-id in response!\n", stderr); | |
174 | ippDelete(response); | |
175 | httpClose(http); | |
176 | return (1); | |
177 | } | |
178 | ||
179 | subscription_id = attr->values[0].integer; | |
180 | ||
181 | printf("Create-%s-Subscription: notify-subscription-id=%d\n", | |
182 | strstr(uri, "/jobs/") ? "Job" : "Printer", subscription_id); | |
183 | ||
184 | ippDelete(response); | |
185 | ||
186 | /* | |
187 | * Monitor for events... | |
188 | */ | |
189 | ||
190 | sequence_number = 0; | |
191 | ||
192 | while (!terminate) | |
193 | { | |
194 | /* | |
195 | * Get the current events... | |
196 | */ | |
197 | ||
198 | printf("\nGet-Notifications(%d,%d):", subscription_id, sequence_number); | |
199 | fflush(stdout); | |
200 | ||
201 | request = ippNewRequest(IPP_GET_NOTIFICATIONS); | |
202 | ||
203 | if (strstr(uri, "/jobs/")) | |
204 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri); | |
205 | else | |
206 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, | |
207 | uri); | |
208 | ||
209 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, | |
210 | "requesting-user-name", NULL, cupsUser()); | |
211 | ||
212 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, | |
213 | "notify-subscription-ids", subscription_id); | |
214 | if (sequence_number) | |
215 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, | |
216 | "notify-sequence-numbers", sequence_number + 1); | |
217 | ||
218 | response = cupsDoRequest(http, request, uri); | |
219 | ||
220 | printf(" %s\n", ippErrorString(cupsLastError())); | |
221 | ||
222 | if (cupsLastError() >= IPP_BAD_REQUEST) | |
223 | fprintf(stderr, "Get-Notifications: %s\n", cupsLastErrorString()); | |
224 | else if (response) | |
225 | { | |
226 | print_attributes(response, 0); | |
227 | ||
228 | for (attr = ippFindAttribute(response, "notify-sequence-number", | |
229 | IPP_TAG_INTEGER); | |
230 | attr; | |
231 | attr = ippFindNextAttribute(response, "notify-sequence-number", | |
232 | IPP_TAG_INTEGER)) | |
233 | if (attr->values[0].integer > sequence_number) | |
234 | sequence_number = attr->values[0].integer; | |
235 | } | |
236 | ||
237 | if ((attr = ippFindAttribute(response, "notify-get-interval", | |
238 | IPP_TAG_INTEGER)) != NULL && | |
239 | attr->values[0].integer > 0) | |
240 | interval = attr->values[0].integer; | |
241 | else | |
242 | interval = 5; | |
243 | ||
244 | ippDelete(response); | |
7e86f2f6 | 245 | sleep((unsigned)interval); |
07725fee | 246 | } |
247 | ||
248 | /* | |
249 | * Cancel the subscription... | |
250 | */ | |
251 | ||
252 | printf("\nCancel-Subscription:"); | |
253 | fflush(stdout); | |
254 | ||
255 | request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION); | |
256 | ||
257 | if (strstr(uri, "/jobs/")) | |
258 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri); | |
259 | else | |
260 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, | |
261 | uri); | |
262 | ||
263 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
264 | NULL, cupsUser()); | |
265 | ||
266 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, | |
267 | "notify-subscription-id", subscription_id); | |
268 | ||
269 | ippDelete(cupsDoRequest(http, request, uri)); | |
270 | ||
271 | printf(" %s\n", ippErrorString(cupsLastError())); | |
272 | ||
273 | if (cupsLastError() >= IPP_BAD_REQUEST) | |
274 | fprintf(stderr, "Cancel-Subscription: %s\n", cupsLastErrorString()); | |
275 | ||
276 | /* | |
277 | * Close the connection and return... | |
278 | */ | |
279 | ||
280 | httpClose(http); | |
281 | ||
282 | return (0); | |
283 | } | |
284 | ||
285 | ||
286 | /* | |
287 | * 'print_attributes()' - Print the attributes in a request... | |
288 | */ | |
289 | ||
f899b121 | 290 | static void |
07725fee | 291 | print_attributes(ipp_t *ipp, /* I - IPP request */ |
292 | int indent) /* I - Indentation */ | |
293 | { | |
294 | int i; /* Looping var */ | |
295 | ipp_tag_t group; /* Current group */ | |
296 | ipp_attribute_t *attr; /* Current attribute */ | |
a2326b5b | 297 | _ipp_value_t *val; /* Current value */ |
07725fee | 298 | static const char * const tags[] = /* Value/group tag strings */ |
299 | { | |
300 | "reserved-00", | |
301 | "operation-attributes-tag", | |
302 | "job-attributes-tag", | |
303 | "end-of-attributes-tag", | |
304 | "printer-attributes-tag", | |
305 | "unsupported-attributes-tag", | |
306 | "subscription-attributes-tag", | |
307 | "event-attributes-tag", | |
308 | "reserved-08", | |
309 | "reserved-09", | |
310 | "reserved-0A", | |
311 | "reserved-0B", | |
312 | "reserved-0C", | |
313 | "reserved-0D", | |
314 | "reserved-0E", | |
315 | "reserved-0F", | |
316 | "unsupported", | |
317 | "default", | |
318 | "unknown", | |
319 | "no-value", | |
320 | "reserved-14", | |
321 | "not-settable", | |
322 | "delete-attr", | |
323 | "admin-define", | |
324 | "reserved-18", | |
325 | "reserved-19", | |
326 | "reserved-1A", | |
327 | "reserved-1B", | |
328 | "reserved-1C", | |
329 | "reserved-1D", | |
330 | "reserved-1E", | |
331 | "reserved-1F", | |
332 | "reserved-20", | |
333 | "integer", | |
334 | "boolean", | |
335 | "enum", | |
336 | "reserved-24", | |
337 | "reserved-25", | |
338 | "reserved-26", | |
339 | "reserved-27", | |
340 | "reserved-28", | |
341 | "reserved-29", | |
342 | "reserved-2a", | |
343 | "reserved-2b", | |
344 | "reserved-2c", | |
345 | "reserved-2d", | |
346 | "reserved-2e", | |
347 | "reserved-2f", | |
348 | "octetString", | |
349 | "dateTime", | |
350 | "resolution", | |
351 | "rangeOfInteger", | |
352 | "begCollection", | |
353 | "textWithLanguage", | |
354 | "nameWithLanguage", | |
355 | "endCollection", | |
356 | "reserved-38", | |
357 | "reserved-39", | |
358 | "reserved-3a", | |
359 | "reserved-3b", | |
360 | "reserved-3c", | |
361 | "reserved-3d", | |
362 | "reserved-3e", | |
363 | "reserved-3f", | |
364 | "reserved-40", | |
365 | "textWithoutLanguage", | |
366 | "nameWithoutLanguage", | |
367 | "reserved-43", | |
368 | "keyword", | |
369 | "uri", | |
370 | "uriScheme", | |
371 | "charset", | |
372 | "naturalLanguage", | |
373 | "mimeMediaType", | |
374 | "memberName" | |
375 | }; | |
376 | ||
377 | ||
378 | for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next) | |
379 | { | |
380 | if ((attr->group_tag == IPP_TAG_ZERO && indent <= 8) || !attr->name) | |
381 | { | |
382 | group = IPP_TAG_ZERO; | |
383 | putchar('\n'); | |
384 | continue; | |
385 | } | |
386 | ||
387 | if (group != attr->group_tag) | |
388 | { | |
389 | group = attr->group_tag; | |
390 | ||
391 | putchar('\n'); | |
392 | for (i = 4; i < indent; i ++) | |
393 | putchar(' '); | |
394 | ||
395 | printf("%s:\n\n", tags[group]); | |
396 | } | |
397 | ||
398 | for (i = 0; i < indent; i ++) | |
399 | putchar(' '); | |
400 | ||
401 | printf("%s (", attr->name); | |
402 | if (attr->num_values > 1) | |
403 | printf("1setOf "); | |
404 | printf("%s):", tags[attr->value_tag]); | |
405 | ||
406 | switch (attr->value_tag) | |
407 | { | |
408 | case IPP_TAG_ENUM : | |
409 | case IPP_TAG_INTEGER : | |
410 | for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) | |
411 | printf(" %d", val->integer); | |
412 | putchar('\n'); | |
413 | break; | |
414 | ||
415 | case IPP_TAG_BOOLEAN : | |
416 | for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) | |
417 | printf(" %s", val->boolean ? "true" : "false"); | |
418 | putchar('\n'); | |
419 | break; | |
420 | ||
421 | case IPP_TAG_RANGE : | |
422 | for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) | |
423 | printf(" %d-%d", val->range.lower, val->range.upper); | |
424 | putchar('\n'); | |
425 | break; | |
426 | ||
427 | case IPP_TAG_DATE : | |
428 | { | |
07725fee | 429 | char vstring[256]; /* Formatted time */ |
430 | ||
431 | for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) | |
554aa7b7 | 432 | printf(" (%s)", _cupsStrDate(vstring, sizeof(vstring), ippDateToTime(val->date))); |
07725fee | 433 | } |
434 | putchar('\n'); | |
435 | break; | |
436 | ||
437 | case IPP_TAG_RESOLUTION : | |
438 | for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) | |
439 | printf(" %dx%d%s", val->resolution.xres, val->resolution.yres, | |
3e7fe0ca | 440 | val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); |
07725fee | 441 | putchar('\n'); |
442 | break; | |
443 | ||
444 | case IPP_TAG_STRING : | |
445 | case IPP_TAG_TEXTLANG : | |
446 | case IPP_TAG_NAMELANG : | |
447 | case IPP_TAG_TEXT : | |
448 | case IPP_TAG_NAME : | |
449 | case IPP_TAG_KEYWORD : | |
450 | case IPP_TAG_URI : | |
451 | case IPP_TAG_URISCHEME : | |
452 | case IPP_TAG_CHARSET : | |
453 | case IPP_TAG_LANGUAGE : | |
454 | case IPP_TAG_MIMETYPE : | |
455 | for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) | |
456 | printf(" \"%s\"", val->string.text); | |
457 | putchar('\n'); | |
458 | break; | |
459 | ||
460 | case IPP_TAG_BEGIN_COLLECTION : | |
461 | putchar('\n'); | |
462 | ||
463 | for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) | |
464 | { | |
465 | if (i) | |
466 | putchar('\n'); | |
467 | print_attributes(val->collection, indent + 4); | |
468 | } | |
469 | break; | |
470 | ||
471 | default : | |
472 | printf("UNKNOWN (%d values)\n", attr->num_values); | |
473 | break; | |
474 | } | |
475 | } | |
476 | } | |
477 | ||
478 | ||
479 | /* | |
480 | * 'sigterm_handler()' - Flag when the user hits CTRL-C... | |
481 | */ | |
482 | ||
483 | static void | |
484 | sigterm_handler(int sig) /* I - Signal number (unused) */ | |
485 | { | |
486 | (void)sig; | |
487 | ||
488 | terminate = 1; | |
489 | } | |
490 | ||
491 | ||
492 | /* | |
493 | * 'usage()' - Show program usage... | |
494 | */ | |
495 | ||
496 | static void | |
497 | usage(void) | |
498 | { | |
499 | puts("Usage: testsub [-E] [-e event ... -e eventN] [-h hostname] URI"); | |
500 | exit(0); | |
501 | } |