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