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