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