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