1/* 2 * "$Id: testsub.c 11934 2014-06-17 18:58:29Z msweet $" 3 * 4 * Scheduler notification tester for CUPS. 5 * 6 * Copyright 2007-2014 by Apple Inc. 7 * Copyright 2006-2007 by Easy Software Products. 8 * 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/". 14 */ 15 16/* 17 * Include necessary headers... 18 */ 19 20#include <cups/cups.h> 21#include <cups/debug-private.h> 22#include <cups/string-private.h> 23#include <signal.h> 24#include <cups/ipp-private.h> /* TODO: Update so we don't need this */ 25 26 27/* 28 * Local globals... 29 */ 30 31static int terminate = 0; 32 33 34/* 35 * Local functions... 36 */ 37 38static void print_attributes(ipp_t *ipp, int indent); 39static void sigterm_handler(int sig); 40static void usage(void) __attribute__((noreturn)); 41 42 43/* 44 * 'main()' - Subscribe to the . 45 */ 46 47int 48main(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); 247 sleep((unsigned)interval); 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 292static void 293print_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 */ 299 _ipp_value_t *val; /* Current value */ 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 { 431 char vstring[256]; /* Formatted time */ 432 433 for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) 434 printf(" (%s)", _cupsStrDate(vstring, sizeof(vstring), ippDateToTime(val->date))); 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, 442 val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); 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 485static void 486sigterm_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 498static void 499usage(void) 500{ 501 puts("Usage: testsub [-E] [-e event ... -e eventN] [-h hostname] URI"); 502 exit(0); 503} 504 505 506 507/* 508 * End of "$Id: testsub.c 11934 2014-06-17 18:58:29Z msweet $". 509 */ 510