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