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