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