]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/testclient.c
Add explicit 1 second wait for Digest challenge.
[thirdparty/cups.git] / cups / testclient.c
CommitLineData
75e1a17c
MS
1/*
2 * Simulated client test program for CUPS.
3 *
e22f464e 4 * Copyright © 2017-2018 by Apple Inc.
75e1a17c 5 *
e22f464e
MS
6 * Licensed under Apache License v2.0. See the file "LICENSE" for more
7 * information.
75e1a17c
MS
8 */
9
10/*
11 * Include necessary headers...
12 */
13
4b16c717 14#include <stdio.h>
75e1a17c 15#include <stdlib.h>
4b16c717
MS
16#include <cups/cups.h>
17#include <cups/raster.h>
18#include <cups/string-private.h>
19#include <cups/thread-private.h>
75e1a17c
MS
20
21
22/*
23 * Local types...
24 */
25
26typedef struct _client_monitor_s
27{
28 const char *uri, /* Printer URI */
29 *hostname, /* Hostname */
30 *user, /* Username */
31 *resource; /* Resource path */
32 int port; /* Port number */
33 http_encryption_t encryption; /* Use encryption? */
34 ipp_pstate_t printer_state; /* Current printer state */
35 char printer_state_reasons[1024];
36 /* Current printer-state-reasons */
37 int job_id; /* Job ID for submitted job */
38 ipp_jstate_t job_state; /* Current job state */
39 char job_state_reasons[1024];
40 /* Current job-state-reasons */
41} _client_monitor_t;
42
43
44/*
45 * Local functions...
46 */
47
7f14a297 48static const char *make_raster_file(ipp_t *response, int grayscale, char *tempname, size_t tempsize, const char **format);
240a27f9 49static void *monitor_printer(_client_monitor_t *monitor);
7f14a297 50static void show_attributes(const char *title, int request, ipp_t *ipp);
240a27f9
MS
51static void show_capabilities(ipp_t *response);
52static void usage(void);
75e1a17c
MS
53
54
55/*
56 * 'main()' - Main entry.
57 */
58
59int /* O - Exit status */
60main(int argc, /* I - Number of command-line arguments */
61 char *argv[]) /* I - Command-line arguments */
62{
240a27f9
MS
63 int i; /* Looping var */
64 const char *opt, /* Current option */
65 *uri = NULL, /* Printer URI */
66 *printfile = NULL,
67 /* Print file */
68 *printformat = NULL;
69 /* Print format */
7f14a297 70 int keepfile = 0, /* Keep temp file? */
e37405ea
MS
71 grayscale = 0, /* Force grayscale? */
72 verbosity = 0; /* Verbosity */
240a27f9
MS
73 char tempfile[1024] = "",
74 /* Temporary file (if any) */
75 scheme[32], /* URI scheme */
76 userpass[256], /* Username:password */
77 hostname[256], /* Hostname */
78 resource[256]; /* Resource path */
79 int port; /* Port number */
80 http_encryption_t encryption; /* Encryption mode */
81 _client_monitor_t monitor; /* Monitoring data */
82 http_t *http; /* HTTP connection */
83 ipp_t *request, /* IPP request */
84 *response; /* IPP response */
85 ipp_attribute_t *attr; /* IPP attribute */
86 static const char * const pattrs[] = /* Printer attributes we are interested in */
87 {
88 "job-template",
89 "printer-defaults",
90 "printer-description",
91 "media-col-database",
92 "media-col-ready"
93 };
94
95
96 /*
97 * Parse command-line options...
98 */
99
e22f464e
MS
100 if (argc == 1)
101 return (0);
102
240a27f9
MS
103 for (i = 1; i < argc; i ++)
104 {
105 if (argv[i][0] == '-')
106 {
107 for (opt = argv[i] + 1; *opt; opt ++)
108 {
109 switch (*opt)
110 {
5535551f
MS
111 case 'd' : /* -d document-format */
112 if (printformat)
113 {
114 puts("Document format can only be specified once.");
115 usage();
116 return (1);
117 }
118
119 i ++;
120 if (i >= argc)
121 {
122 puts("Expected document format after '-d'.");
123 usage();
124 return (1);
125 }
126
127 printformat = argv[i];
128 break;
129
240a27f9
MS
130 case 'f' : /* -f print-file */
131 if (printfile)
132 {
133 puts("Print file can only be specified once.");
134 usage();
135 return (1);
136 }
137
138 i ++;
139 if (i >= argc)
140 {
141 puts("Expected print file after '-f'.");
142 usage();
143 return (1);
144 }
145
146 printfile = argv[i];
147 break;
148
7f14a297
MS
149 case 'g' :
150 grayscale = 1;
151 break;
152
153 case 'k' :
154 keepfile = 1;
155 break;
156
e37405ea
MS
157 case 'v' :
158 verbosity ++;
159 break;
160
240a27f9
MS
161 default :
162 printf("Unknown option '-%c'.\n", *opt);
163 usage();
164 return (1);
165 }
166 }
167 }
168 else if (uri || (strncmp(argv[i], "ipp://", 6) && strncmp(argv[i], "ipps://", 7)))
169 {
170 printf("Unknown command-line argument '%s'.\n", argv[i]);
171 usage();
172 return (1);
173 }
174 else
175 uri = argv[i];
176 }
177
178 /*
179 * Make sure we have everything we need.
180 */
181
182 if (!uri)
183 {
184 puts("Expected printer URI.");
185 usage();
186 return (1);
187 }
188
189 /*
190 * Connect to the printer...
191 */
192
4b16c717 193 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
240a27f9
MS
194 {
195 printf("Bad printer URI '%s'.\n", uri);
196 return (1);
197 }
198
199 if (!port)
200 port = IPP_PORT;
201
202 if (!strcmp(scheme, "https") || !strcmp(scheme, "ipps"))
203 encryption = HTTP_ENCRYPTION_ALWAYS;
204 else
205 encryption = HTTP_ENCRYPTION_IF_REQUESTED;
206
207 if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 0, NULL)) == NULL)
208 {
209 printf("Unable to connect to '%s' on port %d: %s\n", hostname, port, cupsLastErrorString());
210 return (1);
211 }
212
213 /*
214 * Query printer status and capabilities...
215 */
216
217 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
218 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
219 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
220 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
221
222 response = cupsDoRequest(http, request, resource);
223
e37405ea
MS
224 if (verbosity)
225 show_capabilities(response);
240a27f9
MS
226
227 /*
228 * Now figure out what we will be printing...
229 */
230
231 if (printfile)
232 {
233 /*
234 * User specified a print file, figure out the format...
235 */
236
237 if ((opt = strrchr(printfile, '.')) != NULL)
238 {
239 /*
240 * Guess the format from the extension...
241 */
242
243 if (!strcmp(opt, ".jpg"))
244 printformat = "image/jpeg";
245 else if (!strcmp(opt, ".pdf"))
246 printformat = "application/pdf";
247 else if (!strcmp(opt, ".ps"))
248 printformat = "application/postscript";
249 else if (!strcmp(opt, ".pwg"))
250 printformat = "image/pwg-raster";
251 else if (!strcmp(opt, ".urf"))
252 printformat = "image/urf";
253 else
254 printformat = "application/octet-stream";
255 }
256 else
257 {
258 /*
259 * Tell the printer to auto-detect...
260 */
261
262 printformat = "application/octet-stream";
263 }
264 }
265 else
266 {
267 /*
268 * No file specified, make something to test with...
269 */
270
7f14a297 271 if ((printfile = make_raster_file(response, grayscale, tempfile, sizeof(tempfile), &printformat)) == NULL)
240a27f9
MS
272 return (1);
273 }
274
275 ippDelete(response);
276
277 /*
278 * Start monitoring the printer in the background...
279 */
280
281 memset(&monitor, 0, sizeof(monitor));
282
283 monitor.uri = uri;
284 monitor.hostname = hostname;
285 monitor.resource = resource;
286 monitor.port = port;
287 monitor.encryption = encryption;
288
289 _cupsThreadCreate((_cups_thread_func_t)monitor_printer, &monitor);
290
291 /*
292 * Create the job and wait for completion...
293 */
294
295 request = ippNewRequest(IPP_OP_CREATE_JOB);
296 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
297 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
298
299 if ((opt = strrchr(printfile, '/')) != NULL)
300 opt ++;
301 else
302 opt = printfile;
303
4b16c717 304 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, opt);
240a27f9 305
e37405ea
MS
306 if (verbosity)
307 show_attributes("Create-Job request", 1, request);
7f14a297 308
240a27f9
MS
309 response = cupsDoRequest(http, request, resource);
310
e37405ea
MS
311 if (verbosity)
312 show_attributes("Create-Job response", 0, response);
7f14a297 313
240a27f9
MS
314 if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE)
315 {
316 printf("Unable to create print job: %s\n", cupsLastErrorString());
317
318 monitor.job_state = IPP_JSTATE_ABORTED;
319
320 goto cleanup;
321 }
322
323 if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL)
324 {
325 puts("No job-id returned in Create-Job request.");
326
327 monitor.job_state = IPP_JSTATE_ABORTED;
328
329 goto cleanup;
330 }
331
332 monitor.job_id = ippGetInteger(attr, 0);
333
7f14a297
MS
334 printf("CREATED JOB %d, sending %s of type %s\n", monitor.job_id, printfile, printformat);
335
240a27f9
MS
336 ippDelete(response);
337
4b16c717 338 request = ippNewRequest(IPP_OP_SEND_DOCUMENT);
240a27f9
MS
339 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
340 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", monitor.job_id);
341 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
342 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, printformat);
4b16c717 343 ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
240a27f9 344
e37405ea
MS
345 if (verbosity)
346 show_attributes("Send-Document request", 1, request);
7f14a297 347
240a27f9
MS
348 response = cupsDoFileRequest(http, request, resource, printfile);
349
e37405ea
MS
350 if (verbosity)
351 show_attributes("Send-Document response", 0, response);
7f14a297 352
240a27f9
MS
353 if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE)
354 {
355 printf("Unable to print file: %s\n", cupsLastErrorString());
356
357 monitor.job_state = IPP_JSTATE_ABORTED;
358
359 goto cleanup;
360 }
361
7f14a297
MS
362 puts("WAITING FOR JOB TO COMPLETE");
363
240a27f9
MS
364 while (monitor.job_state < IPP_JSTATE_CANCELED)
365 sleep(1);
366
367 /*
368 * Cleanup after ourselves...
369 */
370
371 cleanup:
372
373 httpClose(http);
374
7f14a297 375 if (tempfile[0] && !keepfile)
240a27f9
MS
376 unlink(tempfile);
377
378 return (monitor.job_state == IPP_JSTATE_COMPLETED);
379}
380
381
382/*
383 * 'make_raster_file()' - Create a temporary raster file.
384 */
385
386static const char * /* O - Print filename */
387make_raster_file(ipp_t *response, /* I - Printer attributes */
7f14a297 388 int grayscale, /* I - Force grayscale? */
240a27f9
MS
389 char *tempname, /* I - Temporary filename buffer */
390 size_t tempsize, /* I - Size of temp file buffer */
391 const char **format) /* O - Print format */
392{
4b16c717
MS
393 int i, /* Looping var */
394 count; /* Number of values */
395 ipp_attribute_t *attr; /* Printer attribute */
396 const char *type = NULL; /* Raster type (colorspace + bits) */
397 pwg_media_t *media = NULL; /* Media size */
398 int xdpi = 0, /* Horizontal resolution */
399 ydpi = 0; /* Vertical resolution */
400 int fd; /* Temporary file */
401 cups_mode_t mode; /* Raster mode */
402 cups_raster_t *ras; /* Raster stream */
403 cups_page_header2_t header; /* Page header */
404 unsigned char *line, /* Line of raster data */
405 *lineptr; /* Pointer into line */
406 unsigned y, /* Current position on page */
407 xcount, ycount, /* Current count for X and Y */
408 xrep, yrep, /* Repeat count for X and Y */
409 xoff, yoff, /* Offsets for X and Y */
410 yend; /* End Y value */
411 int temprow, /* Row in template */
412 tempcolor; /* Template color */
413 const char *template; /* Pointer into template */
414 const unsigned char *color; /* Current color */
415 static const unsigned char colors[][3] =
416 { /* Colors for test */
417 { 191, 191, 191 },
418 { 127, 127, 127 },
419 { 63, 63, 63 },
420 { 0, 0, 0 },
421 { 255, 0, 0 },
422 { 255, 127, 0 },
423 { 255, 255, 0 },
424 { 127, 255, 0 },
425 { 0, 255, 0 },
426 { 0, 255, 127 },
427 { 0, 255, 255 },
428 { 0, 127, 255 },
429 { 0, 0, 255 },
430 { 127, 0, 255 },
431 { 255, 0, 255 }
432 };
433 static const char * const templates[] =
434 { /* Raster template */
435 " CCC U U PPPP SSS TTTTT EEEEE SSS TTTTT 000 1 222 333 4 55555 66 77777 888 999 ",
436 "C C U U P P S S T E S S T 0 0 11 2 2 3 3 4 4 5 6 7 8 8 9 9 ",
437 "C U U P P S T E S T 0 0 1 2 3 4 4 5 6 7 8 8 9 9 ",
438 "C U U PPPP SSS ----- T EEEE SSS T 0 0 0 1 22 333 44444 555 6666 7 888 9999 ",
439 "C U U P S T E S T 0 0 1 2 3 4 5 6 6 7 8 8 9 ",
440 "C C U U P S S T E S S T 0 0 1 2 3 3 4 5 5 6 6 7 8 8 9 ",
441 " CCC UUU P SSS T EEEEE SSS T 000 111 22222 333 4 555 666 7 888 99 ",
442 " "
443 };
444
445
446 /*
447 * Figure out the output format...
448 */
449
450 if ((attr = ippFindAttribute(response, "document-format-supported", IPP_TAG_MIMETYPE)) == NULL)
451 {
452 puts("No supported document formats, aborting.");
453 return (NULL);
454 }
455
5535551f
MS
456 if (*format)
457 {
458 if (!ippContainsString(attr, *format))
459 {
460 printf("Printer does not support document-format '%s'.\n", *format);
461 return (NULL);
462 }
463
464 if (!strcmp(*format, "image/urf"))
465 mode = CUPS_RASTER_WRITE_APPLE;
466 else if (!strcmp(*format, "image/pwg-raster"))
467 mode = CUPS_RASTER_WRITE_PWG;
468 else
469 {
470 printf("Unable to generate document-format '%s'.\n", *format);
471 return (NULL);
472 }
473 }
474 else if (ippContainsString(attr, "image/urf"))
4b16c717
MS
475 {
476 /*
477 * Apple Raster format...
478 */
479
480 *format = "image/urf";
481 mode = CUPS_RASTER_WRITE_APPLE;
482 }
483 else if (ippContainsString(attr, "image/pwg-raster"))
484 {
485 /*
486 * PWG Raster format...
487 */
488
489 *format = "image/pwg-raster";
490 mode = CUPS_RASTER_WRITE_PWG;
491 }
492 else
493 {
494 /*
495 * No supported raster format...
496 */
497
498 puts("Printer does not support Apple or PWG raster files, aborting.");
499 return (NULL);
500 }
501
502 /*
503 * Figure out the the media, resolution, and color mode...
504 */
505
506 if ((attr = ippFindAttribute(response, "media-default", IPP_TAG_KEYWORD)) != NULL)
507 {
508 /*
509 * Use default media...
510 */
511
512 media = pwgMediaForPWG(ippGetString(attr, 0, NULL));
513 }
514 else if ((attr = ippFindAttribute(response, "media-ready", IPP_TAG_KEYWORD)) != NULL)
515 {
516 /*
517 * Use ready media...
518 */
519
520 if (ippContainsString(attr, "na_letter_8.5x11in"))
521 media = pwgMediaForPWG("na_letter_8.5x11in");
522 else if (ippContainsString(attr, "iso_a4_210x297mm"))
523 media = pwgMediaForPWG("iso_a4_210x297mm");
524 else
525 media = pwgMediaForPWG(ippGetString(attr, 0, NULL));
526 }
527 else
528 {
529 puts("No default or ready media reported by printer, aborting.");
530 return (NULL);
531 }
532
5535551f 533 if (mode == CUPS_RASTER_WRITE_APPLE && (attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL)
4b16c717
MS
534 {
535 for (i = 0, count = ippGetCount(attr); i < count; i ++)
536 {
537 const char *val = ippGetString(attr, i, NULL);
538
7f14a297
MS
539 if (!strncmp(val, "RS", 2))
540 xdpi = ydpi = atoi(val + 2);
541 else if (!strncmp(val, "W8", 2) && !type)
4b16c717 542 type = "sgray_8";
7f14a297 543 else if (!strncmp(val, "SRGB24", 6) && !grayscale)
4b16c717
MS
544 type = "srgb_8";
545 }
546 }
5535551f 547 else if (mode == CUPS_RASTER_WRITE_PWG && (attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL)
4b16c717
MS
548 {
549 for (i = 0, count = ippGetCount(attr); i < count; i ++)
550 {
551 int tempxdpi, tempydpi;
552 ipp_res_t tempunits;
553
554 tempxdpi = ippGetResolution(attr, 0, &tempydpi, &tempunits);
555
556 if (i == 0 || tempxdpi < xdpi || tempydpi < ydpi)
557 {
558 xdpi = tempxdpi;
559 ydpi = tempydpi;
560 }
561 }
562
563 if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) != NULL)
564 {
7f14a297 565 if (!grayscale && ippContainsString(attr, "srgb_8"))
4b16c717
MS
566 type = "srgb_8";
567 else if (ippContainsString(attr, "sgray_8"))
568 type = "sgray_8";
569 }
570 }
571
572 if (xdpi < 72 || ydpi < 72)
573 {
574 puts("No supported raster resolutions, aborting.");
575 return (NULL);
576 }
577
578 if (!type)
579 {
580 puts("No supported color spaces or bit depths, aborting.");
581 return (NULL);
582 }
583
584 /*
585 * Make the raster context and details...
586 */
587
588 if (!cupsRasterInitPWGHeader(&header, media, type, xdpi, ydpi, "one-sided", NULL))
589 {
590 printf("Unable to initialize raster context: %s\n", cupsRasterErrorString());
591 return (NULL);
592 }
593
594 header.cupsInteger[CUPS_RASTER_PWG_TotalPageCount] = 1;
595
596 if (header.cupsWidth > (4 * header.HWResolution[0]))
597 {
598 xoff = header.HWResolution[0] / 2;
599 yoff = header.HWResolution[1] / 2;
600 }
601 else
602 {
603 xoff = 0;
604 yoff = 0;
605 }
606
607 xrep = (header.cupsWidth - 2 * xoff) / 140;
608 yrep = xrep * header.HWResolution[1] / header.HWResolution[0];
609 yend = header.cupsHeight - yoff;
610
611 /*
612 * Prepare the raster file...
613 */
614
615 if ((line = malloc(header.cupsBytesPerLine)) == NULL)
616 {
617 printf("Unable to allocate %u bytes for raster output: %s\n", header.cupsBytesPerLine, strerror(errno));
618 return (NULL);
619 }
620
621 if ((fd = cupsTempFd(tempname, (int)tempsize)) < 0)
622 {
623 printf("Unable to create temporary print file: %s\n", strerror(errno));
e22f464e 624 free(line);
4b16c717
MS
625 return (NULL);
626 }
627
628 if ((ras = cupsRasterOpen(fd, mode)) == NULL)
629 {
630 printf("Unable to open raster stream: %s\n", cupsRasterErrorString());
631 close(fd);
e22f464e 632 free(line);
4b16c717
MS
633 return (NULL);
634 }
635
636 /*
637 * Write a single page consisting of the template dots repeated over the page.
638 */
639
640 cupsRasterWriteHeader2(ras, &header);
641
642 memset(line, 0xff, header.cupsBytesPerLine);
643
644 for (y = 0; y < yoff; y ++)
645 cupsRasterWritePixels(ras, line, header.cupsBytesPerLine);
646
7f14a297 647 for (temprow = 0, tempcolor = 0; y < yend;)
4b16c717
MS
648 {
649 template = templates[temprow];
650 color = colors[tempcolor];
651
652 temprow ++;
653 if (temprow >= (int)(sizeof(templates) / sizeof(templates[0])))
654 {
655 temprow = 0;
656 tempcolor ++;
657 if (tempcolor >= (int)(sizeof(colors) / sizeof(colors[0])))
658 tempcolor = 0;
7f14a297
MS
659 else if (tempcolor > 3 && header.cupsColorSpace == CUPS_CSPACE_SW)
660 tempcolor = 0;
4b16c717
MS
661 }
662
663 memset(line, 0xff, header.cupsBytesPerLine);
664
665 if (header.cupsColorSpace == CUPS_CSPACE_SW)
666 {
667 /*
668 * Do grayscale output...
669 */
670
671 for (lineptr = line + xoff; *template; template ++)
672 {
673 if (*template != ' ')
674 {
675 for (xcount = xrep; xcount > 0; xcount --)
676 *lineptr++ = *color;
677 }
678 else
679 {
680 lineptr += xrep;
681 }
682 }
683 }
684 else
685 {
686 /*
687 * Do color output...
688 */
689
690 for (lineptr = line + 3 * xoff; *template; template ++)
691 {
692 if (*template != ' ')
693 {
694 for (xcount = xrep; xcount > 0; xcount --, lineptr += 3)
695 memcpy(lineptr, color, 3);
696 }
697 else
698 {
699 lineptr += 3 * xrep;
700 }
701 }
702 }
703
704 for (ycount = yrep; ycount > 0 && y < yend; ycount --, y ++)
705 cupsRasterWritePixels(ras, line, header.cupsBytesPerLine);
706 }
707
708 memset(line, 0xff, header.cupsBytesPerLine);
709
710 for (y = 0; y < header.cupsHeight; y ++)
711 cupsRasterWritePixels(ras, line, header.cupsBytesPerLine);
712
713 cupsRasterClose(ras);
714
715 close(fd);
716
717 printf("PRINT FILE: %s\n", tempname);
718
719 return (tempname);
75e1a17c
MS
720}
721
722
723/*
724 * 'monitor_printer()' - Monitor the job and printer states.
725 */
726
727static void * /* O - Thread exit code */
728monitor_printer(
729 _client_monitor_t *monitor) /* I - Monitoring data */
730{
731 http_t *http; /* Connection to printer */
732 ipp_t *request, /* IPP request */
733 *response; /* IPP response */
734 ipp_attribute_t *attr; /* Attribute in response */
735 ipp_pstate_t printer_state; /* Printer state */
736 char printer_state_reasons[1024];
737 /* Printer state reasons */
75e1a17c
MS
738 ipp_jstate_t job_state; /* Job state */
739 char job_state_reasons[1024];/* Printer state reasons */
740 static const char * const jattrs[] = /* Job attributes we want */
741 {
742 "job-state",
743 "job-state-reasons"
744 };
745 static const char * const pattrs[] = /* Printer attributes we want */
746 {
747 "printer-state",
748 "printer-state-reasons"
749 };
750
751
752 /*
753 * Open a connection to the printer...
754 */
755
4b16c717 756 http = httpConnect2(monitor->hostname, monitor->port, NULL, AF_UNSPEC, monitor->encryption, 1, 0, NULL);
75e1a17c
MS
757
758 /*
759 * Loop until the job is canceled, aborted, or completed.
760 */
761
762 printer_state = (ipp_pstate_t)0;
763 printer_state_reasons[0] = '\0';
764
765 job_state = (ipp_jstate_t)0;
766 job_state_reasons[0] = '\0';
767
240a27f9 768 while (monitor->job_state < IPP_JSTATE_CANCELED)
75e1a17c
MS
769 {
770 /*
771 * Reconnect to the printer as needed...
772 */
773
774 if (httpGetFd(http) < 0)
4b16c717 775 httpReconnect2(http, 30000, NULL);
75e1a17c
MS
776
777 if (httpGetFd(http) >= 0)
778 {
779 /*
780 * Connected, so check on the printer state...
781 */
782
783 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
784 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, monitor->uri);
785 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
786 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
787
788 response = cupsDoRequest(http, request, monitor->resource);
789
790 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
791 printer_state = (ipp_pstate_t)ippGetInteger(attr, 0);
792
793 if ((attr = ippFindAttribute(response, "printer-state-reasons", IPP_TAG_KEYWORD)) != NULL)
794 ippAttributeString(attr, printer_state_reasons, sizeof(printer_state_reasons));
795
796 if (printer_state != monitor->printer_state || strcmp(printer_state_reasons, monitor->printer_state_reasons))
797 {
798 printf("PRINTER: %s (%s)\n", ippEnumString("printer-state", printer_state), printer_state_reasons);
799
800 monitor->printer_state = printer_state;
801 strlcpy(monitor->printer_state_reasons, printer_state_reasons, sizeof(monitor->printer_state_reasons));
802 }
803
804 ippDelete(response);
805
806 if (monitor->job_id > 0)
807 {
808 /*
809 * Check the status of the job itself...
810 */
811
812 request = ippNewRequest(IPP_OP_GET_JOB_ATTRIBUTES);
813 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, monitor->uri);
814 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", monitor->job_id);
815 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
816 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(jattrs) / sizeof(jattrs[0])), NULL, jattrs);
817
818 response = cupsDoRequest(http, request, monitor->resource);
819
820 if ((attr = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL)
821 job_state = (ipp_jstate_t)ippGetInteger(attr, 0);
822
823 if ((attr = ippFindAttribute(response, "job-state-reasons", IPP_TAG_KEYWORD)) != NULL)
824 ippAttributeString(attr, job_state_reasons, sizeof(job_state_reasons));
825
826 if (job_state != monitor->job_state || strcmp(job_state_reasons, monitor->job_state_reasons))
827 {
828 printf("JOB %d: %s (%s)\n", monitor->job_id, ippEnumString("job-state", job_state), job_state_reasons);
829
830 monitor->job_state = job_state;
831 strlcpy(monitor->job_state_reasons, job_state_reasons, sizeof(monitor->job_state_reasons));
832 }
833
834 ippDelete(response);
835 }
836 }
837
4b16c717 838 if (monitor->job_state < IPP_JSTATE_CANCELED)
240a27f9
MS
839 {
840 /*
841 * Sleep for 5 seconds...
842 */
75e1a17c 843
240a27f9
MS
844 sleep(5);
845 }
75e1a17c
MS
846 }
847
848 /*
849 * Cleanup and return...
850 */
851
852 httpClose(http);
853
854 return (NULL);
855}
240a27f9
MS
856
857
7f14a297
MS
858/*
859 * 'show_attributes()' - Show attributes in a request or response.
860 */
861
862static void
863show_attributes(const char *title, /* I - Title */
864 int request, /* I - 1 for request, 0 for response */
865 ipp_t *ipp) /* I - IPP request/response */
866{
867 int minor, major = ippGetVersion(ipp, &minor);
868 /* IPP version number */
869 ipp_tag_t group = IPP_TAG_ZERO;
870 /* Current group tag */
871 ipp_attribute_t *attr; /* Current attribute */
872 const char *name; /* Attribute name */
873 char buffer[1024]; /* Value */
874
875
876 printf("%s:\n", title);
877 printf(" version=%d.%d\n", major, minor);
878 printf(" request-id=%d\n", ippGetRequestId(ipp));
879 if (!request)
880 printf(" status-code=%s\n", ippErrorString(ippGetStatusCode(ipp)));
881
882 for (attr = ippFirstAttribute(ipp); attr; attr = ippNextAttribute(ipp))
883 {
884 if (group != ippGetGroupTag(attr))
885 {
886 group = ippGetGroupTag(attr);
887 if (group)
888 printf(" %s:\n", ippTagString(group));
889 }
890
891 if ((name = ippGetName(attr)) != NULL)
892 {
893 ippAttributeString(attr, buffer, sizeof(buffer));
894 printf(" %s(%s%s)=%s\n", name, ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)), buffer);
895 }
896 }
897}
898
899
240a27f9
MS
900/*
901 * 'show_capabilities()' - Show printer capabilities.
902 */
903
904static void
905show_capabilities(ipp_t *response) /* I - Printer attributes */
906{
907 int i; /* Looping var */
908 ipp_attribute_t *attr; /* Attribute */
909 char buffer[1024]; /* Attribute value buffer */
4b16c717 910 static const char * const pattrs[] = /* Attributes we want to show */
240a27f9
MS
911 {
912 "copies-default",
913 "copies-supported",
914 "finishings-default",
915 "finishings-ready",
916 "finishings-supported",
917 "media-default",
918 "media-ready",
919 "media-supported",
920 "output-bin-default",
921 "output-bin-supported",
922 "print-color-mode-default",
923 "print-color-mode-supported",
924 "sides-default",
925 "sides-supported",
926 "document-format-default",
927 "document-format-supported",
928 "pwg-raster-document-resolution-supported",
929 "pwg-raster-document-type-supported",
930 "urf-supported"
4b16c717
MS
931 };
932
240a27f9
MS
933
934 puts("CAPABILITIES:");
935 for (i = 0; i < (int)(sizeof(pattrs) / sizeof(pattrs[0])); i ++)
936 {
937 if ((attr = ippFindAttribute(response, pattrs[i], IPP_TAG_ZERO)) != NULL)
938 {
939 ippAttributeString(attr, buffer, sizeof(buffer));
940 printf(" %s=%s\n", pattrs[i], buffer);
941 }
942 }
943}
944
945
946/*
947 * 'usage()' - Show program usage...
948 */
949
950static void
951usage(void)
952{
5535551f
MS
953 puts("Usage: ./testclient printer-uri [options]");
954 puts("Options:");
955 puts(" -d document-format Generate the specified format");
956 puts(" -f print-file Print the named file");
957 puts(" -g Force grayscale printing");
958 puts(" -k Keep temporary files");
e37405ea 959 puts(" -v Be more verbose");
240a27f9 960}