]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/ipp.c
Merge changes from CUPS 1.5svn-r9567
[thirdparty/cups.git] / backend / ipp.c
CommitLineData
ef416fc2 1/*
b19ccc9e 2 * "$Id: ipp.c 7948 2008-09-17 00:04:12Z mike $"
ef416fc2 3 *
cc754834 4 * IPP backend for CUPS.
ef416fc2 5 *
0268488e 6 * Copyright 2007-2011 by Apple Inc.
7594b224 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
ef416fc2 12 * "LICENSE" which should have been included with this file. If this
bc44d920 13 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
19 * main() - Send a file to the printer or server.
b423cd4c 20 * cancel_job() - Cancel a print job.
7cf5915e 21 * check_printer_state() - Check the printer state.
b423cd4c 22 * compress_files() - Compress print files...
7cf5915e 23 * monitor_printer() - Monitor the printer state...
0268488e 24 * new_request() - Create a new print creation or validation request.
ef416fc2 25 * password_cb() - Disable the password prompt for
26 * cupsDoFileRequest().
1f0275e3 27 * report_attr() - Report an IPP attribute value.
ef416fc2 28 * report_printer_state() - Report the printer state.
ef416fc2 29 * sigterm_handler() - Handle 'terminate' signals that stop the backend.
30 */
31
32/*
33 * Include necessary headers.
34 */
35
7a14d768 36#include "backend-private.h"
ef416fc2 37#include <sys/types.h>
38#include <sys/stat.h>
ef416fc2 39#include <sys/wait.h>
40
7cf5915e
MS
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
ef416fc2 61/*
62 * Globals...
63 */
64
18ecb428
MS
65static const char *auth_info_required = "none";
66 /* New auth-info-required value */
7cf5915e
MS
67static const char * const jattrs[] = /* Job attributes we want */
68{
69 "job-media-sheets-completed",
70 "job-state",
71 "job-state-reasons"
72};
cc754834 73static int job_canceled = 0; /* Job cancelled? */
7cf5915e
MS
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",
c8fef167 89 "operations-supported",
7cf5915e
MS
90 "printer-alert",
91 "printer-alert-description",
92 "printer-is-accepting-jobs",
93 "printer-state",
94 "printer-state-message",
95 "printer-state-reasons",
96};
ef416fc2 97
98
99/*
100 * Local functions...
101 */
102
7cf5915e
MS
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);
b423cd4c 110#ifdef HAVE_LIBZ
7cf5915e 111static void compress_files(int num_files, char **files);
b423cd4c 112#endif /* HAVE_LIBZ */
7cf5915e 113static void *monitor_printer(_cups_monitor_t *monitor);
0268488e
MS
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);
7cf5915e
MS
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);
ef416fc2 124
125
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
134int /* O - Exit status */
bd7854cb 135main(int argc, /* I - Number of command-line args */
ef416fc2 136 char *argv[]) /* I - Command-line arguments */
137{
138 int i; /* Looping var */
b94498cf 139 int send_options; /* Send job options? */
ef416fc2 140 int num_options; /* Number of printer options */
141 cups_option_t *options; /* Printer options */
1f0275e3 142 const char *device_uri; /* Device URI */
acb056cb 143 char scheme[255], /* Scheme in URI */
ef416fc2 144 hostname[1024], /* Hostname */
145 username[255], /* Username info */
146 resource[1024], /* Resource info (printer name) */
26d47ec6 147 addrname[256], /* Address name */
ef416fc2 148 *optptr, /* Pointer to URI options */
db1f069b
MS
149 *name, /* Name of option */
150 *value, /* Value of option */
151 sep; /* Separator character */
c8fef167 152 http_addrlist_t *addrlist; /* Address of printer */
7a14d768
MS
153 int snmp_fd, /* SNMP socket */
154 start_count, /* Page count via SNMP at start */
426c6a59
MS
155 page_count, /* Page count via SNMP */
156 have_supplies; /* Printer supports supply levels? */
bd7854cb 157 int num_files; /* Number of files to print */
cc754834 158 char **files; /* Files to print */
ef416fc2 159 int port; /* Port number (not used) */
c8fef167 160 char portname[255]; /* Port name */
ef416fc2 161 char uri[HTTP_MAX_URI]; /* Updated URI without user/pass */
cc754834 162 http_status_t http_status; /* Status of HTTP request */
ef416fc2 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 */
c0e1af83 168 time_t start_time; /* Time of first connect */
c0e1af83 169 int contimeout; /* Connection timeout */
170 int delay; /* Delay for retries... */
0268488e
MS
171 const char *compression; /* Compression mode */
172 int waitjob, /* Wait for job complete? */
ef416fc2 173 waitprinter; /* Wait for printer ready? */
7cf5915e 174 _cups_monitor_t monitor; /* Monitoring data */
ef416fc2 175 ipp_attribute_t *job_id_attr; /* job-id attribute */
176 int job_id; /* job-id value */
bd7854cb 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 */
cc754834 180 ipp_attribute_t *cups_version; /* cups-version */
bd7854cb 181 ipp_attribute_t *format_sup; /* document-format-supported */
cc754834 182 ipp_attribute_t *media_col_sup; /* media-col-supported */
0268488e 183 ipp_attribute_t *operations_sup; /* operations-supported */
ef416fc2 184 ipp_attribute_t *printer_state; /* printer-state attribute */
bd7854cb 185 ipp_attribute_t *printer_accepting; /* printer-is-accepting-jobs */
0268488e 186 int validate_job; /* Does printer support Validate-Job? */
d09495fa 187 int copies, /* Number of copies for job */
188 copies_remaining; /* Number of copies remaining */
c277e2f8 189 const char *content_type, /* CONTENT_TYPE environment variable */
0268488e
MS
190 *final_content_type, /* FINAL_CONTENT_TYPE environment var */
191 *document_format; /* document-format value */
cc754834
MS
192 int fd; /* File descriptor */
193 off_t bytes; /* Bytes copied */
194 char buffer[16384]; /* Copy buffer */
ef416fc2 195#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
196 struct sigaction action; /* Actions for POSIX signals */
197#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
198 int version; /* IPP version */
0268488e
MS
199 ppd_file_t *ppd; /* PPD file */
200 _pwg_t *pwg; /* PWG<->PPD mapping data */
ef416fc2 201
202
203 /*
204 * Make sure status messages are not buffered...
205 */
206
207 setbuf(stderr, NULL);
208
209 /*
210 * Ignore SIGPIPE and catch SIGTERM signals...
211 */
212
213#ifdef HAVE_SIGSET
214 sigset(SIGPIPE, SIG_IGN);
215 sigset(SIGTERM, sigterm_handler);
216#elif defined(HAVE_SIGACTION)
217 memset(&action, 0, sizeof(action));
218 action.sa_handler = SIG_IGN;
219 sigaction(SIGPIPE, &action, NULL);
220
221 sigemptyset(&action.sa_mask);
222 sigaddset(&action.sa_mask, SIGTERM);
223 action.sa_handler = sigterm_handler;
224 sigaction(SIGTERM, &action, NULL);
225#else
226 signal(SIGPIPE, SIG_IGN);
227 signal(SIGTERM, sigterm_handler);
228#endif /* HAVE_SIGSET */
229
230 /*
231 * Check command-line...
232 */
233
234 if (argc == 1)
235 {
236 char *s;
237
238 if ((s = strrchr(argv[0], '/')) != NULL)
239 s ++;
240 else
241 s = argv[0];
242
8b450588
MS
243 printf("network %s \"Unknown\" \"%s (%s)\"\n",
244 s, _cupsLangString(cupsLangDefault(),
245 _("Internet Printing Protocol")), s);
ef416fc2 246 return (CUPS_BACKEND_OK);
247 }
bd7854cb 248 else if (argc < 6)
ef416fc2 249 {
db1f069b 250 _cupsLangPrintf(stderr,
0837b7e8 251 _("Usage: %s job-id user title copies options [file]"),
db1f069b 252 argv[0]);
ef416fc2 253 return (CUPS_BACKEND_STOP);
254 }
255
256 /*
bd7854cb 257 * Get the (final) content type...
ef416fc2 258 */
259
c277e2f8
MS
260 if ((content_type = getenv("CONTENT_TYPE")) == NULL)
261 content_type = "application/octet-stream";
ef416fc2 262
c277e2f8
MS
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 }
d09495fa 270
ef416fc2 271 /*
272 * Extract the hostname and printer name from the URI...
273 */
274
0268488e
MS
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 }
1f0275e3 283
acb056cb
MS
284 httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme),
285 username, sizeof(username), hostname, sizeof(hostname), &port,
286 resource, sizeof(resource));
ef416fc2 287
a41f09e2
MS
288 if (!port)
289 port = IPP_PORT; /* Default to port 631 */
290
acb056cb 291 if (!strcmp(scheme, "https"))
ef416fc2 292 cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
8ca02f3c 293 else
294 cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
ef416fc2 295
ef416fc2 296 /*
297 * See if there are any options...
298 */
299
0268488e 300 compression = NULL;
cc754834 301 version = 20;
ef416fc2 302 waitjob = 1;
303 waitprinter = 1;
c0e1af83 304 contimeout = 7 * 24 * 60 * 60;
ef416fc2 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
db1f069b 325 name = optptr;
ef416fc2 326
db1f069b
MS
327 while (*optptr && *optptr != '=' && *optptr != '+' && *optptr != '&')
328 optptr ++;
329
330 if ((sep = *optptr) != '\0')
331 *optptr++ = '\0';
332
333 if (sep == '=')
ef416fc2 334 {
335 /*
336 * Get the value...
337 */
338
db1f069b 339 value = optptr;
ef416fc2 340
db1f069b 341 while (*optptr && *optptr != '+' && *optptr != '&')
ef416fc2 342 optptr ++;
db1f069b
MS
343
344 if (*optptr)
345 *optptr++ = '\0';
ef416fc2 346 }
347 else
db1f069b 348 value = (char *)"";
ef416fc2 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 {
0837b7e8
MS
390 _cupsLangPrintFilter(stderr, "ERROR",
391 _("Unknown encryption option value: \"%s\"."),
392 value);
ef416fc2 393 }
394 }
395 else if (!strcasecmp(name, "version"))
396 {
397 if (!strcmp(value, "1.0"))
c168a833 398 version = 10;
ef416fc2 399 else if (!strcmp(value, "1.1"))
c168a833
MS
400 version = 11;
401 else if (!strcmp(value, "2.0"))
402 version = 20;
403 else if (!strcmp(value, "2.1"))
404 version = 21;
0837b7e8
MS
405 else if (!strcmp(value, "2.2"))
406 version = 22;
ef416fc2 407 else
408 {
0837b7e8
MS
409 _cupsLangPrintFilter(stderr, "ERROR",
410 _("Unknown version option value: \"%s\"."),
411 value);
ef416fc2 412 }
413 }
b423cd4c 414#ifdef HAVE_LIBZ
415 else if (!strcasecmp(name, "compression"))
416 {
0268488e
MS
417 if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") ||
418 !strcasecmp(value, "on") || !strcasecmp(value, "gzip"))
419 compression = "gzip";
b423cd4c 420 }
421#endif /* HAVE_LIBZ */
c0e1af83 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 }
ef416fc2 431 else
432 {
433 /*
434 * Unknown option...
435 */
436
0837b7e8
MS
437 _cupsLangPrintFilter(stderr, "ERROR",
438 _("Unknown option \"%s\" with value \"%s\"."),
439 name, value);
ef416fc2 440 }
441 }
442 }
443
b423cd4c 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 {
cc754834
MS
452 num_files = 0;
453 send_options = !strcasecmp(final_content_type, "application/pdf") ||
454 !strcasecmp(final_content_type, "application/vnd.cups-pdf") ||
0268488e 455 !strncasecmp(final_content_type, "image/", 6);
cc754834
MS
456
457 fputs("DEBUG: Sending stdin for job...\n", stderr);
b423cd4c 458 }
459 else
460 {
461 /*
462 * Point to the files on the command-line...
463 */
464
c277e2f8
MS
465 num_files = argc - 6;
466 files = argv + 6;
467 send_options = 1;
b94498cf 468
b423cd4c 469#ifdef HAVE_LIBZ
470 if (compression)
471 compress_files(num_files, files);
472#endif /* HAVE_LIBZ */
b423cd4c 473
cc754834
MS
474 fprintf(stderr, "DEBUG: %d files to send in job...\n", num_files);
475 }
b423cd4c 476
ef416fc2 477 /*
478 * Set the authentication info, if any...
479 */
480
481 cupsSetPasswordCB(password_cb);
482
483 if (username[0])
484 {
485 /*
486 * Use authenticaion information in the device URI...
487 */
488
489 if ((password = strchr(username, ':')) != NULL)
490 *password++ = '\0';
491
492 cupsSetUser(username);
493 }
494 else if (!getuid())
495 {
496 /*
09a101d6 497 * Try loading authentication information from the environment.
ef416fc2 498 */
499
db1f069b
MS
500 const char *ptr = getenv("AUTH_USERNAME");
501
502 if (ptr)
09a101d6 503 cupsSetUser(ptr);
ef416fc2 504
09a101d6 505 password = getenv("AUTH_PASSWORD");
ef416fc2 506 }
507
508 /*
c8fef167 509 * Try finding the remote server...
ef416fc2 510 */
511
4d301e69 512 start_time = time(NULL);
c0e1af83 513
c8fef167
MS
514 sprintf(portname, "%d", port);
515
757d2cad 516 fputs("STATE: +connecting-to-device\n", stderr);
c8fef167
MS
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;
757d2cad 559
ef416fc2 560 do
561 {
acb056cb 562 fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port);
0837b7e8 563 _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer."));
ef416fc2 564
c8fef167 565 if (httpReconnect(http))
ef416fc2 566 {
c7017ecc
MS
567 int error = errno; /* Connection error */
568
c8fef167
MS
569 if (http->status == HTTP_PKI_ERROR)
570 fputs("STATE: +cups-certificate-error\n", stderr);
571
cc754834 572 if (job_canceled)
7594b224 573 break;
574
ef416fc2 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
0837b7e8
MS
584 _cupsLangPrintFilter(stderr, "INFO",
585 _("Unable to contact printer, queuing on next "
586 "printer in class."));
ef416fc2 587
ef416fc2 588 /*
589 * Sleep 5 seconds to keep the job from requeuing too rapidly...
590 */
591
592 sleep(5);
593
c8fef167
MS
594 fputs("STATE: -connecting-to-device\n", stderr);
595
ef416fc2 596 return (CUPS_BACKEND_FAILED);
597 }
598
c7017ecc
MS
599 fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno));
600
ef416fc2 601 if (errno == ECONNREFUSED || errno == EHOSTDOWN ||
602 errno == EHOSTUNREACH)
603 {
c0e1af83 604 if (contimeout && (time(NULL) - start_time) > contimeout)
605 {
0837b7e8
MS
606 _cupsLangPrintFilter(stderr, "ERROR",
607 _("The printer is not responding."));
c8fef167 608 fputs("STATE: -connecting-to-device\n", stderr);
c0e1af83 609 return (CUPS_BACKEND_FAILED);
610 }
611
c7017ecc
MS
612 switch (error)
613 {
614 case EHOSTDOWN :
0837b7e8
MS
615 _cupsLangPrintFilter(stderr, "WARNING",
616 _("Network printer \"%s\" may not exist or "
617 "is unavailable at this time."),
618 hostname);
c7017ecc
MS
619 break;
620
621 case EHOSTUNREACH :
0837b7e8
MS
622 _cupsLangPrintFilter(stderr, "WARNING",
623 _("Network printer \"%s\" is unreachable at "
624 "this time."), hostname);
c7017ecc
MS
625 break;
626
627 case ECONNREFUSED :
628 default :
0837b7e8
MS
629 _cupsLangPrintFilter(stderr, "WARNING",
630 _("Network printer \"%s\" is busy."),
631 hostname);
c7017ecc
MS
632 break;
633 }
c0e1af83 634
635 sleep(delay);
636
637 if (delay < 30)
638 delay += 5;
ef416fc2 639 }
ef416fc2 640 else
641 {
0837b7e8
MS
642 _cupsLangPrintFilter(stderr, "ERROR",
643 _("Network printer \"%s\" is not responding."),
644 hostname);
ef416fc2 645 sleep(30);
646 }
7594b224 647
cc754834 648 if (job_canceled)
7594b224 649 break;
ef416fc2 650 }
c8fef167
MS
651 else
652 fputs("STATE: -cups-certificate-error\n", stderr);
ef416fc2 653 }
c8fef167 654 while (http->fd < 0);
ef416fc2 655
cc754834 656 if (job_canceled || !http)
7594b224 657 return (CUPS_BACKEND_FAILED);
7594b224 658
757d2cad 659 fputs("STATE: -connecting-to-device\n", stderr);
0837b7e8 660 _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));
ef416fc2 661
26d47ec6 662#ifdef AF_INET6
663 if (http->hostaddr->addr.sa_family == AF_INET6)
c0e1af83 664 fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6)...\n",
665 httpAddrString(http->hostaddr, addrname, sizeof(addrname)),
666 ntohs(http->hostaddr->ipv6.sin6_port));
26d47ec6 667 else
668#endif /* AF_INET6 */
669 if (http->hostaddr->addr.sa_family == AF_INET)
670 fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4)...\n",
c0e1af83 671 httpAddrString(http->hostaddr, addrname, sizeof(addrname)),
672 ntohs(http->hostaddr->ipv4.sin_port));
26d47ec6 673
ef416fc2 674 /*
675 * Build a URI for the printer and fill the standard IPP attributes for
676 * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it
677 * might contain username:password information...
678 */
679
acb056cb
MS
680 httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, NULL, hostname,
681 port, resource);
ef416fc2 682
683 /*
684 * First validate the destination and see if the device supports multiple
cc754834 685 * copies...
ef416fc2 686 */
687
0268488e
MS
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;
ef416fc2 695
696 do
697 {
7a14d768
MS
698 /*
699 * Check for side-channel requests...
700 */
701
702 backendCheckSideChannel(snmp_fd, http->hostaddr);
703
ef416fc2 704 /*
705 * Build the IPP request...
706 */
707
fa73b229 708 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
c168a833
MS
709 request->request.op.version[0] = version / 10;
710 request->request.op.version[1] = version % 10;
ef416fc2 711
712 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
713 NULL, uri);
714
715 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
716 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
717 NULL, pattrs);
718
719 /*
720 * Do the request...
721 */
722
723 fputs("DEBUG: Getting supported attributes...\n", stderr);
724
97c9a8d7 725 if (http->version < HTTP_1_1)
cc754834 726 {
c7017ecc
MS
727 fprintf(stderr, "DEBUG: Printer responded with HTTP version %d.%d.\n",
728 http->version / 100, http->version % 100);
729
0837b7e8
MS
730 _cupsLangPrintFilter(stderr, "ERROR",
731 _("Unable to print: the printer does not conform to "
732 "the IPP standard."));
cc754834
MS
733 exit(CUPS_BACKEND_STOP);
734 }
97c9a8d7 735
7cf5915e
MS
736 supported = cupsDoRequest(http, request, resource);
737 ipp_status = cupsLastError();
ef416fc2 738
739 if (ipp_status > IPP_OK_CONFLICT)
740 {
7cf5915e
MS
741 fprintf(stderr, "DEBUG: Get-Printer-Attributes returned %s.\n",
742 ippErrorString(ipp_status));
743
ef416fc2 744 if (ipp_status == IPP_PRINTER_BUSY ||
745 ipp_status == IPP_SERVICE_UNAVAILABLE)
746 {
c0e1af83 747 if (contimeout && (time(NULL) - start_time) > contimeout)
748 {
0837b7e8
MS
749 _cupsLangPrintFilter(stderr, "ERROR",
750 _("The printer is not responding."));
c0e1af83 751 return (CUPS_BACKEND_FAILED);
752 }
753
0837b7e8
MS
754 _cupsLangPrintFilter(stderr, "WARNING",
755 _("Network host \"%s\" is busy; will retry in %d "
756 "seconds."), hostname, delay);
c0e1af83 757
db1f069b 758 report_printer_state(supported, 0);
c0e1af83 759
760 sleep(delay);
761
762 if (delay < 30)
763 delay += 5;
ef416fc2 764 }
765 else if ((ipp_status == IPP_BAD_REQUEST ||
c168a833 766 ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10)
ef416fc2 767 {
768 /*
cc754834 769 * Switch to IPP/1.1 or IPP/1.0...
ef416fc2 770 */
771
cc754834
MS
772 if (version >= 20)
773 {
0837b7e8
MS
774 _cupsLangPrintFilter(stderr, "INFO",
775 _("Printer does not support IPP/%d.%d, trying "
776 "IPP/%s."), version / 10, version % 10, "1.1");
cc754834
MS
777 version = 11;
778 }
779 else
780 {
0837b7e8
MS
781 _cupsLangPrintFilter(stderr, "INFO",
782 _("Printer does not support IPP/%d.%d, trying "
783 "IPP/%s."), version / 10, version % 10, "1.0");
cc754834
MS
784 version = 10;
785 }
786
ef416fc2 787 httpReconnect(http);
788 }
789 else if (ipp_status == IPP_NOT_FOUND)
790 {
0837b7e8
MS
791 _cupsLangPrintFilter(stderr, "ERROR",
792 _("The printer URI is incorrect or no longer "
793 "exists."));
ef416fc2 794
795 if (supported)
796 ippDelete(supported);
797
798 return (CUPS_BACKEND_STOP);
799 }
41681883
MS
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 }
ef416fc2 809 else
810 {
0837b7e8
MS
811 _cupsLangPrintFilter(stderr, "ERROR",
812 _("Unable to get printer status: %s"),
813 cupsLastErrorString());
ef416fc2 814 sleep(10);
815 }
816
817 if (supported)
818 ippDelete(supported);
819
820 continue;
821 }
cc754834
MS
822
823 /*
824 * Check for supported attributes...
825 */
826
827 if ((copies_sup = ippFindAttribute(supported, "copies-supported",
828 IPP_TAG_RANGE)) != NULL)
ef416fc2 829 {
830 /*
831 * Has the "copies-supported" attribute - does it have an upper
832 * bound > 1?
833 */
834
cc754834
MS
835 fprintf(stderr, "DEBUG: copies-supported=%d-%d\n",
836 copies_sup->values[0].range.lower,
837 copies_sup->values[0].range.upper);
838
ef416fc2 839 if (copies_sup->values[0].range.upper <= 1)
840 copies_sup = NULL; /* No */
841 }
842
cc754834 843 cups_version = ippFindAttribute(supported, "cups-version", IPP_TAG_TEXT);
ef416fc2 844
cc754834
MS
845 if ((format_sup = ippFindAttribute(supported, "document-format-supported",
846 IPP_TAG_MIMETYPE)) != NULL)
ef416fc2 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);
853 }
854
cc754834
MS
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
0268488e
MS
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
db1f069b 893 report_printer_state(supported, 0);
ef416fc2 894 }
895 while (ipp_status > IPP_OK_CONFLICT);
896
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 ||
bd7854cb 910 (printer_state->values[0].integer > IPP_PRINTER_PROCESSING &&
911 waitprinter) ||
ef416fc2 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
0837b7e8
MS
922 _cupsLangPrintFilter(stderr, "INFO",
923 _("Unable to contact printer, queuing on next "
924 "printer in class."));
ef416fc2 925
926 ippDelete(supported);
927 httpClose(http);
928
ef416fc2 929 /*
930 * Sleep 5 seconds to keep the job from requeuing too rapidly...
931 */
932
933 sleep(5);
934
935 return (CUPS_BACKEND_FAILED);
936 }
937 }
938
939 /*
940 * See if the printer supports multiple copies...
941 */
942
d09495fa 943 copies = atoi(argv[4]);
944
ef416fc2 945 if (copies_sup || argc < 7)
d09495fa 946 {
947 copies_remaining = 1;
948
949 if (argc < 7)
950 copies = 1;
951 }
ef416fc2 952 else
d09495fa 953 copies_remaining = copies;
ef416fc2 954
0268488e
MS
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 }
c8fef167
MS
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 }
0268488e
MS
1002 }
1003
7cf5915e
MS
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
ef416fc2 1021 /*
0268488e 1022 * Validate access to the printer...
ef416fc2 1023 */
1024
0268488e 1025 while (!job_canceled)
ef416fc2 1026 {
0268488e
MS
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);
b423cd4c 1031
0268488e 1032 ippDelete(cupsDoRequest(http, request, resource));
ef416fc2 1033
0268488e 1034 ipp_status = cupsLastError();
ef416fc2 1035
c8fef167
MS
1036 if (ipp_status > IPP_OK_CONFLICT &&
1037 ipp_status != IPP_OPERATION_NOT_SUPPORTED)
cc754834 1038 {
0268488e
MS
1039 if (job_canceled)
1040 break;
cc754834 1041
0268488e
MS
1042 if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1043 ipp_status == IPP_PRINTER_BUSY)
ef416fc2 1044 {
0268488e
MS
1045 _cupsLangPrintFilter(stderr, "INFO",
1046 _("Printer busy; will retry in 10 seconds."));
1047 sleep(10);
cc754834
MS
1048 }
1049 else
ef416fc2 1050 {
1051 /*
0268488e 1052 * Update auth-info-required as needed...
ef416fc2 1053 */
1054
0268488e 1055 _cupsLangPrintFilter(stderr, "ERROR", "%s", cupsLastErrorString());
d9bca400 1056
0268488e 1057 if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
cc754834 1058 {
0268488e
MS
1059 fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n",
1060 httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE));
ef416fc2 1061
0268488e
MS
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 */
cc754834 1068
0268488e
MS
1069 if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
1070 "Negotiate", 9))
1071 auth_info_required = "negotiate";
1072 }
ef416fc2 1073
0268488e
MS
1074 goto cleanup;
1075 }
1076 }
1077 else
1078 break;
1079 }
cc754834 1080
0268488e
MS
1081 /*
1082 * Then issue the print-job request...
1083 */
cc754834 1084
0268488e 1085 job_id = 0;
7cf5915e 1086
0268488e
MS
1087 while (!job_canceled && copies_remaining > 0)
1088 {
1089 /*
1090 * Check for side-channel requests...
1091 */
cc754834 1092
0268488e 1093 backendCheckSideChannel(snmp_fd, http->hostaddr);
7cf5915e 1094
0268488e
MS
1095 /*
1096 * Build the IPP job creation request...
1097 */
d09495fa 1098
0268488e
MS
1099 if (job_canceled)
1100 break;
ef416fc2 1101
0268488e
MS
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);
ef416fc2 1106
ef416fc2 1107 /*
1108 * Do the request...
1109 */
1110
bd7854cb 1111 if (num_files > 1)
1112 response = cupsDoRequest(http, request, resource);
ef416fc2 1113 else
cc754834
MS
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
1124 while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
1125 {
1126 fprintf(stderr, "DEBUG: Read %d bytes...\n", (int)bytes);
1127
4220952d 1128 if (cupsWriteRequestData(http, buffer, bytes) != HTTP_CONTINUE)
cc754834
MS
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 }
bd7854cb 1147
1148 ipp_status = cupsLastError();
ef416fc2 1149
1150 if (ipp_status > IPP_OK_CONFLICT)
1151 {
1152 job_id = 0;
1153
cc754834 1154 if (job_canceled)
bd7854cb 1155 break;
1156
ef416fc2 1157 if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1158 ipp_status == IPP_PRINTER_BUSY)
1159 {
0837b7e8
MS
1160 _cupsLangPrintFilter(stderr, "INFO",
1161 _("Printer busy; will retry in 10 seconds."));
ef416fc2 1162 sleep(10);
1163 }
1164 else
68b10830
MS
1165 {
1166 /*
1167 * Update auth-info-required as needed...
1168 */
1169
0837b7e8
MS
1170 _cupsLangPrintFilter(stderr, "ERROR",
1171 _("Print file was not accepted: %s"),
1172 cupsLastErrorString());
68b10830 1173
18ecb428 1174 if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
68b10830
MS
1175 {
1176 fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n",
1177 httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE));
1178
18ecb428
MS
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
68b10830
MS
1186 if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
1187 "Negotiate", 9))
18ecb428 1188 auth_info_required = "negotiate";
68b10830
MS
1189 }
1190 }
ef416fc2 1191 }
1192 else if ((job_id_attr = ippFindAttribute(response, "job-id",
1193 IPP_TAG_INTEGER)) == NULL)
1194 {
0837b7e8
MS
1195 _cupsLangPrintFilter(stderr, "INFO",
1196 _("Print file accepted - job ID unknown."));
ef416fc2 1197 job_id = 0;
1198 }
1199 else
1200 {
7cf5915e 1201 monitor.job_id = job_id = job_id_attr->values[0].integer;
0837b7e8
MS
1202 _cupsLangPrintFilter(stderr, "INFO",
1203 _("Print file accepted - job ID %d."), job_id);
ef416fc2 1204 }
1205
bd7854cb 1206 ippDelete(response);
1207
cc754834 1208 if (job_canceled)
bd7854cb 1209 break;
1210
1211 if (job_id && num_files > 1)
1212 {
1213 for (i = 0; i < num_files; i ++)
1214 {
7a14d768
MS
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
bd7854cb 1225 request = ippNewRequest(IPP_SEND_DOCUMENT);
c168a833
MS
1226 request->request.op.version[0] = version / 10;
1227 request->request.op.version[1] = version % 10;
bd7854cb 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
cc754834
MS
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 {
4220952d 1252 if (cupsWriteRequestData(http, buffer, bytes) != HTTP_CONTINUE)
cc754834
MS
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 }
97c9a8d7 1266
cc754834
MS
1267 ippDelete(cupsGetResponse(http, resource));
1268 ippDelete(request);
bd7854cb 1269
1270 if (cupsLastError() > IPP_OK_CONFLICT)
1271 {
1272 ipp_status = cupsLastError();
1273
0837b7e8
MS
1274 _cupsLangPrintFilter(stderr, "ERROR",
1275 _("Unable to add file to job: %s"),
1276 cupsLastErrorString());
bd7854cb 1277 break;
1278 }
1279 }
1280 }
ef416fc2 1281
1282 if (ipp_status <= IPP_OK_CONFLICT && argc > 6)
1283 {
1284 fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1);
d09495fa 1285 copies_remaining --;
ef416fc2 1286 }
1287 else if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1288 ipp_status == IPP_PRINTER_BUSY)
1f6f3dbc 1289 continue;
ef416fc2 1290 else
d09495fa 1291 copies_remaining --;
ef416fc2 1292
1293 /*
1294 * Wait for the job to complete...
1295 */
1296
1297 if (!job_id || !waitjob)
1298 continue;
1299
0837b7e8 1300 _cupsLangPrintFilter(stderr, "INFO", _("Waiting for job to complete."));
ef416fc2 1301
cc754834 1302 for (delay = 1; !job_canceled;)
ef416fc2 1303 {
7a14d768
MS
1304 /*
1305 * Check for side-channel requests...
1306 */
1307
1308 backendCheckSideChannel(snmp_fd, http->hostaddr);
1309
ef416fc2 1310 /*
1311 * Build an IPP_GET_JOB_ATTRIBUTES request...
1312 */
1313
fa73b229 1314 request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
c168a833
MS
1315 request->request.op.version[0] = version / 10;
1316 request->request.op.version[1] = version % 10;
ef416fc2 1317
1318 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1319 NULL, uri);
1320
1321 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
1322 job_id);
1323
1324 if (argv[2][0])
1325 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1326 "requesting-user-name", NULL, argv[2]);
1327
1328 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1329 "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]),
1330 NULL, jattrs);
1331
1332 /*
1333 * Do the request...
1334 */
1335
bd7854cb 1336 response = cupsDoRequest(http, request, resource);
1337 ipp_status = cupsLastError();
ef416fc2 1338
1339 if (ipp_status == IPP_NOT_FOUND)
1340 {
1341 /*
1342 * Job has gone away and/or the server has no job history...
1343 */
1344
1345 ippDelete(response);
1346
1347 ipp_status = IPP_OK;
1348 break;
1349 }
1350
1351 if (ipp_status > IPP_OK_CONFLICT)
1352 {
1353 if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
1354 ipp_status != IPP_PRINTER_BUSY)
1355 {
bd7854cb 1356 ippDelete(response);
ef416fc2 1357
0837b7e8
MS
1358 _cupsLangPrintFilter(stderr, "ERROR",
1359 _("Unable to get job attributes: %s"),
1360 cupsLastErrorString());
ef416fc2 1361 break;
1362 }
1363 }
1364
bd7854cb 1365 if (response)
ef416fc2 1366 {
1367 if ((job_state = ippFindAttribute(response, "job-state",
1368 IPP_TAG_ENUM)) != NULL)
1369 {
1370 /*
1371 * Stop polling if the job is finished or pending-held...
1372 */
1373
b94498cf 1374 if (job_state->values[0].integer > IPP_JOB_STOPPED)
ef416fc2 1375 {
c8fef167 1376 if ((job_sheets = ippFindAttribute(response,
fa73b229 1377 "job-media-sheets-completed",
1378 IPP_TAG_INTEGER)) != NULL)
bd7854cb 1379 fprintf(stderr, "PAGE: total %d\n",
1380 job_sheets->values[0].integer);
ef416fc2 1381
1382 ippDelete(response);
1383 break;
1384 }
1385 }
7a0cbd5e
MS
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
1394 fputs("DEBUG: No job-state available from printer - stopping queue.\n",
1395 stderr);
1396 ipp_status = IPP_INTERNAL_ERROR;
1397 break;
1398 }
ef416fc2 1399 }
1400
bd7854cb 1401 ippDelete(response);
ef416fc2 1402
7cf5915e 1403#if 0
ef416fc2 1404 /*
1405 * Check the printer state and report it if necessary...
1406 */
1407
db1f069b 1408 check_printer_state(http, uri, resource, argv[2], version, job_id);
7cf5915e 1409#endif /* 0 */
ef416fc2 1410
1411 /*
2e4ff8af 1412 * Wait 1-10 seconds before polling again...
ef416fc2 1413 */
1414
2e4ff8af
MS
1415 sleep(delay);
1416
1417 delay ++;
1418 if (delay > 10)
1419 delay = 1;
ef416fc2 1420 }
1421 }
1422
1423 /*
bd7854cb 1424 * Cancel the job as needed...
ef416fc2 1425 */
1426
cc754834 1427 if (job_canceled && job_id)
bd7854cb 1428 cancel_job(http, uri, job_id, resource, argv[2], version);
1429
1430 /*
1431 * Check the printer state and report it if necessary...
1432 */
ef416fc2 1433
db1f069b 1434 check_printer_state(http, uri, resource, argv[2], version, job_id);
ef416fc2 1435
7a14d768
MS
1436 /*
1437 * Collect the final page count as needed...
1438 */
1439
c8fef167 1440 if (have_supplies &&
7a14d768
MS
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
18ecb428
MS
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
ef416fc2 1454 /*
1455 * Free memory...
1456 */
1457
0268488e
MS
1458 cleanup:
1459
1460 cupsFreeOptions(num_options, options);
1461 _pwgDestroy(pwg);
1462
ef416fc2 1463 httpClose(http);
1464
bd7854cb 1465 ippDelete(supported);
ef416fc2 1466
1467 /*
1468 * Remove the temporary file(s) if necessary...
1469 */
1470
b423cd4c 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
ef416fc2 1479 /*
1480 * Return the queue status...
1481 */
1482
18ecb428
MS
1483 fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
1484
1485 if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
7ff4fea9 1486 return (CUPS_BACKEND_AUTH_REQUIRED);
7a0cbd5e
MS
1487 else if (ipp_status == IPP_INTERNAL_ERROR)
1488 return (CUPS_BACKEND_STOP);
7ff4fea9
MS
1489 else if (ipp_status > IPP_OK_CONFLICT)
1490 return (CUPS_BACKEND_FAILED);
1491 else
41681883 1492 {
0837b7e8 1493 _cupsLangPrintFilter(stderr, "INFO", _("Ready to print."));
7ff4fea9 1494 return (CUPS_BACKEND_OK);
41681883 1495 }
ef416fc2 1496}
1497
1498
bd7854cb 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
0837b7e8 1514 _cupsLangPrintFilter(stderr, "INFO", _("Canceling print job."));
bd7854cb 1515
1516 request = ippNewRequest(IPP_CANCEL_JOB);
c168a833
MS
1517 request->request.op.version[0] = version / 10;
1518 request->request.op.version[1] = version % 10;
bd7854cb 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)
0837b7e8
MS
1535 _cupsLangPrintFilter(stderr, "ERROR", _("Unable to cancel job: %s"),
1536 cupsLastErrorString());
bd7854cb 1537}
1538
1539
ef416fc2 1540/*
7cf5915e 1541 * 'check_printer_state()' - Check the printer state.
ef416fc2 1542 */
1543
7cf5915e 1544static ipp_pstate_t /* O - Current printer-state */
fa73b229 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 */
db1f069b 1550 int version, /* I - IPP version */
7cf5915e 1551 int job_id)
ef416fc2 1552{
7cf5915e
MS
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 */
ef416fc2 1558
1559
1560 /*
7cf5915e 1561 * Send a Get-Printer-Attributes request and log the results...
ef416fc2 1562 */
1563
fa73b229 1564 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
c168a833
MS
1565 request->request.op.version[0] = version / 10;
1566 request->request.op.version[1] = version % 10;
ef416fc2 1567
1568 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
7cf5915e 1569 NULL, uri);
ef416fc2 1570
1571 if (user && user[0])
1572 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
7cf5915e 1573 "requesting-user-name", NULL, user);
ef416fc2 1574
323c5de1 1575 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
7cf5915e
MS
1576 "requested-attributes",
1577 (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
ef416fc2 1578
1579 if ((response = cupsDoRequest(http, request, resource)) != NULL)
1580 {
db1f069b 1581 report_printer_state(response, job_id);
7cf5915e
MS
1582
1583 if ((attr = ippFindAttribute(response, "printer-state",
1584 IPP_TAG_ENUM)) != NULL)
1585 printer_state = (ipp_pstate_t)attr->values[0].integer;
1586
ef416fc2 1587 ippDelete(response);
1588 }
7cf5915e
MS
1589
1590 /*
1591 * Return the printer-state value...
1592 */
1593
1594 return (printer_state);
ef416fc2 1595}
1596
1597
b423cd4c 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 */
a74454a7 1615 buffer[32768]; /* Copy buffer */
b423cd4c 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 {
0837b7e8 1623 _cupsLangPrintError("ERROR", _("Unable to create compressed print file"));
b423cd4c 1624 exit(CUPS_BACKEND_FAILED);
1625 }
1626
1627 if ((out = cupsFileOpenFd(fd, "w9")) == NULL)
1628 {
0837b7e8 1629 _cupsLangPrintError("ERROR", _("Unable to open compressed print file"));
b423cd4c 1630 exit(CUPS_BACKEND_FAILED);
1631 }
1632
1633 if ((in = cupsFileOpen(files[i], "r")) == NULL)
1634 {
0837b7e8 1635 _cupsLangPrintError("ERROR", _("Unable to open print file"));
b423cd4c 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 {
0837b7e8
MS
1644 _cupsLangPrintError("ERROR",
1645 _("Unable to generate compressed print file"));
b423cd4c 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))
1659 fprintf(stderr,
1660 "DEBUG: File %d compressed to %.1f%% of original size, "
1661 CUPS_LLFMT " bytes...\n",
e1d6a774 1662 i + 1, 100.0 * outinfo.st_size / total,
1663 CUPS_LLCAST outinfo.st_size);
b423cd4c 1664 }
1665}
1666#endif /* HAVE_LIBZ */
1667
1668
7cf5915e
MS
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
c8fef167 1690 http = _httpCreate(monitor->hostname, monitor->port, NULL, monitor->encryption,
1106b00e 1691 AF_UNSPEC);
7cf5915e
MS
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
0268488e
MS
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 */
c8fef167 1800 int copies, /* I - copies value or 0 */
0268488e
MS
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
ef416fc2 2010/*
2011 * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
2012 */
2013
bd7854cb 2014static const char * /* O - Password */
fa73b229 2015password_cb(const char *prompt) /* I - Prompt (not used) */
ef416fc2 2016{
2017 (void)prompt;
2018
18ecb428
MS
2019 /*
2020 * Remember that we need to authenticate...
2021 */
2022
2023 auth_info_required = "username,password";
2024
3dfe78b3 2025 if (password && *password && password_tries < 3)
76cd9e37
MS
2026 {
2027 password_tries ++;
2028
ef416fc2 2029 return (password);
76cd9e37 2030 }
ef416fc2 2031 else
2032 {
2033 /*
18ecb428 2034 * Give up after 3 tries or if we don't have a password to begin with...
ef416fc2 2035 */
2036
18ecb428 2037 return (NULL);
ef416fc2 2038 }
2039}
2040
2041
1f0275e3
MS
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
ef416fc2 2110/*
2111 * 'report_printer_state()' - Report the printer state.
2112 */
2113
bd7854cb 2114static int /* O - Number of reasons shown */
db1f069b
MS
2115report_printer_state(ipp_t *ipp, /* I - IPP response */
2116 int job_id) /* I - Current job ID */
ef416fc2 2117{
2118 int i; /* Looping var */
2119 int count; /* Count of reasons shown... */
7cf5915e
MS
2120 ipp_attribute_t *pa, /* printer-alert */
2121 *pam, /* printer-alert-message */
2122 *psm, /* printer-state-message */
1f0275e3
MS
2123 *reasons, /* printer-state-reasons */
2124 *marker; /* marker-* attributes */
ef416fc2 2125 const char *reason; /* Current reason */
ef416fc2 2126 const char *prefix; /* Prefix for STATE: line */
7cf5915e
MS
2127 char value[1024], /* State/message string */
2128 *valptr; /* Pointer into string */
c8fef167
MS
2129 static int ipp_supplies = -1;
2130 /* Report supply levels? */
ef416fc2 2131
2132
7cf5915e
MS
2133 /*
2134 * Report alerts and messages...
2135 */
2136
2137 if ((pa = ippFindAttribute(ipp, "printer-alert", IPP_TAG_TEXT)) != NULL)
2138 report_attr(pa);
2139
2140 if ((pam = ippFindAttribute(ipp, "printer-alert-message",
2141 IPP_TAG_TEXT)) != NULL)
2142 report_attr(pam);
2143
323c5de1 2144 if ((psm = ippFindAttribute(ipp, "printer-state-message",
2145 IPP_TAG_TEXT)) != NULL)
7cf5915e
MS
2146 {
2147 char *ptr; /* Pointer into message */
2148
2149
2150 strlcpy(value, "INFO: ", sizeof(value));
2151 for (ptr = psm->values[0].string.text, valptr = value + 6;
2152 *ptr && valptr < (value + sizeof(value) - 6);
2153 ptr ++)
2154 {
2155 if (*ptr < ' ' && *ptr > 0 && *ptr != '\t')
2156 {
2157 /*
2158 * Substitute "<XX>" for the control character; sprintf is safe because
2159 * we always leave 6 chars free at the end...
2160 */
2161
2162 sprintf(valptr, "<%02X>", *ptr);
2163 valptr += 4;
2164 }
2165 else
2166 *valptr++ = *ptr;
2167 }
2168
2169 *valptr++ = '\n';
e60ec91f 2170 *valptr = '\0';
7cf5915e
MS
2171
2172 fputs(value, stderr);
2173 }
2174
2175 /*
2176 * Now report printer-state-reasons, filtering out some of the reasons we never
2177 * want to set...
2178 */
323c5de1 2179
ef416fc2 2180 if ((reasons = ippFindAttribute(ipp, "printer-state-reasons",
2181 IPP_TAG_KEYWORD)) == NULL)
2182 return (0);
2183
7cf5915e 2184 value[0] = '\0';
4d301e69 2185 prefix = "STATE: ";
ef416fc2 2186
7cf5915e 2187 for (i = 0, count = 0, valptr = value; i < reasons->num_values; i ++)
ef416fc2 2188 {
2189 reason = reasons->values[i].string.text;
2190
4d301e69
MS
2191 if (strcmp(reason, "paused") &&
2192 strcmp(reason, "com.apple.print.recoverable-warning"))
db1f069b 2193 {
7cf5915e
MS
2194 strlcpy(valptr, prefix, sizeof(value) - (valptr - value) - 1);
2195 valptr += strlen(valptr);
2196 strlcpy(valptr, reason, sizeof(value) - (valptr - value) - 1);
2197 valptr += strlen(valptr);
db1f069b
MS
2198
2199 prefix = ",";
2200 }
ef416fc2 2201 }
2202
7cf5915e
MS
2203 if (value[0])
2204 {
2205 *valptr++ = '\n';
e60ec91f 2206 *valptr = '\0';
7cf5915e
MS
2207 fputs(value, stderr);
2208 }
ef416fc2 2209
1f0275e3
MS
2210 /*
2211 * Relay the current marker-* attribute values...
2212 */
2213
c8fef167
MS
2214 if (ipp_supplies < 0)
2215 {
2216 ppd_file_t *ppd; /* PPD file */
2217 ppd_attr_t *ppdattr; /* Attribute in PPD file */
2218
2219 if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL &&
2220 (ppdattr = ppdFindAttr(ppd, "cupsIPPSupplies", NULL)) != NULL &&
2221 ppdattr->value && strcasecmp(ppdattr->value, "true"))
2222 ipp_supplies = 0;
2223 else
2224 ipp_supplies = 1;
2225
2226 ppdClose(ppd);
2227 }
2228
2229 if (ipp_supplies > 0)
2230 {
2231 if ((marker = ippFindAttribute(ipp, "marker-colors", IPP_TAG_NAME)) != NULL)
2232 report_attr(marker);
2233 if ((marker = ippFindAttribute(ipp, "marker-high-levels",
2234 IPP_TAG_INTEGER)) != NULL)
2235 report_attr(marker);
2236 if ((marker = ippFindAttribute(ipp, "marker-levels",
2237 IPP_TAG_INTEGER)) != NULL)
2238 report_attr(marker);
2239 if ((marker = ippFindAttribute(ipp, "marker-low-levels",
2240 IPP_TAG_INTEGER)) != NULL)
2241 report_attr(marker);
2242 if ((marker = ippFindAttribute(ipp, "marker-message",
2243 IPP_TAG_TEXT)) != NULL)
2244 report_attr(marker);
2245 if ((marker = ippFindAttribute(ipp, "marker-names", IPP_TAG_NAME)) != NULL)
2246 report_attr(marker);
2247 if ((marker = ippFindAttribute(ipp, "marker-types",
2248 IPP_TAG_KEYWORD)) != NULL)
2249 report_attr(marker);
2250 }
1f0275e3 2251
ef416fc2 2252 return (count);
2253}
2254
2255
ef416fc2 2256/*
2257 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
2258 */
2259
2260static void
2261sigterm_handler(int sig) /* I - Signal */
2262{
2263 (void)sig; /* remove compiler warnings... */
2264
cc754834 2265 if (!job_canceled)
bd7854cb 2266 {
2267 /*
2268 * Flag that the job should be cancelled...
2269 */
2270
cc754834 2271 job_canceled = 1;
bd7854cb 2272 return;
2273 }
2274
ef416fc2 2275 exit(1);
2276}
2277
2278
2279/*
b19ccc9e 2280 * End of "$Id: ipp.c 7948 2008-09-17 00:04:12Z mike $".
ef416fc2 2281 */