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