]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/ipp.c
Use peer credentials if the authorization reference is missing a username.
[thirdparty/cups.git] / backend / ipp.c
CommitLineData
c8f9565c 1/*
c9d3f842 2 * "$Id$"
c8f9565c 3 *
6875feac 4 * IPP backend for CUPS.
c8f9565c 5 *
04c7bec1 6 * Copyright 2007-2011 by Apple Inc.
bb3ff448 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
c8f9565c 8 *
9 * These coded instructions, statements, and computer programs are the
4e8d321f 10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
c8f9565c 12 * "LICENSE" which should have been included with this file. If this
4e8d321f 13 * file is missing or damaged, see the license at "http://www.cups.org/".
c8f9565c 14 *
dab1a4d8 15 * This file is subject to the Apple OS-Developed Software exception.
16 *
c8f9565c 17 * Contents:
18 *
d1c2727f 19 * main() - Send a file to the printer or server.
1230a8a0 20 * cancel_job() - Cancel a print job.
b9738d7c 21 * check_printer_state() - Check the printer state.
1230a8a0 22 * compress_files() - Compress print files...
b9738d7c 23 * monitor_printer() - Monitor the printer state...
2ec940b5 24 * new_request() - Create a new print creation or validation request.
d1c2727f 25 * password_cb() - Disable the password prompt for
26 * cupsDoFileRequest().
7c7997c3 27 * report_attr() - Report an IPP attribute value.
d1c2727f 28 * report_printer_state() - Report the printer state.
8f4595eb 29 * sigterm_handler() - Handle 'terminate' signals that stop the backend.
c8f9565c 30 */
31
32/*
33 * Include necessary headers.
34 */
35
eab5b04e 36#include "backend-private.h"
c8f9565c 37#include <sys/types.h>
38#include <sys/stat.h>
1c85e5c0 39#include <sys/wait.h>
c8f9565c 40
b9738d7c 41
42/*
43 * Types...
44 */
45
46typedef struct _cups_monitor_s /**** Monitoring data ****/
47{
48 const char *uri, /* Printer URI */
49 *hostname, /* Hostname */
50 *user, /* Username */
51 *resource; /* Resource path */
52 int port, /* Port number */
53 version, /* IPP version */
54 job_id; /* Job ID for submitted job */
55 http_encryption_t encryption; /* Use encryption? */
56 ipp_jstate_t job_state; /* Current job state */
57 ipp_pstate_t printer_state; /* Current printer state */
58} _cups_monitor_t;
59
60
8f4595eb 61/*
62 * Globals...
63 */
64
4233257e 65static const char *auth_info_required = "none";
66 /* New auth-info-required value */
b9738d7c 67static const char * const jattrs[] = /* Job attributes we want */
68{
69 "job-media-sheets-completed",
70 "job-state",
71 "job-state-reasons"
72};
6875feac 73static int job_canceled = 0; /* Job cancelled? */
b9738d7c 74static char *password = NULL; /* Password for device URI */
75static int password_tries = 0; /* Password tries */
76static const char * const pattrs[] = /* Printer attributes we want */
77{
78 "copies-supported",
79 "cups-version",
80 "document-format-supported",
81 "marker-colors",
82 "marker-high-levels",
83 "marker-levels",
84 "marker-low-levels",
85 "marker-message",
86 "marker-names",
87 "marker-types",
88 "media-col-supported",
e2fe9bbd 89 "operations-supported",
b9738d7c 90 "printer-alert",
91 "printer-alert-description",
92 "printer-is-accepting-jobs",
93 "printer-state",
94 "printer-state-message",
95 "printer-state-reasons",
96};
8f4595eb 97
98
b5cb0608 99/*
100 * Local functions...
101 */
102
b9738d7c 103static void cancel_job(http_t *http, const char *uri, int id,
104 const char *resource, const char *user,
105 int version);
106static ipp_pstate_t check_printer_state(http_t *http, const char *uri,
107 const char *resource,
108 const char *user, int version,
109 int job_id);
1230a8a0 110#ifdef HAVE_LIBZ
b9738d7c 111static void compress_files(int num_files, char **files);
1230a8a0 112#endif /* HAVE_LIBZ */
b9738d7c 113static void *monitor_printer(_cups_monitor_t *monitor);
2ec940b5 114static ipp_t *new_request(ipp_op_t op, int version, const char *uri,
115 const char *user, const char *title,
116 int num_options, cups_option_t *options,
117 const char *compression, int copies,
118 const char *format, _pwg_t *pwg,
119 ipp_attribute_t *media_col_sup);
b9738d7c 120static const char *password_cb(const char *);
121static void report_attr(ipp_attribute_t *attr);
122static int report_printer_state(ipp_t *ipp, int job_id);
123static void sigterm_handler(int sig);
a684a3b0 124
b5cb0608 125
c8f9565c 126/*
127 * 'main()' - Send a file to the printer or server.
128 *
129 * Usage:
130 *
131 * printer-uri job-id user title copies options [file]
132 */
133
74ef1ffb 134int /* O - Exit status */
072c4872 135main(int argc, /* I - Number of command-line args */
74ef1ffb 136 char *argv[]) /* I - Command-line arguments */
c8f9565c 137{
74ef1ffb 138 int i; /* Looping var */
cad2b75f 139 int send_options; /* Send job options? */
74ef1ffb 140 int num_options; /* Number of printer options */
141 cups_option_t *options; /* Printer options */
cda2b561 142 const char *device_uri; /* Device URI */
9fa9ba8f 143 char scheme[255], /* Scheme in URI */
74ef1ffb 144 hostname[1024], /* Hostname */
145 username[255], /* Username info */
146 resource[1024], /* Resource info (printer name) */
a0c0bbe7 147 addrname[256], /* Address name */
74ef1ffb 148 *optptr, /* Pointer to URI options */
abd1f85f 149 *name, /* Name of option */
150 *value, /* Value of option */
151 sep; /* Separator character */
cce0044f 152 http_addrlist_t *addrlist; /* Address of printer */
eab5b04e 153 int snmp_fd, /* SNMP socket */
154 start_count, /* Page count via SNMP at start */
6bffe4a6 155 page_count, /* Page count via SNMP */
156 have_supplies; /* Printer supports supply levels? */
072c4872 157 int num_files; /* Number of files to print */
6875feac 158 char **files; /* Files to print */
74ef1ffb 159 int port; /* Port number (not used) */
cce0044f 160 char portname[255]; /* Port name */
74ef1ffb 161 char uri[HTTP_MAX_URI]; /* Updated URI without user/pass */
6875feac 162 http_status_t http_status; /* Status of HTTP request */
74ef1ffb 163 ipp_status_t ipp_status; /* Status of IPP request */
164 http_t *http; /* HTTP connection */
165 ipp_t *request, /* IPP request */
166 *response, /* IPP response */
167 *supported; /* get-printer-attributes response */
ff0295f0 168 time_t start_time; /* Time of first connect */
ff0295f0 169 int contimeout; /* Connection timeout */
170 int delay; /* Delay for retries... */
2ec940b5 171 const char *compression; /* Compression mode */
172 int waitjob, /* Wait for job complete? */
74ef1ffb 173 waitprinter; /* Wait for printer ready? */
b9738d7c 174 _cups_monitor_t monitor; /* Monitoring data */
74ef1ffb 175 ipp_attribute_t *job_id_attr; /* job-id attribute */
176 int job_id; /* job-id value */
072c4872 177 ipp_attribute_t *job_sheets; /* job-media-sheets-completed */
178 ipp_attribute_t *job_state; /* job-state */
179 ipp_attribute_t *copies_sup; /* copies-supported */
6875feac 180 ipp_attribute_t *cups_version; /* cups-version */
072c4872 181 ipp_attribute_t *format_sup; /* document-format-supported */
6875feac 182 ipp_attribute_t *media_col_sup; /* media-col-supported */
2ec940b5 183 ipp_attribute_t *operations_sup; /* operations-supported */
74ef1ffb 184 ipp_attribute_t *printer_state; /* printer-state attribute */
072c4872 185 ipp_attribute_t *printer_accepting; /* printer-is-accepting-jobs */
2ec940b5 186 int validate_job; /* Does printer support Validate-Job? */
37de726f 187 int copies, /* Number of copies for job */
188 copies_remaining; /* Number of copies remaining */
b43a3371 189 const char *content_type, /* CONTENT_TYPE environment variable */
2ec940b5 190 *final_content_type, /* FINAL_CONTENT_TYPE environment var */
191 *document_format; /* document-format value */
6875feac 192 int fd; /* File descriptor */
193 off_t bytes; /* Bytes copied */
194 char buffer[16384]; /* Copy buffer */
4ff40357 195#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
74ef1ffb 196 struct sigaction action; /* Actions for POSIX signals */
4ff40357 197#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
74ef1ffb 198 int version; /* IPP version */
2ec940b5 199 ppd_file_t *ppd; /* PPD file */
200 _pwg_t *pwg; /* PWG<->PPD mapping data */
c8f9565c 201
4b23f3b3 202
203 /*
204 * Make sure status messages are not buffered...
205 */
206
2922de55 207 setbuf(stderr, NULL);
c8f9565c 208
98904cd6 209 /*
8f4595eb 210 * Ignore SIGPIPE and catch SIGTERM signals...
98904cd6 211 */
212
213#ifdef HAVE_SIGSET
214 sigset(SIGPIPE, SIG_IGN);
8f4595eb 215 sigset(SIGTERM, sigterm_handler);
98904cd6 216#elif defined(HAVE_SIGACTION)
217 memset(&action, 0, sizeof(action));
218 action.sa_handler = SIG_IGN;
219 sigaction(SIGPIPE, &action, NULL);
8f4595eb 220
221 sigemptyset(&action.sa_mask);
222 sigaddset(&action.sa_mask, SIGTERM);
223 action.sa_handler = sigterm_handler;
224 sigaction(SIGTERM, &action, NULL);
98904cd6 225#else
226 signal(SIGPIPE, SIG_IGN);
8f4595eb 227 signal(SIGTERM, sigterm_handler);
98904cd6 228#endif /* HAVE_SIGSET */
229
4b23f3b3 230 /*
231 * Check command-line...
232 */
233
68edc300 234 if (argc == 1)
235 {
183914a3 236 char *s;
237
d4c438d4 238 if ((s = strrchr(argv[0], '/')) != NULL)
239 s ++;
240 else
241 s = argv[0];
242
3037604c 243 printf("network %s \"Unknown\" \"%s (%s)\"\n",
244 s, _cupsLangString(cupsLangDefault(),
245 _("Internet Printing Protocol")), s);
6248387b 246 return (CUPS_BACKEND_OK);
68edc300 247 }
072c4872 248 else if (argc < 6)
c8f9565c 249 {
472af6f3 250 _cupsLangPrintf(stderr,
4c4eea89 251 _("Usage: %s job-id user title copies options [file]"),
472af6f3 252 argv[0]);
6248387b 253 return (CUPS_BACKEND_STOP);
c8f9565c 254 }
255
a684a3b0 256 /*
072c4872 257 * Get the (final) content type...
a684a3b0 258 */
259
b43a3371 260 if ((content_type = getenv("CONTENT_TYPE")) == NULL)
261 content_type = "application/octet-stream";
a684a3b0 262
b43a3371 263 if ((final_content_type = getenv("FINAL_CONTENT_TYPE")) == NULL)
264 {
265 final_content_type = content_type;
266
267 if (!strncmp(final_content_type, "printer/", 8))
268 final_content_type = "application/vnd.cups-raw";
269 }
12d8a513 270
7abb7137 271 /*
272 * Extract the hostname and printer name from the URI...
273 */
274
04c7bec1 275 while ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
276 {
277 _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer."));
278 sleep(10);
279
280 if (getenv("CLASS") != NULL)
281 return (CUPS_BACKEND_FAILED);
282 }
cda2b561 283
9fa9ba8f 284 httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme),
285 username, sizeof(username), hostname, sizeof(hostname), &port,
286 resource, sizeof(resource));
7abb7137 287
6df6deaf 288 if (!port)
289 port = IPP_PORT; /* Default to port 631 */
290
9fa9ba8f 291 if (!strcmp(scheme, "https"))
7abb7137 292 cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
692bbbae 293 else
294 cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
7abb7137 295
897922a9 296 /*
297 * See if there are any options...
298 */
299
2ec940b5 300 compression = NULL;
6875feac 301 version = 20;
897922a9 302 waitjob = 1;
303 waitprinter = 1;
ff0295f0 304 contimeout = 7 * 24 * 60 * 60;
897922a9 305
306 if ((optptr = strchr(resource, '?')) != NULL)
307 {
308 /*
309 * Yup, terminate the device name string and move to the first
310 * character of the optptr...
311 */
312
313 *optptr++ = '\0';
314
315 /*
316 * Then parse the optptr...
317 */
318
319 while (*optptr)
320 {
321 /*
322 * Get the name...
323 */
324
abd1f85f 325 name = optptr;
897922a9 326
abd1f85f 327 while (*optptr && *optptr != '=' && *optptr != '+' && *optptr != '&')
328 optptr ++;
329
330 if ((sep = *optptr) != '\0')
331 *optptr++ = '\0';
332
333 if (sep == '=')
897922a9 334 {
335 /*
336 * Get the value...
337 */
338
abd1f85f 339 value = optptr;
897922a9 340
abd1f85f 341 while (*optptr && *optptr != '+' && *optptr != '&')
897922a9 342 optptr ++;
abd1f85f 343
344 if (*optptr)
345 *optptr++ = '\0';
897922a9 346 }
347 else
abd1f85f 348 value = (char *)"";
897922a9 349
350 /*
351 * Process the option...
352 */
353
354 if (!strcasecmp(name, "waitjob"))
355 {
356 /*
357 * Wait for job completion?
358 */
359
360 waitjob = !strcasecmp(value, "on") ||
361 !strcasecmp(value, "yes") ||
362 !strcasecmp(value, "true");
363 }
364 else if (!strcasecmp(name, "waitprinter"))
365 {
366 /*
367 * Wait for printer idle?
368 */
369
370 waitprinter = !strcasecmp(value, "on") ||
371 !strcasecmp(value, "yes") ||
372 !strcasecmp(value, "true");
373 }
374 else if (!strcasecmp(name, "encryption"))
375 {
376 /*
377 * Enable/disable encryption?
378 */
379
380 if (!strcasecmp(value, "always"))
381 cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
382 else if (!strcasecmp(value, "required"))
383 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
384 else if (!strcasecmp(value, "never"))
385 cupsSetEncryption(HTTP_ENCRYPT_NEVER);
386 else if (!strcasecmp(value, "ifrequested"))
387 cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
388 else
389 {
4c4eea89 390 _cupsLangPrintFilter(stderr, "ERROR",
391 _("Unknown encryption option value: \"%s\"."),
392 value);
897922a9 393 }
394 }
a708af2a 395 else if (!strcasecmp(name, "version"))
396 {
397 if (!strcmp(value, "1.0"))
22d59a30 398 version = 10;
a708af2a 399 else if (!strcmp(value, "1.1"))
22d59a30 400 version = 11;
401 else if (!strcmp(value, "2.0"))
402 version = 20;
403 else if (!strcmp(value, "2.1"))
404 version = 21;
4c4eea89 405 else if (!strcmp(value, "2.2"))
406 version = 22;
a708af2a 407 else
408 {
4c4eea89 409 _cupsLangPrintFilter(stderr, "ERROR",
410 _("Unknown version option value: \"%s\"."),
411 value);
a708af2a 412 }
413 }
1230a8a0 414#ifdef HAVE_LIBZ
415 else if (!strcasecmp(name, "compression"))
416 {
2ec940b5 417 if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") ||
418 !strcasecmp(value, "on") || !strcasecmp(value, "gzip"))
419 compression = "gzip";
1230a8a0 420 }
421#endif /* HAVE_LIBZ */
ff0295f0 422 else if (!strcasecmp(name, "contimeout"))
423 {
424 /*
425 * Set the connection timeout...
426 */
427
428 if (atoi(value) > 0)
429 contimeout = atoi(value);
430 }
897922a9 431 else
432 {
433 /*
434 * Unknown option...
435 */
436
4c4eea89 437 _cupsLangPrintFilter(stderr, "ERROR",
438 _("Unknown option \"%s\" with value \"%s\"."),
439 name, value);
897922a9 440 }
441 }
442 }
443
1230a8a0 444 /*
445 * If we have 7 arguments, print the file named on the command-line.
446 * Otherwise, copy stdin to a temporary file and print the temporary
447 * file.
448 */
449
450 if (argc == 6)
451 {
6875feac 452 num_files = 0;
453 send_options = !strcasecmp(final_content_type, "application/pdf") ||
454 !strcasecmp(final_content_type, "application/vnd.cups-pdf") ||
2ec940b5 455 !strncasecmp(final_content_type, "image/", 6);
6875feac 456
457 fputs("DEBUG: Sending stdin for job...\n", stderr);
1230a8a0 458 }
459 else
460 {
461 /*
462 * Point to the files on the command-line...
463 */
464
b43a3371 465 num_files = argc - 6;
466 files = argv + 6;
467 send_options = 1;
cad2b75f 468
1230a8a0 469#ifdef HAVE_LIBZ
470 if (compression)
471 compress_files(num_files, files);
472#endif /* HAVE_LIBZ */
1230a8a0 473
6875feac 474 fprintf(stderr, "DEBUG: %d files to send in job...\n", num_files);
475 }
1230a8a0 476
c8f9565c 477 /*
b5cb0608 478 * Set the authentication info, if any...
c8f9565c 479 */
480
b5cb0608 481 cupsSetPasswordCB(password_cb);
482
483 if (username[0])
484 {
48e211f3 485 /*
486 * Use authenticaion information in the device URI...
487 */
488
b5cb0608 489 if ((password = strchr(username, ':')) != NULL)
490 *password++ = '\0';
491
492 cupsSetUser(username);
493 }
48e211f3 494 else if (!getuid())
495 {
496 /*
fa1fc704 497 * Try loading authentication information from the environment.
48e211f3 498 */
499
abd1f85f 500 const char *ptr = getenv("AUTH_USERNAME");
501
502 if (ptr)
fa1fc704 503 cupsSetUser(ptr);
48e211f3 504
fa1fc704 505 password = getenv("AUTH_PASSWORD");
48e211f3 506 }
c8f9565c 507
508 /*
cce0044f 509 * Try finding the remote server...
c8f9565c 510 */
511
f831f3d8 512 start_time = time(NULL);
ff0295f0 513
cce0044f 514 sprintf(portname, "%d", port);
515
22a980cc 516 fputs("STATE: +connecting-to-device\n", stderr);
cce0044f 517 fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);
518
519 while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
520 {
521 _cupsLangPrintFilter(stderr, "INFO",
522 _("Unable to locate printer \"%s\"."), hostname);
523 sleep(10);
524
525 if (getenv("CLASS") != NULL)
526 {
527 fputs("STATE: -connecting-to-device\n", stderr);
528 return (CUPS_BACKEND_STOP);
529 }
530 }
531
532 http = _httpCreate(hostname, port, addrlist, cupsEncryption(), AF_UNSPEC);
533
534 /*
535 * See if the printer supports SNMP...
536 */
537
538 if ((snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family)) >= 0)
539 {
540 have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr),
541 &start_count, NULL);
542 }
543 else
544 have_supplies = start_count = 0;
545
546 /*
547 * Wait for data from the filter...
548 */
549
550 if (num_files == 0)
551 if (!backendWaitLoop(snmp_fd, &(addrlist->addr), backendNetworkSideCB))
552 return (CUPS_BACKEND_OK);
553
554 /*
555 * Try connecting to the remote server...
556 */
557
558 delay = 5;
22a980cc 559
97fcaf92 560 do
c8f9565c 561 {
9fa9ba8f 562 fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port);
4c4eea89 563 _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer."));
c8f9565c 564
cce0044f 565 if (httpReconnect(http))
d21a7597 566 {
03a8680a 567 int error = errno; /* Connection error */
568
cce0044f 569 if (http->status == HTTP_PKI_ERROR)
570 fputs("STATE: +cups-certificate-error\n", stderr);
571
6875feac 572 if (job_canceled)
bb3ff448 573 break;
574
997cf8b0 575 if (getenv("CLASS") != NULL)
576 {
577 /*
578 * If the CLASS environment variable is set, the job was submitted
579 * to a class and not to a specific queue. In this case, we want
580 * to abort immediately so that the job can be requeued on the next
581 * available printer in the class.
582 */
583
4c4eea89 584 _cupsLangPrintFilter(stderr, "INFO",
585 _("Unable to contact printer, queuing on next "
586 "printer in class."));
997cf8b0 587
997cf8b0 588 /*
589 * Sleep 5 seconds to keep the job from requeuing too rapidly...
590 */
591
592 sleep(5);
593
cce0044f 594 fputs("STATE: -connecting-to-device\n", stderr);
595
6248387b 596 return (CUPS_BACKEND_FAILED);
997cf8b0 597 }
598
03a8680a 599 fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno));
600
4c2096b8 601 if (errno == ECONNREFUSED || errno == EHOSTDOWN ||
602 errno == EHOSTUNREACH)
97fcaf92 603 {
ff0295f0 604 if (contimeout && (time(NULL) - start_time) > contimeout)
605 {
4c4eea89 606 _cupsLangPrintFilter(stderr, "ERROR",
607 _("The printer is not responding."));
cce0044f 608 fputs("STATE: -connecting-to-device\n", stderr);
ff0295f0 609 return (CUPS_BACKEND_FAILED);
610 }
611
03a8680a 612 switch (error)
613 {
614 case EHOSTDOWN :
4c4eea89 615 _cupsLangPrintFilter(stderr, "WARNING",
616 _("Network printer \"%s\" may not exist or "
617 "is unavailable at this time."),
618 hostname);
03a8680a 619 break;
620
621 case EHOSTUNREACH :
4c4eea89 622 _cupsLangPrintFilter(stderr, "WARNING",
623 _("Network printer \"%s\" is unreachable at "
624 "this time."), hostname);
03a8680a 625 break;
626
627 case ECONNREFUSED :
628 default :
4c4eea89 629 _cupsLangPrintFilter(stderr, "WARNING",
630 _("Network printer \"%s\" is busy."),
631 hostname);
03a8680a 632 break;
633 }
ff0295f0 634
635 sleep(delay);
636
637 if (delay < 30)
638 delay += 5;
97fcaf92 639 }
640 else
641 {
4c4eea89 642 _cupsLangPrintFilter(stderr, "ERROR",
643 _("Network printer \"%s\" is not responding."),
644 hostname);
2cc18dd2 645 sleep(30);
97fcaf92 646 }
bb3ff448 647
6875feac 648 if (job_canceled)
bb3ff448 649 break;
d21a7597 650 }
cce0044f 651 else
652 fputs("STATE: -cups-certificate-error\n", stderr);
c8f9565c 653 }
cce0044f 654 while (http->fd < 0);
c8f9565c 655
6875feac 656 if (job_canceled || !http)
bb3ff448 657 return (CUPS_BACKEND_FAILED);
bb3ff448 658
22a980cc 659 fputs("STATE: -connecting-to-device\n", stderr);
4c4eea89 660 _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));
a4e23897 661
a0c0bbe7 662#ifdef AF_INET6
663 if (http->hostaddr->addr.sa_family == AF_INET6)
ff0295f0 664 fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6)...\n",
665 httpAddrString(http->hostaddr, addrname, sizeof(addrname)),
666 ntohs(http->hostaddr->ipv6.sin6_port));
a0c0bbe7 667 else
668#endif /* AF_INET6 */
669 if (http->hostaddr->addr.sa_family == AF_INET)
ff0295f0 670 fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4)...\n",
671 httpAddrString(http->hostaddr, addrname, sizeof(addrname)),
672 ntohs(http->hostaddr->ipv4.sin_port));
a0c0bbe7 673
c8f9565c 674 /*
675 * Build a URI for the printer and fill the standard IPP attributes for
8ce7c000 676 * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it
677 * might contain username:password information...
c8f9565c 678 */
679
11fdb546 680 httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, NULL, hostname,
681 port, resource);
c8f9565c 682
683 /*
97fcaf92 684 * First validate the destination and see if the device supports multiple
6875feac 685 * copies...
c8f9565c 686 */
687
2ec940b5 688 copies_sup = NULL;
689 cups_version = NULL;
690 format_sup = NULL;
691 media_col_sup = NULL;
692 supported = NULL;
693 operations_sup = NULL;
694 validate_job = 0;
c8f9565c 695
97fcaf92 696 do
c8f9565c 697 {
56f7a531 698 /*
699 * Check for side-channel requests...
700 */
701
702 backendCheckSideChannel(snmp_fd, http->hostaddr);
703
c8f9565c 704 /*
97fcaf92 705 * Build the IPP request...
c8f9565c 706 */
707
e12df069 708 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
22d59a30 709 request->request.op.version[0] = version / 10;
710 request->request.op.version[1] = version % 10;
c8f9565c 711
97fcaf92 712 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
713 NULL, uri);
c8f9565c 714
8f4595eb 715 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
716 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
717 NULL, pattrs);
718
97fcaf92 719 /*
720 * Do the request...
721 */
c8f9565c 722
2054e655 723 fputs("DEBUG: Getting supported attributes...\n", stderr);
a4e23897 724
acd7eb22 725 if (http->version < HTTP_1_1)
6875feac 726 {
8962df79 727 fprintf(stderr, "DEBUG: Printer responded with HTTP version %d.%d.\n",
728 http->version / 100, http->version % 100);
729
4c4eea89 730 _cupsLangPrintFilter(stderr, "ERROR",
731 _("Unable to print: the printer does not conform to "
732 "the IPP standard."));
6875feac 733 exit(CUPS_BACKEND_STOP);
734 }
acd7eb22 735
b9738d7c 736 supported = cupsDoRequest(http, request, resource);
737 ipp_status = cupsLastError();
b5cb0608 738
739 if (ipp_status > IPP_OK_CONFLICT)
c8f9565c 740 {
b9738d7c 741 fprintf(stderr, "DEBUG: Get-Printer-Attributes returned %s.\n",
742 ippErrorString(ipp_status));
743
b5cb0608 744 if (ipp_status == IPP_PRINTER_BUSY ||
745 ipp_status == IPP_SERVICE_UNAVAILABLE)
c8f9565c 746 {
ff0295f0 747 if (contimeout && (time(NULL) - start_time) > contimeout)
748 {
4c4eea89 749 _cupsLangPrintFilter(stderr, "ERROR",
750 _("The printer is not responding."));
ff0295f0 751 return (CUPS_BACKEND_FAILED);
752 }
753
4c4eea89 754 _cupsLangPrintFilter(stderr, "WARNING",
755 _("Network host \"%s\" is busy; will retry in %d "
756 "seconds."), hostname, delay);
ff0295f0 757
41368129 758 report_printer_state(supported, 0);
ff0295f0 759
760 sleep(delay);
761
762 if (delay < 30)
763 delay += 5;
97fcaf92 764 }
b5cb0608 765 else if ((ipp_status == IPP_BAD_REQUEST ||
22d59a30 766 ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10)
c8f9565c 767 {
b5cb0608 768 /*
6875feac 769 * Switch to IPP/1.1 or IPP/1.0...
b5cb0608 770 */
97fcaf92 771
6875feac 772 if (version >= 20)
773 {
4c4eea89 774 _cupsLangPrintFilter(stderr, "INFO",
775 _("Printer does not support IPP/%d.%d, trying "
776 "IPP/%s."), version / 10, version % 10, "1.1");
6875feac 777 version = 11;
778 }
779 else
780 {
4c4eea89 781 _cupsLangPrintFilter(stderr, "INFO",
782 _("Printer does not support IPP/%d.%d, trying "
783 "IPP/%s."), version / 10, version % 10, "1.0");
6875feac 784 version = 10;
785 }
786
a4e23897 787 httpReconnect(http);
c8f9565c 788 }
67474245 789 else if (ipp_status == IPP_NOT_FOUND)
790 {
4c4eea89 791 _cupsLangPrintFilter(stderr, "ERROR",
792 _("The printer URI is incorrect or no longer "
793 "exists."));
67474245 794
795 if (supported)
796 ippDelete(supported);
797
6248387b 798 return (CUPS_BACKEND_STOP);
67474245 799 }
fc7e68cf 800 else if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
801 {
802 if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
803 "Negotiate", 9))
804 auth_info_required = "negotiate";
805
806 fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
807 return (CUPS_BACKEND_AUTH_REQUIRED);
808 }
97fcaf92 809 else
67474245 810 {
4c4eea89 811 _cupsLangPrintFilter(stderr, "ERROR",
812 _("Unable to get printer status: %s"),
813 cupsLastErrorString());
67474245 814 sleep(10);
815 }
d1c2727f 816
817 if (supported)
818 ippDelete(supported);
819
820 continue;
97fcaf92 821 }
6875feac 822
823 /*
824 * Check for supported attributes...
825 */
826
827 if ((copies_sup = ippFindAttribute(supported, "copies-supported",
828 IPP_TAG_RANGE)) != NULL)
97fcaf92 829 {
b5cb0608 830 /*
831 * Has the "copies-supported" attribute - does it have an upper
832 * bound > 1?
833 */
97fcaf92 834
6875feac 835 fprintf(stderr, "DEBUG: copies-supported=%d-%d\n",
836 copies_sup->values[0].range.lower,
837 copies_sup->values[0].range.upper);
838
b5cb0608 839 if (copies_sup->values[0].range.upper <= 1)
840 copies_sup = NULL; /* No */
841 }
97fcaf92 842
6875feac 843 cups_version = ippFindAttribute(supported, "cups-version", IPP_TAG_TEXT);
b5cb0608 844
6875feac 845 if ((format_sup = ippFindAttribute(supported, "document-format-supported",
846 IPP_TAG_MIMETYPE)) != NULL)
b5cb0608 847 {
848 fprintf(stderr, "DEBUG: document-format-supported (%d values)\n",
849 format_sup->num_values);
850 for (i = 0; i < format_sup->num_values; i ++)
851 fprintf(stderr, "DEBUG: [%d] = \"%s\"\n", i,
852 format_sup->values[i].string.text);
c8f9565c 853 }
d1c2727f 854
6875feac 855 if ((media_col_sup = ippFindAttribute(supported, "media-col-supported",
856 IPP_TAG_KEYWORD)) != NULL)
857 {
858 fprintf(stderr, "DEBUG: media-col-supported (%d values)\n",
859 media_col_sup->num_values);
860 for (i = 0; i < media_col_sup->num_values; i ++)
861 fprintf(stderr, "DEBUG: [%d] = \"%s\"\n", i,
862 media_col_sup->values[i].string.text);
863 }
864
2ec940b5 865 if ((operations_sup = ippFindAttribute(supported, "operations-supported",
866 IPP_TAG_ENUM)) != NULL)
867 {
868 for (i = 0; i < operations_sup->num_values; i ++)
869 if (operations_sup->values[i].integer == IPP_VALIDATE_JOB)
870 {
871 validate_job = 1;
872 break;
873 }
874
875 if (!validate_job)
876 {
877 _cupsLangPrintFilter(stderr, "WARNING",
878 _("This printer does not conform to the IPP "
879 "standard and may not work."));
880 fputs("DEBUG: operations-supported does not list Validate-Job.\n",
881 stderr);
882 }
883 }
884 else
885 {
886 _cupsLangPrintFilter(stderr, "WARNING",
887 _("This printer does not conform to the IPP "
888 "standard and may not work."));
889 fputs("DEBUG: operations-supported not returned in "
890 "Get-Printer-Attributes request.\n", stderr);
891 }
892
41368129 893 report_printer_state(supported, 0);
c8f9565c 894 }
97fcaf92 895 while (ipp_status > IPP_OK_CONFLICT);
c8f9565c 896
997cf8b0 897 /*
898 * See if the printer is accepting jobs and is not stopped; if either
899 * condition is true and we are printing to a class, requeue the job...
900 */
901
902 if (getenv("CLASS") != NULL)
903 {
904 printer_state = ippFindAttribute(supported, "printer-state",
905 IPP_TAG_ENUM);
906 printer_accepting = ippFindAttribute(supported, "printer-is-accepting-jobs",
907 IPP_TAG_BOOLEAN);
908
909 if (printer_state == NULL ||
072c4872 910 (printer_state->values[0].integer > IPP_PRINTER_PROCESSING &&
911 waitprinter) ||
997cf8b0 912 printer_accepting == NULL ||
913 !printer_accepting->values[0].boolean)
914 {
915 /*
916 * If the CLASS environment variable is set, the job was submitted
917 * to a class and not to a specific queue. In this case, we want
918 * to abort immediately so that the job can be requeued on the next
919 * available printer in the class.
920 */
921
4c4eea89 922 _cupsLangPrintFilter(stderr, "INFO",
923 _("Unable to contact printer, queuing on next "
924 "printer in class."));
997cf8b0 925
926 ippDelete(supported);
927 httpClose(http);
928
997cf8b0 929 /*
930 * Sleep 5 seconds to keep the job from requeuing too rapidly...
931 */
932
933 sleep(5);
934
6248387b 935 return (CUPS_BACKEND_FAILED);
997cf8b0 936 }
937 }
938
c8f9565c 939 /*
97fcaf92 940 * See if the printer supports multiple copies...
c8f9565c 941 */
942
37de726f 943 copies = atoi(argv[4]);
944
d1c2727f 945 if (copies_sup || argc < 7)
7d52601e 946 {
37de726f 947 copies_remaining = 1;
7d52601e 948
949 if (argc < 7)
950 copies = 1;
951 }
0c5b0932 952 else
37de726f 953 copies_remaining = copies;
0c5b0932 954
2ec940b5 955 /*
956 * Prepare remaining printing options...
957 */
958
959 options = NULL;
960 pwg = NULL;
961
962 if (send_options)
963 {
964 num_options = cupsParseOptions(argv[5], 0, &options);
965
966 if (!cups_version && media_col_sup)
967 {
968 /*
969 * Load the PPD file and generate PWG attribute mapping information...
970 */
971
972 ppd = ppdOpenFile(getenv("PPD"));
973 pwg = _pwgCreateWithPPD(ppd);
974
975 ppdClose(ppd);
976 }
977 }
978 else
979 num_options = 0;
980
981 document_format = NULL;
982
983 if (format_sup != NULL)
984 {
985 for (i = 0; i < format_sup->num_values; i ++)
986 if (!strcasecmp(final_content_type, format_sup->values[i].string.text))
987 {
988 document_format = final_content_type;
989 break;
990 }
cce0044f 991
992 if (!document_format)
993 {
994 for (i = 0; i < format_sup->num_values; i ++)
995 if (!strcasecmp("application/octet-stream",
996 format_sup->values[i].string.text))
997 {
998 document_format = "application/octet-stream";
999 break;
1000 }
1001 }
2ec940b5 1002 }
1003
b9738d7c 1004 /*
1005 * Start monitoring the printer in the background...
1006 */
1007
1008 monitor.uri = uri;
1009 monitor.hostname = hostname;
1010 monitor.user = argv[2];
1011 monitor.resource = resource;
1012 monitor.port = port;
1013 monitor.version = version;
1014 monitor.job_id = 0;
1015 monitor.encryption = cupsEncryption();
1016 monitor.job_state = IPP_JOB_PENDING;
1017 monitor.printer_state = IPP_PRINTER_IDLE;
1018
1019 _cupsThreadCreate((_cups_thread_func_t)monitor_printer, &monitor);
1020
c8f9565c 1021 /*
2ec940b5 1022 * Validate access to the printer...
c8f9565c 1023 */
1024
2ec940b5 1025 while (!job_canceled)
c8f9565c 1026 {
2ec940b5 1027 request = new_request(IPP_VALIDATE_JOB, version, uri, argv[2], argv[3],
1028 num_options, options, compression,
1029 copies_sup ? copies : 1, document_format, pwg,
1030 media_col_sup);
97fcaf92 1031
2ec940b5 1032 ippDelete(cupsDoRequest(http, request, resource));
8ce7c000 1033
2ec940b5 1034 ipp_status = cupsLastError();
97fcaf92 1035
cce0044f 1036 if (ipp_status > IPP_OK_CONFLICT &&
1037 ipp_status != IPP_OPERATION_NOT_SUPPORTED)
6875feac 1038 {
2ec940b5 1039 if (job_canceled)
1040 break;
6875feac 1041
2ec940b5 1042 if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1043 ipp_status == IPP_PRINTER_BUSY)
e7186d00 1044 {
2ec940b5 1045 _cupsLangPrintFilter(stderr, "INFO",
1046 _("Printer busy; will retry in 10 seconds."));
1047 sleep(10);
6875feac 1048 }
1049 else
e7186d00 1050 {
1051 /*
2ec940b5 1052 * Update auth-info-required as needed...
e7186d00 1053 */
1054
2ec940b5 1055 _cupsLangPrintFilter(stderr, "ERROR", "%s", cupsLastErrorString());
b8f3410f 1056
2ec940b5 1057 if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
6875feac 1058 {
2ec940b5 1059 fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n",
1060 httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE));
97fcaf92 1061
2ec940b5 1062 /*
1063 * Normal authentication goes through the password callback, which sets
1064 * auth_info_required to "username,password". Kerberos goes directly
1065 * through GSSAPI, so look for Negotiate in the WWW-Authenticate header
1066 * here and set auth_info_required as needed...
1067 */
6875feac 1068
2ec940b5 1069 if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
1070 "Negotiate", 9))
1071 auth_info_required = "negotiate";
1072 }
753453e4 1073
2ec940b5 1074 goto cleanup;
1075 }
1076 }
1077 else
1078 break;
1079 }
37de726f 1080
2ec940b5 1081 /*
1082 * Then issue the print-job request...
1083 */
6875feac 1084
2ec940b5 1085 job_id = 0;
6875feac 1086
2ec940b5 1087 while (!job_canceled && copies_remaining > 0)
1088 {
1089 /*
1090 * Check for side-channel requests...
1091 */
b9738d7c 1092
2ec940b5 1093 backendCheckSideChannel(snmp_fd, http->hostaddr);
b9738d7c 1094
2ec940b5 1095 /*
1096 * Build the IPP job creation request...
1097 */
6875feac 1098
2ec940b5 1099 if (job_canceled)
1100 break;
753453e4 1101
2ec940b5 1102 request = new_request(num_files > 1 ? IPP_CREATE_JOB : IPP_PRINT_JOB,
1103 version, uri, argv[2], argv[3], num_options, options,
1104 compression, copies_sup ? copies : 1, document_format,
1105 pwg, media_col_sup);
c8f9565c 1106
cb555bcf 1107 /*
b5cb0608 1108 * Do the request...
cb555bcf 1109 */
1110
072c4872 1111 if (num_files > 1)
1112 response = cupsDoRequest(http, request, resource);
b5cb0608 1113 else
6875feac 1114 {
1115 fputs("DEBUG: Sending file using chunking...\n", stderr);
1116 http_status = cupsSendRequest(http, request, resource, 0);
1117 if (http_status == HTTP_CONTINUE && request->state == IPP_DATA)
1118 {
1119 if (num_files == 1)
1120 fd = open(files[0], O_RDONLY);
1121 else
1122 fd = 0;
1123
d2355476 1124 while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
6875feac 1125 {
d2355476 1126 fprintf(stderr, "DEBUG: Read %d bytes...\n", (int)bytes);
1127
e6af41cc 1128 if (cupsWriteRequestData(http, buffer, bytes) != HTTP_CONTINUE)
6875feac 1129 break;
1130 else
1131 {
1132 /*
1133 * Check for side-channel requests...
1134 */
1135
1136 backendCheckSideChannel(snmp_fd, http->hostaddr);
1137 }
1138 }
1139
1140 if (num_files == 1)
1141 close(fd);
1142 }
1143
1144 response = cupsGetResponse(http, resource);
1145 ippDelete(request);
1146 }
072c4872 1147
1148 ipp_status = cupsLastError();
b5cb0608 1149
1150 if (ipp_status > IPP_OK_CONFLICT)
1151 {
753453e4 1152 job_id = 0;
1153
6875feac 1154 if (job_canceled)
072c4872 1155 break;
1156
b5cb0608 1157 if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1158 ipp_status == IPP_PRINTER_BUSY)
1159 {
4c4eea89 1160 _cupsLangPrintFilter(stderr, "INFO",
1161 _("Printer busy; will retry in 10 seconds."));
b5cb0608 1162 sleep(10);
1163 }
1164 else
ebac5c9b 1165 {
1166 /*
1167 * Update auth-info-required as needed...
1168 */
1169
4c4eea89 1170 _cupsLangPrintFilter(stderr, "ERROR",
1171 _("Print file was not accepted: %s"),
1172 cupsLastErrorString());
ebac5c9b 1173
4233257e 1174 if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
ebac5c9b 1175 {
1176 fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n",
1177 httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE));
1178
4233257e 1179 /*
1180 * Normal authentication goes through the password callback, which sets
1181 * auth_info_required to "username,password". Kerberos goes directly
1182 * through GSSAPI, so look for Negotiate in the WWW-Authenticate header
1183 * here and set auth_info_required as needed...
1184 */
1185
ebac5c9b 1186 if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
1187 "Negotiate", 9))
4233257e 1188 auth_info_required = "negotiate";
ebac5c9b 1189 }
1190 }
b5cb0608 1191 }
1192 else if ((job_id_attr = ippFindAttribute(response, "job-id",
1193 IPP_TAG_INTEGER)) == NULL)
97fcaf92 1194 {
4c4eea89 1195 _cupsLangPrintFilter(stderr, "INFO",
1196 _("Print file accepted - job ID unknown."));
b5cb0608 1197 job_id = 0;
1198 }
1199 else
1200 {
b9738d7c 1201 monitor.job_id = job_id = job_id_attr->values[0].integer;
4c4eea89 1202 _cupsLangPrintFilter(stderr, "INFO",
1203 _("Print file accepted - job ID %d."), job_id);
97fcaf92 1204 }
cb555bcf 1205
072c4872 1206 ippDelete(response);
1207
6875feac 1208 if (job_canceled)
072c4872 1209 break;
1210
1211 if (job_id && num_files > 1)
1212 {
1213 for (i = 0; i < num_files; i ++)
1214 {
56f7a531 1215 /*
1216 * Check for side-channel requests...
1217 */
1218
1219 backendCheckSideChannel(snmp_fd, http->hostaddr);
1220
1221 /*
1222 * Send the next file in the job...
1223 */
1224
072c4872 1225 request = ippNewRequest(IPP_SEND_DOCUMENT);
22d59a30 1226 request->request.op.version[0] = version / 10;
1227 request->request.op.version[1] = version % 10;
072c4872 1228
1229 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1230 NULL, uri);
1231
1232 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
1233 job_id);
1234
1235 if (argv[2][0])
1236 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1237 "requesting-user-name", NULL, argv[2]);
1238
1239 if ((i + 1) == num_files)
1240 ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
1241
1242 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1243 "document-format", NULL, content_type);
1244
6875feac 1245 fprintf(stderr, "DEBUG: Sending file %d using chunking...\n", i + 1);
1246 http_status = cupsSendRequest(http, request, resource, 0);
1247 if (http_status == HTTP_CONTINUE && request->state == IPP_DATA &&
1248 (fd = open(files[i], O_RDONLY)) >= 0)
1249 {
1250 while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
1251 {
e6af41cc 1252 if (cupsWriteRequestData(http, buffer, bytes) != HTTP_CONTINUE)
6875feac 1253 break;
1254 else
1255 {
1256 /*
1257 * Check for side-channel requests...
1258 */
1259
1260 backendCheckSideChannel(snmp_fd, http->hostaddr);
1261 }
1262 }
1263
1264 close(fd);
1265 }
acd7eb22 1266
6875feac 1267 ippDelete(cupsGetResponse(http, resource));
1268 ippDelete(request);
072c4872 1269
1270 if (cupsLastError() > IPP_OK_CONFLICT)
1271 {
1272 ipp_status = cupsLastError();
1273
4c4eea89 1274 _cupsLangPrintFilter(stderr, "ERROR",
1275 _("Unable to add file to job: %s"),
1276 cupsLastErrorString());
072c4872 1277 break;
1278 }
1279 }
1280 }
b5cb0608 1281
753453e4 1282 if (ipp_status <= IPP_OK_CONFLICT && argc > 6)
b5cb0608 1283 {
1284 fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1);
37de726f 1285 copies_remaining --;
b5cb0608 1286 }
ab827512 1287 else if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1288 ipp_status == IPP_PRINTER_BUSY)
a04d2365 1289 continue;
ab827512 1290 else
37de726f 1291 copies_remaining --;
8ce7c000 1292
c8f9565c 1293 /*
b5cb0608 1294 * Wait for the job to complete...
c8f9565c 1295 */
1296
897922a9 1297 if (!job_id || !waitjob)
b5cb0608 1298 continue;
1299
4c4eea89 1300 _cupsLangPrintFilter(stderr, "INFO", _("Waiting for job to complete."));
b5cb0608 1301
6875feac 1302 for (delay = 1; !job_canceled;)
c8f9565c 1303 {
56f7a531 1304 /*
1305 * Check for side-channel requests...
1306 */
1307
1308 backendCheckSideChannel(snmp_fd, http->hostaddr);
1309
97fcaf92 1310 /*
b5cb0608 1311 * Build an IPP_GET_JOB_ATTRIBUTES request...
97fcaf92 1312 */
1313
e12df069 1314 request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
22d59a30 1315 request->request.op.version[0] = version / 10;
1316 request->request.op.version[1] = version % 10;
97fcaf92 1317
b5cb0608 1318 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1319 NULL, uri);
3f9cb6c6 1320
b5cb0608 1321 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
1322 job_id);
c8f9565c 1323
ee8b7dd3 1324 if (argv[2][0])
897922a9 1325 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1326 "requesting-user-name", NULL, argv[2]);
ee8b7dd3 1327
8f4595eb 1328 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1329 "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]),
1330 NULL, jattrs);
97fcaf92 1331
1332 /*
b5cb0608 1333 * Do the request...
97fcaf92 1334 */
1335
072c4872 1336 response = cupsDoRequest(http, request, resource);
1337 ipp_status = cupsLastError();
97fcaf92 1338
b5cb0608 1339 if (ipp_status == IPP_NOT_FOUND)
97fcaf92 1340 {
b5cb0608 1341 /*
d1c2727f 1342 * Job has gone away and/or the server has no job history...
b5cb0608 1343 */
97fcaf92 1344
b5cb0608 1345 ippDelete(response);
d1c2727f 1346
1347 ipp_status = IPP_OK;
b5cb0608 1348 break;
97fcaf92 1349 }
1350
b5cb0608 1351 if (ipp_status > IPP_OK_CONFLICT)
6a536282 1352 {
b5cb0608 1353 if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
1354 ipp_status != IPP_PRINTER_BUSY)
97fcaf92 1355 {
072c4872 1356 ippDelete(response);
b5cb0608 1357
4c4eea89 1358 _cupsLangPrintFilter(stderr, "ERROR",
1359 _("Unable to get job attributes: %s"),
1360 cupsLastErrorString());
b5cb0608 1361 break;
97fcaf92 1362 }
6a536282 1363 }
8f4595eb 1364
072c4872 1365 if (response)
97fcaf92 1366 {
8f4595eb 1367 if ((job_state = ippFindAttribute(response, "job-state",
1368 IPP_TAG_ENUM)) != NULL)
97fcaf92 1369 {
8f4595eb 1370 /*
1371 * Stop polling if the job is finished or pending-held...
1372 */
1373
7951315f 1374 if (job_state->values[0].integer > IPP_JOB_STOPPED)
8f4595eb 1375 {
e12df069 1376 if ((job_sheets = ippFindAttribute(response,
1377 "job-media-sheets-completed",
1378 IPP_TAG_INTEGER)) != NULL)
072c4872 1379 fprintf(stderr, "PAGE: total %d\n",
1380 job_sheets->values[0].integer);
ab827512 1381
8f4595eb 1382 ippDelete(response);
1383 break;
1384 }
97fcaf92 1385 }
f3fdb6b2 1386 else
1387 {
1388 /*
1389 * If the printer does not return a job-state attribute, it does not
1390 * conform to the IPP specification - break out immediately and fail
1391 * the job...
1392 */
1393
7a43b482 1394 fputs("DEBUG: No job-state available from printer - stopping queue.\n",
1395 stderr);
f3fdb6b2 1396 ipp_status = IPP_INTERNAL_ERROR;
1397 break;
1398 }
97fcaf92 1399 }
1400
072c4872 1401 ippDelete(response);
d1c2727f 1402
b9738d7c 1403#if 0
b5cb0608 1404 /*
6bb5a528 1405 * Check the printer state and report it if necessary...
b5cb0608 1406 */
c8f9565c 1407
41368129 1408 check_printer_state(http, uri, resource, argv[2], version, job_id);
b9738d7c 1409#endif /* 0 */
d1c2727f 1410
1411 /*
2ce8588b 1412 * Wait 1-10 seconds before polling again...
d1c2727f 1413 */
97fcaf92 1414
2ce8588b 1415 sleep(delay);
1416
1417 delay ++;
1418 if (delay > 10)
1419 delay = 1;
97fcaf92 1420 }
c8f9565c 1421 }
1422
6bb5a528 1423 /*
072c4872 1424 * Cancel the job as needed...
6bb5a528 1425 */
1426
6875feac 1427 if (job_canceled && job_id)
072c4872 1428 cancel_job(http, uri, job_id, resource, argv[2], version);
1429
1430 /*
1431 * Check the printer state and report it if necessary...
1432 */
6bb5a528 1433
41368129 1434 check_printer_state(http, uri, resource, argv[2], version, job_id);
6bb5a528 1435
eab5b04e 1436 /*
1437 * Collect the final page count as needed...
1438 */
1439
6bffe4a6 1440 if (have_supplies &&
eab5b04e 1441 !backendSNMPSupplies(snmp_fd, http->hostaddr, &page_count, NULL) &&
1442 page_count > start_count)
1443 fprintf(stderr, "PAGE: total %d\n", page_count - start_count);
1444
4233257e 1445#ifdef HAVE_GSSAPI
1446 /*
1447 * See if we used Kerberos at all...
1448 */
1449
1450 if (http->gssctx)
1451 auth_info_required = "negotiate";
1452#endif /* HAVE_GSSAPI */
1453
c8f9565c 1454 /*
1455 * Free memory...
1456 */
1457
2ec940b5 1458 cleanup:
1459
1460 cupsFreeOptions(num_options, options);
1461 _pwgDestroy(pwg);
1462
c8f9565c 1463 httpClose(http);
c8f9565c 1464
072c4872 1465 ippDelete(supported);
2922de55 1466
c8f9565c 1467 /*
b8f3410f 1468 * Remove the temporary file(s) if necessary...
c8f9565c 1469 */
1470
1230a8a0 1471#ifdef HAVE_LIBZ
1472 if (compression)
1473 {
1474 for (i = 0; i < num_files; i ++)
1475 unlink(files[i]);
1476 }
1477#endif /* HAVE_LIBZ */
1478
c8f9565c 1479 /*
1480 * Return the queue status...
1481 */
1482
4233257e 1483 fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
1484
1485 if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
3fe655a3 1486 return (CUPS_BACKEND_AUTH_REQUIRED);
f3fdb6b2 1487 else if (ipp_status == IPP_INTERNAL_ERROR)
1488 return (CUPS_BACKEND_STOP);
3fe655a3 1489 else if (ipp_status > IPP_OK_CONFLICT)
1490 return (CUPS_BACKEND_FAILED);
1491 else
83d83f7a 1492 {
4c4eea89 1493 _cupsLangPrintFilter(stderr, "INFO", _("Ready to print."));
3fe655a3 1494 return (CUPS_BACKEND_OK);
83d83f7a 1495 }
b5cb0608 1496}
1497
1498
072c4872 1499/*
1500 * 'cancel_job()' - Cancel a print job.
1501 */
1502
1503static void
1504cancel_job(http_t *http, /* I - HTTP connection */
1505 const char *uri, /* I - printer-uri */
1506 int id, /* I - job-id */
1507 const char *resource, /* I - Resource path */
1508 const char *user, /* I - requesting-user-name */
1509 int version) /* I - IPP version */
1510{
1511 ipp_t *request; /* Cancel-Job request */
1512
1513
4c4eea89 1514 _cupsLangPrintFilter(stderr, "INFO", _("Canceling print job."));
072c4872 1515
1516 request = ippNewRequest(IPP_CANCEL_JOB);
22d59a30 1517 request->request.op.version[0] = version / 10;
1518 request->request.op.version[1] = version % 10;
072c4872 1519
1520 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1521 NULL, uri);
1522 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", id);
1523
1524 if (user && user[0])
1525 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1526 "requesting-user-name", NULL, user);
1527
1528 /*
1529 * Do the request...
1530 */
1531
1532 ippDelete(cupsDoRequest(http, request, resource));
1533
1534 if (cupsLastError() > IPP_OK_CONFLICT)
4c4eea89 1535 _cupsLangPrintFilter(stderr, "ERROR", _("Unable to cancel job: %s"),
1536 cupsLastErrorString());
072c4872 1537}
1538
1539
6bb5a528 1540/*
b9738d7c 1541 * 'check_printer_state()' - Check the printer state.
6bb5a528 1542 */
1543
b9738d7c 1544static ipp_pstate_t /* O - Current printer-state */
e12df069 1545check_printer_state(
1546 http_t *http, /* I - HTTP connection */
1547 const char *uri, /* I - Printer URI */
1548 const char *resource, /* I - Resource path */
1549 const char *user, /* I - Username, if any */
41368129 1550 int version, /* I - IPP version */
b9738d7c 1551 int job_id)
6bb5a528 1552{
b9738d7c 1553 ipp_t *request, /* IPP request */
1554 *response; /* IPP response */
1555 ipp_attribute_t *attr; /* Attribute in response */
1556 ipp_pstate_t printer_state = IPP_PRINTER_STOPPED;
1557 /* Current printer-state */
6bb5a528 1558
1559
1560 /*
b9738d7c 1561 * Send a Get-Printer-Attributes request and log the results...
6bb5a528 1562 */
1563
e12df069 1564 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
22d59a30 1565 request->request.op.version[0] = version / 10;
1566 request->request.op.version[1] = version % 10;
6bb5a528 1567
1568 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
b9738d7c 1569 NULL, uri);
6bb5a528 1570
1571 if (user && user[0])
1572 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
b9738d7c 1573 "requesting-user-name", NULL, user);
6bb5a528 1574
a6ccc6e8 1575 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
b9738d7c 1576 "requested-attributes",
1577 (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
6bb5a528 1578
1579 if ((response = cupsDoRequest(http, request, resource)) != NULL)
1580 {
41368129 1581 report_printer_state(response, job_id);
b9738d7c 1582
1583 if ((attr = ippFindAttribute(response, "printer-state",
1584 IPP_TAG_ENUM)) != NULL)
1585 printer_state = (ipp_pstate_t)attr->values[0].integer;
1586
6bb5a528 1587 ippDelete(response);
1588 }
b9738d7c 1589
1590 /*
1591 * Return the printer-state value...
1592 */
1593
1594 return (printer_state);
6bb5a528 1595}
1596
1597
1230a8a0 1598#ifdef HAVE_LIBZ
1599/*
1600 * 'compress_files()' - Compress print files...
1601 */
1602
1603static void
1604compress_files(int num_files, /* I - Number of files */
1605 char **files) /* I - Files */
1606{
1607 int i, /* Looping var */
1608 fd; /* Temporary file descriptor */
1609 ssize_t bytes; /* Bytes read/written */
1610 size_t total; /* Total bytes read */
1611 cups_file_t *in, /* Input file */
1612 *out; /* Output file */
1613 struct stat outinfo; /* Output file information */
1614 char filename[1024], /* Temporary filename */
1fb9f3e8 1615 buffer[32768]; /* Copy buffer */
1230a8a0 1616
1617
1618 fprintf(stderr, "DEBUG: Compressing %d job files...\n", num_files);
1619 for (i = 0; i < num_files; i ++)
1620 {
1621 if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
1622 {
4c4eea89 1623 _cupsLangPrintError("ERROR", _("Unable to create compressed print file"));
1230a8a0 1624 exit(CUPS_BACKEND_FAILED);
1625 }
1626
1627 if ((out = cupsFileOpenFd(fd, "w9")) == NULL)
1628 {
4c4eea89 1629 _cupsLangPrintError("ERROR", _("Unable to open compressed print file"));
1230a8a0 1630 exit(CUPS_BACKEND_FAILED);
1631 }
1632
1633 if ((in = cupsFileOpen(files[i], "r")) == NULL)
1634 {
4c4eea89 1635 _cupsLangPrintError("ERROR", _("Unable to open print file"));
1230a8a0 1636 cupsFileClose(out);
1637 exit(CUPS_BACKEND_FAILED);
1638 }
1639
1640 total = 0;
1641 while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0)
1642 if (cupsFileWrite(out, buffer, bytes) < bytes)
1643 {
4c4eea89 1644 _cupsLangPrintError("ERROR",
1645 _("Unable to generate compressed print file"));
1230a8a0 1646 cupsFileClose(in);
1647 cupsFileClose(out);
1648 exit(CUPS_BACKEND_FAILED);
1649 }
1650 else
1651 total += bytes;
1652
1653 cupsFileClose(out);
1654 cupsFileClose(in);
1655
1656 files[i] = strdup(filename);
1657
1658 if (!stat(filename, &outinfo))
ff0295f0 1659 fprintf(stderr,
1660 "DEBUG: File %d compressed to %.1f%% of original size, "
1661 CUPS_LLFMT " bytes...\n",
1662 i + 1, 100.0 * outinfo.st_size / total,
1663 CUPS_LLCAST outinfo.st_size);
1230a8a0 1664 }
1665}
1666#endif /* HAVE_LIBZ */
1667
1668
b9738d7c 1669/*
1670 * 'monitor_printer()' - Monitor the printer state...
1671 */
1672
1673static void * /* O - Thread exit code */
1674monitor_printer(
1675 _cups_monitor_t *monitor) /* I - Monitoring data */
1676{
1677 http_t *http; /* Connection to printer */
1678 ipp_t *request, /* IPP request */
1679 *response; /* IPP response */
1680 ipp_attribute_t *attr; /* Attribute in response */
1681 int delay, /* Current delay */
1682 prev_delay, /* Previous delay */
1683 temp_delay; /* Temporary delay value */
1684
1685
1686 /*
1687 * Make a copy of the printer connection...
1688 */
1689
cce0044f 1690 http = _httpCreate(monitor->hostname, monitor->port, NULL, monitor->encryption,
16f98e36 1691 AF_UNSPEC);
b9738d7c 1692 cupsSetPasswordCB(password_cb);
1693
1694 /*
1695 * Loop until the job is canceled, aborted, or completed.
1696 */
1697
1698 delay = 1;
1699 prev_delay = 0;
1700
1701 while (monitor->job_state < IPP_JOB_CANCELED && !job_canceled)
1702 {
1703 /*
1704 * Reconnect to the printer...
1705 */
1706
1707 if (!httpReconnect(http))
1708 {
1709 /*
1710 * Connected, so check on the printer state...
1711 */
1712
1713 monitor->printer_state = check_printer_state(http, monitor->uri,
1714 monitor->resource,
1715 monitor->user,
1716 monitor->version,
1717 monitor->job_id);
1718
1719 if (monitor->job_id > 0)
1720 {
1721 /*
1722 * Check the status of the job itself...
1723 */
1724
1725 request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
1726 request->request.op.version[0] = monitor->version / 10;
1727 request->request.op.version[1] = monitor->version % 10;
1728
1729 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1730 NULL, monitor->uri);
1731 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
1732 monitor->job_id);
1733
1734 if (monitor->user && monitor->user[0])
1735 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1736 "requesting-user-name", NULL, monitor->user);
1737
1738 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1739 "requested-attributes",
1740 (int)(sizeof(jattrs) / sizeof(jattrs[0])), NULL, jattrs);
1741
1742 /*
1743 * Do the request...
1744 */
1745
1746 response = cupsDoRequest(http, request, monitor->resource);
1747
1748 if ((attr = ippFindAttribute(response, "job-state",
1749 IPP_TAG_ENUM)) != NULL)
1750 monitor->job_state = (ipp_jstate_t)attr->values[0].integer;
1751 else
1752 monitor->job_state = IPP_JOB_COMPLETED;
1753
1754 ippDelete(response);
1755 }
1756
1757 /*
1758 * Disconnect from the printer - we'll reconnect on the next poll...
1759 */
1760
1761 _httpDisconnect(http);
1762 }
1763
1764 /*
1765 * Sleep for N seconds, and then update the next sleep time using a
1766 * Fibonacci series (1 1 2 3 5 8)...
1767 */
1768
1769 sleep(delay);
1770
1771 temp_delay = delay;
1772 delay = (delay + prev_delay) % 12;
1773 prev_delay = delay < temp_delay ? 0 : temp_delay;
1774 }
1775
1776 /*
1777 * Cleanup and return...
1778 */
1779
1780 httpClose(http);
1781
1782 return (NULL);
1783}
1784
1785
2ec940b5 1786/*
1787 * 'new_request()' - Create a new print creation or validation request.
1788 */
1789
1790static ipp_t * /* O - Request data */
1791new_request(
1792 ipp_op_t op, /* I - IPP operation code */
1793 int version, /* I - IPP version number */
1794 const char *uri, /* I - printer-uri value */
1795 const char *user, /* I - requesting-user-name value */
1796 const char *title, /* I - job-name value */
1797 int num_options, /* I - Number of options to send */
1798 cups_option_t *options, /* I - Options to send */
1799 const char *compression, /* I - compression value or NULL */
1800 int copies, /* I - copies value or 0 */
1801 const char *format, /* I - documet-format value or NULL */
1802 _pwg_t *pwg, /* I - PWG<->PPD mapping data */
1803 ipp_attribute_t *media_col_sup) /* I - media-col-supported values */
1804{
1805 int i; /* Looping var */
1806 ipp_t *request; /* Request data */
1807 const char *keyword; /* PWG keyword */
1808 _pwg_size_t *size; /* PWG media size */
1809 ipp_t *media_col, /* media-col value */
1810 *media_size; /* media-size value */
1811 const char *media_source, /* media-source value */
1812 *media_type; /* media-type value */
1813
1814
1815 /*
1816 * Create the IPP request...
1817 */
1818
1819 request = ippNewRequest(op);
1820 request->request.op.version[0] = version / 10;
1821 request->request.op.version[1] = version % 10;
1822
1823 fprintf(stderr, "DEBUG: %s IPP/%d.%d\n",
1824 ippOpString(request->request.op.operation_id),
1825 request->request.op.version[0],
1826 request->request.op.version[1]);
1827
1828 /*
1829 * Add standard attributes...
1830 */
1831
1832 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1833 NULL, uri);
1834 fprintf(stderr, "DEBUG: printer-uri=\"%s\"\n", uri);
1835
1836 if (user && *user)
1837 {
1838 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1839 "requesting-user-name", NULL, user);
1840 fprintf(stderr, "DEBUG: requesting-user-name=\"%s\"\n", user);
1841 }
1842
1843 if (title && *title)
1844 {
1845 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
1846 title);
1847 fprintf(stderr, "DEBUG: job-name=\"%s\"\n", title);
1848 }
1849
1850 if (format)
1851 {
1852 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1853 "document-format", NULL, format);
1854 fprintf(stderr, "DEBUG: document-format=\"%s\"\n", format);
1855 }
1856
1857#ifdef HAVE_LIBZ
1858 if (compression)
1859 {
1860 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1861 "compression", NULL, compression);
1862 fprintf(stderr, "DEBUG: compression=\"%s\"\n", compression);
1863 }
1864#endif /* HAVE_LIBZ */
1865
1866 /*
1867 * Handle options on the command-line...
1868 */
1869
1870 if (num_options > 0)
1871 {
1872 if (pwg)
1873 {
1874 /*
1875 * Send standard IPP attributes...
1876 */
1877
1878 if ((keyword = cupsGetOption("PageSize", num_options, options)) == NULL)
1879 keyword = cupsGetOption("media", num_options, options);
1880
1881 if ((size = _pwgGetSize(pwg, keyword)) != NULL)
1882 {
1883 /*
1884 * Add a media-col value...
1885 */
1886
1887 media_size = ippNew();
1888 ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1889 "x-dimension", size->width);
1890 ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1891 "y-dimension", size->length);
1892
1893 media_col = ippNew();
1894 ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size);
1895
1896 media_source = _pwgGetSource(pwg, cupsGetOption("InputSlot",
1897 num_options,
1898 options));
1899 media_type = _pwgGetType(pwg, cupsGetOption("MediaType",
1900 num_options, options));
1901
1902 for (i = 0; i < media_col_sup->num_values; i ++)
1903 {
1904 if (!strcmp(media_col_sup->values[i].string.text,
1905 "media-left-margin"))
1906 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1907 "media-left-margin", size->left);
1908 else if (!strcmp(media_col_sup->values[i].string.text,
1909 "media-bottom-margin"))
1910 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1911 "media-bottom-margin", size->left);
1912 else if (!strcmp(media_col_sup->values[i].string.text,
1913 "media-right-margin"))
1914 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1915 "media-right-margin", size->left);
1916 else if (!strcmp(media_col_sup->values[i].string.text,
1917 "media-top-margin"))
1918 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER,
1919 "media-top-margin", size->left);
1920 else if (!strcmp(media_col_sup->values[i].string.text,
1921 "media-source") && media_source)
1922 ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD,
1923 "media-source", NULL, media_source);
1924 else if (!strcmp(media_col_sup->values[i].string.text,
1925 "media-type") && media_type)
1926 ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD,
1927 "media-type", NULL, media_type);
1928 }
1929
1930 ippAddCollection(request, IPP_TAG_JOB, "media-col", media_col);
1931 }
1932
1933 if ((keyword = cupsGetOption("output-bin", num_options,
1934 options)) == NULL)
1935 keyword = _pwgGetBin(pwg, cupsGetOption("OutputBin", num_options,
1936 options));
1937
1938 if (keyword)
1939 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-bin",
1940 NULL, keyword);
1941
1942 if ((keyword = cupsGetOption("output-mode", num_options,
1943 options)) != NULL)
1944 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-mode",
1945 NULL, keyword);
1946 else if ((keyword = cupsGetOption("ColorModel", num_options,
1947 options)) != NULL)
1948 {
1949 if (!strcasecmp(keyword, "Gray"))
1950 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-mode",
1951 NULL, "monochrome");
1952 else
1953 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-mode",
1954 NULL, "color");
1955 }
1956
1957 if ((keyword = cupsGetOption("print-quality", num_options,
1958 options)) != NULL)
1959 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
1960 atoi(keyword));
1961 else if ((keyword = cupsGetOption("cupsPrintQuality", num_options,
1962 options)) != NULL)
1963 {
1964 if (!strcasecmp(keyword, "draft"))
1965 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
1966 IPP_QUALITY_DRAFT);
1967 else if (!strcasecmp(keyword, "normal"))
1968 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
1969 IPP_QUALITY_NORMAL);
1970 else if (!strcasecmp(keyword, "high"))
1971 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality",
1972 IPP_QUALITY_HIGH);
1973 }
1974
1975 if ((keyword = cupsGetOption("sides", num_options, options)) != NULL)
1976 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
1977 NULL, keyword);
1978 else if (pwg->sides_option &&
1979 (keyword = cupsGetOption(pwg->sides_option, num_options,
1980 options)) != NULL)
1981 {
1982 if (!strcasecmp(keyword, pwg->sides_1sided))
1983 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
1984 NULL, "one-sided");
1985 else if (!strcasecmp(keyword, pwg->sides_2sided_long))
1986 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
1987 NULL, "two-sided-long-edge");
1988 if (!strcasecmp(keyword, pwg->sides_2sided_short))
1989 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides",
1990 NULL, "two-sided-short-edge");
1991 }
1992 }
1993 else
1994 {
1995 /*
1996 * When talking to another CUPS server, send all options...
1997 */
1998
1999 cupsEncodeOptions(request, num_options, options);
2000 }
2001
2002 if (copies > 1)
2003 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", copies);
2004 }
2005
2006 return (request);
2007}
2008
2009
b5cb0608 2010/*
2011 * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
2012 */
2013
072c4872 2014static const char * /* O - Password */
e12df069 2015password_cb(const char *prompt) /* I - Prompt (not used) */
b5cb0608 2016{
2017 (void)prompt;
2018
4233257e 2019 /*
2020 * Remember that we need to authenticate...
2021 */
2022
2023 auth_info_required = "username,password";
2024
acbc1533 2025 if (password && *password && password_tries < 3)
9c85dfbf 2026 {
2027 password_tries ++;
2028
6248387b 2029 return (password);
9c85dfbf 2030 }
6248387b 2031 else
2032 {
2033 /*
4233257e 2034 * Give up after 3 tries or if we don't have a password to begin with...
6248387b 2035 */
2036
4233257e 2037 return (NULL);
6248387b 2038 }
c8f9565c 2039}
2040
2041
7c7997c3 2042/*
2043 * 'report_attr()' - Report an IPP attribute value.
2044 */
2045
2046static void
2047report_attr(ipp_attribute_t *attr) /* I - Attribute */
2048{
2049 int i; /* Looping var */
2050 char value[1024], /* Value string */
2051 *valptr, /* Pointer into value string */
2052 *attrptr; /* Pointer into attribute value */
2053
2054
2055 /*
2056 * Convert the attribute values into quoted strings...
2057 */
2058
2059 for (i = 0, valptr = value;
2060 i < attr->num_values && valptr < (value + sizeof(value) - 10);
2061 i ++)
2062 {
2063 if (i > 0)
2064 *valptr++ = ',';
2065
2066 switch (attr->value_tag)
2067 {
2068 case IPP_TAG_INTEGER :
2069 case IPP_TAG_ENUM :
2070 snprintf(valptr, sizeof(value) - (valptr - value), "%d",
2071 attr->values[i].integer);
2072 valptr += strlen(valptr);
2073 break;
2074
2075 case IPP_TAG_TEXT :
2076 case IPP_TAG_NAME :
2077 case IPP_TAG_KEYWORD :
2078 *valptr++ = '\"';
2079 for (attrptr = attr->values[i].string.text;
2080 *attrptr && valptr < (value + sizeof(value) - 10);
2081 attrptr ++)
2082 {
2083 if (*attrptr == '\\' || *attrptr == '\"')
2084 *valptr++ = '\\';
2085
2086 *valptr++ = *attrptr;
2087 }
2088 *valptr++ = '\"';
2089 break;
2090
2091 default :
2092 /*
2093 * Unsupported value type...
2094 */
2095
2096 return;
2097 }
2098 }
2099
2100 *valptr = '\0';
2101
2102 /*
2103 * Tell the scheduler about the new values...
2104 */
2105
2106 fprintf(stderr, "ATTR: %s=%s\n", attr->name, value);
2107}
2108
2109
c8f9565c 2110/*
d1c2727f 2111 * 'report_printer_state()' - Report the printer state.
2112 */
2113
072c4872 2114static int /* O - Number of reasons shown */
41368129 2115report_printer_state(ipp_t *ipp, /* I - IPP response */
2116 int job_id) /* I - Current job ID */
d1c2727f 2117{
2118 int i; /* Looping var */
d8076497 2119 int count; /* Count of reasons shown... */
b9738d7c 2120 ipp_attribute_t *pa, /* printer-alert */
2121 *pam, /* printer-alert-message */
2122 *psm, /* printer-state-message */
7c7997c3 2123 *reasons, /* printer-state-reasons */
2124 *marker; /* marker-* attributes */
8f4595eb 2125 const char *reason; /* Current reason */
8f4595eb 2126 const char *prefix; /* Prefix for STATE: line */
b9738d7c 2127 char value[1024], /* State/message string */
2128 *valptr; /* Pointer into string */
d1c2727f 2129
2130
b9738d7c 2131 /*
2132 * Report alerts and messages...
2133 */
2134
2135 if ((pa = ippFindAttribute(ipp, "printer-alert", IPP_TAG_TEXT)) != NULL)
2136 report_attr(pa);
2137
2138 if ((pam = ippFindAttribute(ipp, "printer-alert-message",
2139 IPP_TAG_TEXT)) != NULL)
2140 report_attr(pam);
2141
a6ccc6e8 2142 if ((psm = ippFindAttribute(ipp, "printer-state-message",
2143 IPP_TAG_TEXT)) != NULL)
b9738d7c 2144 {
2145 char *ptr; /* Pointer into message */
2146
2147
2148 strlcpy(value, "INFO: ", sizeof(value));
2149 for (ptr = psm->values[0].string.text, valptr = value + 6;
2150 *ptr && valptr < (value + sizeof(value) - 6);
2151 ptr ++)
2152 {
2153 if (*ptr < ' ' && *ptr > 0 && *ptr != '\t')
2154 {
2155 /*
2156 * Substitute "<XX>" for the control character; sprintf is safe because
2157 * we always leave 6 chars free at the end...
2158 */
2159
2160 sprintf(valptr, "<%02X>", *ptr);
2161 valptr += 4;
2162 }
2163 else
2164 *valptr++ = *ptr;
2165 }
2166
2167 *valptr++ = '\n';
57487c71 2168 *valptr = '\0';
b9738d7c 2169
2170 fputs(value, stderr);
2171 }
2172
2173 /*
2174 * Now report printer-state-reasons, filtering out some of the reasons we never
2175 * want to set...
2176 */
a6ccc6e8 2177
d1c2727f 2178 if ((reasons = ippFindAttribute(ipp, "printer-state-reasons",
2179 IPP_TAG_KEYWORD)) == NULL)
2180 return (0);
2181
b9738d7c 2182 value[0] = '\0';
f831f3d8 2183 prefix = "STATE: ";
8f4595eb 2184
b9738d7c 2185 for (i = 0, count = 0, valptr = value; i < reasons->num_values; i ++)
d1c2727f 2186 {
8f4595eb 2187 reason = reasons->values[i].string.text;
2188
f831f3d8 2189 if (strcmp(reason, "paused") &&
2190 strcmp(reason, "com.apple.print.recoverable-warning"))
41368129 2191 {
b9738d7c 2192 strlcpy(valptr, prefix, sizeof(value) - (valptr - value) - 1);
2193 valptr += strlen(valptr);
2194 strlcpy(valptr, reason, sizeof(value) - (valptr - value) - 1);
2195 valptr += strlen(valptr);
41368129 2196
2197 prefix = ",";
2198 }
d1c2727f 2199 }
2200
b9738d7c 2201 if (value[0])
2202 {
2203 *valptr++ = '\n';
57487c71 2204 *valptr = '\0';
b9738d7c 2205 fputs(value, stderr);
2206 }
8f4595eb 2207
7c7997c3 2208 /*
2209 * Relay the current marker-* attribute values...
2210 */
2211
2212 if ((marker = ippFindAttribute(ipp, "marker-colors", IPP_TAG_NAME)) != NULL)
2213 report_attr(marker);
edb24e8f 2214 if ((marker = ippFindAttribute(ipp, "marker-high-levels",
2215 IPP_TAG_INTEGER)) != NULL)
2216 report_attr(marker);
7c7997c3 2217 if ((marker = ippFindAttribute(ipp, "marker-levels",
2218 IPP_TAG_INTEGER)) != NULL)
2219 report_attr(marker);
edb24e8f 2220 if ((marker = ippFindAttribute(ipp, "marker-low-levels",
2221 IPP_TAG_INTEGER)) != NULL)
2222 report_attr(marker);
7c7997c3 2223 if ((marker = ippFindAttribute(ipp, "marker-message", IPP_TAG_TEXT)) != NULL)
2224 report_attr(marker);
2225 if ((marker = ippFindAttribute(ipp, "marker-names", IPP_TAG_NAME)) != NULL)
2226 report_attr(marker);
2227 if ((marker = ippFindAttribute(ipp, "marker-types", IPP_TAG_KEYWORD)) != NULL)
2228 report_attr(marker);
2229
d8076497 2230 return (count);
d1c2727f 2231}
2232
2233
d1c2727f 2234/*
8f4595eb 2235 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
2236 */
2237
2238static void
2239sigterm_handler(int sig) /* I - Signal */
2240{
2241 (void)sig; /* remove compiler warnings... */
2242
6875feac 2243 if (!job_canceled)
072c4872 2244 {
2245 /*
2246 * Flag that the job should be cancelled...
2247 */
2248
6875feac 2249 job_canceled = 1;
072c4872 2250 return;
2251 }
2252
8f4595eb 2253 exit(1);
2254}
2255
2256
2257/*
c9d3f842 2258 * End of "$Id$".
c8f9565c 2259 */