]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/ipp.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / backend / ipp.c
CommitLineData
c8f9565c 1/*
997cf8b0 2 * "$Id: ipp.c,v 1.38.2.14 2002/07/23 21:20:25 mike Exp $"
c8f9565c 3 *
4 * IPP backend for the Common UNIX Printing System (CUPS).
5 *
839c43aa 6 * Copyright 1997-2002 by Easy Software Products, all rights reserved.
c8f9565c 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
8784b6a6 17 * 44141 Airport View Drive, Suite 204
c8f9565c 18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
dab1a4d8 24 * This file is subject to the Apple OS-Developed Software exception.
25 *
c8f9565c 26 * Contents:
27 *
d1c2727f 28 * main() - Send a file to the printer or server.
29 * password_cb() - Disable the password prompt for
30 * cupsDoFileRequest().
31 * report_printer_state() - Report the printer state.
c8f9565c 32 */
33
34/*
35 * Include necessary headers.
36 */
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <errno.h>
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <cups/cups.h>
44#include <cups/language.h>
45#include <cups/string.h>
4ff40357 46#include <signal.h>
c8f9565c 47
48
b5cb0608 49/*
50 * Local functions...
51 */
52
53const char *password_cb(const char *);
d1c2727f 54int report_printer_state(ipp_t *ipp);
b5cb0608 55
56
57/*
58 * Local globals...
59 */
60
61char *password = NULL;
62
63
c8f9565c 64/*
65 * 'main()' - Send a file to the printer or server.
66 *
67 * Usage:
68 *
69 * printer-uri job-id user title copies options [file]
70 */
71
72int /* O - Exit status */
73main(int argc, /* I - Number of command-line arguments (6 or 7) */
74 char *argv[]) /* I - Command-line arguments */
75{
25512894 76 int i; /* Looping var */
c8f9565c 77 int num_options; /* Number of printer options */
3079988e 78 cups_option_t *options; /* Printer options */
c8f9565c 79 char method[255], /* Method in URI */
80 hostname[1024], /* Hostname */
81 username[255], /* Username info */
82 resource[1024], /* Resource info (printer name) */
83 filename[1024]; /* File to print */
84 int port; /* Port number (not used) */
b5cb0608 85 char uri[HTTP_MAX_URI];/* Updated URI without user/pass */
97fcaf92 86 ipp_status_t ipp_status; /* Status of IPP request */
c8f9565c 87 http_t *http; /* HTTP connection */
88 ipp_t *request, /* IPP request */
2922de55 89 *response, /* IPP response */
90 *supported; /* get-printer-attributes response */
b5cb0608 91 ipp_attribute_t *job_id_attr; /* job-id attribute */
92 int job_id; /* job-id value */
93 ipp_attribute_t *job_state; /* job-state attribute */
97fcaf92 94 ipp_attribute_t *copies_sup; /* copies-supported attribute */
25512894 95 ipp_attribute_t *charset_sup; /* charset-supported attribute */
36aa99bb 96 ipp_attribute_t *format_sup; /* document-format-supported attribute */
997cf8b0 97 ipp_attribute_t *printer_state;
98 /* printer-state attribute */
99 ipp_attribute_t *printer_accepting;
100 /* printer-is-accepting-jobs attribute */
25512894 101 const char *charset; /* Character set to use */
c8f9565c 102 cups_lang_t *language; /* Default language */
97fcaf92 103 int copies; /* Number of copies remaining */
0a3944d6 104 const char *content_type; /* CONTENT_TYPE environment variable */
4ff40357 105#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
106 struct sigaction action; /* Actions for POSIX signals */
107#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
5a2c7855 108 int version; /* IPP version */
d1c2727f 109 int reasons; /* Number of printer-state-reasons shown */
c8f9565c 110
4b23f3b3 111
112 /*
113 * Make sure status messages are not buffered...
114 */
115
2922de55 116 setbuf(stderr, NULL);
c8f9565c 117
4b23f3b3 118 /*
119 * Check command-line...
120 */
121
68edc300 122 if (argc == 1)
123 {
183914a3 124 char *s;
125
d4c438d4 126 if ((s = strrchr(argv[0], '/')) != NULL)
127 s ++;
128 else
129 s = argv[0];
130
7c587866 131 printf("network %s \"Unknown\" \"Internet Printing Protocol (%s)\"\n", s, s);
68edc300 132 return (0);
133 }
134 else if (argc < 6 || argc > 7)
c8f9565c 135 {
136 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
137 argv[0]);
138 return (1);
139 }
140
141 /*
142 * If we have 7 arguments, print the file named on the command-line.
97fcaf92 143 * Otherwise, copy stdin to a temporary file and print the temporary
144 * file.
c8f9565c 145 */
146
147 if (argc == 6)
97fcaf92 148 {
149 /*
150 * Copy stdin to a temporary file...
151 */
152
1b5bf964 153 int fd; /* Temporary file */
97fcaf92 154 char buffer[8192]; /* Buffer for copying */
155 int bytes; /* Number of bytes read */
156
157
1b5bf964 158 if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
97fcaf92 159 {
160 perror("ERROR: unable to create temporary file");
161 return (1);
162 }
163
164 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
1b5bf964 165 if (write(fd, buffer, bytes) < bytes)
97fcaf92 166 {
167 perror("ERROR: unable to write to temporary file");
1b5bf964 168 close(fd);
97fcaf92 169 unlink(filename);
170 return (1);
171 }
172
1b5bf964 173 close(fd);
97fcaf92 174 }
175 else
def978d5 176 strlcpy(filename, argv[6], sizeof(filename));
97fcaf92 177
178 /*
b5cb0608 179 * Extract the hostname and printer name from the URI...
97fcaf92 180 */
181
b5cb0608 182 httpSeparate(argv[0], method, username, hostname, &port, resource);
c8f9565c 183
184 /*
b5cb0608 185 * Set the authentication info, if any...
c8f9565c 186 */
187
b5cb0608 188 cupsSetPasswordCB(password_cb);
189
190 if (username[0])
191 {
192 if ((password = strchr(username, ':')) != NULL)
193 *password++ = '\0';
194
195 cupsSetUser(username);
196 }
c8f9565c 197
198 /*
199 * Try connecting to the remote server...
200 */
201
97fcaf92 202 do
c8f9565c 203 {
a4e23897 204 fprintf(stderr, "INFO: Connecting to %s on port %d...\n", hostname, port);
c8f9565c 205
97fcaf92 206 if ((http = httpConnect(hostname, port)) == NULL)
d21a7597 207 {
997cf8b0 208 if (getenv("CLASS") != NULL)
209 {
210 /*
211 * If the CLASS environment variable is set, the job was submitted
212 * to a class and not to a specific queue. In this case, we want
213 * to abort immediately so that the job can be requeued on the next
214 * available printer in the class.
215 */
216
217 fprintf(stderr, "INFO: Unable to queue job on %s, queuing on next printer in class...\n",
218 hostname);
219
220 if (argc == 6)
221 unlink(filename);
222
223 /*
224 * Sleep 5 seconds to keep the job from requeuing too rapidly...
225 */
226
227 sleep(5);
228
229 return (1);
230 }
231
4c2096b8 232 if (errno == ECONNREFUSED || errno == EHOSTDOWN ||
233 errno == EHOSTUNREACH)
97fcaf92 234 {
235 fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...",
236 hostname);
237 sleep(30);
238 }
239 else
240 {
241 perror("ERROR: Unable to connect to IPP host");
2cc18dd2 242 sleep(30);
97fcaf92 243 }
d21a7597 244 }
c8f9565c 245 }
97fcaf92 246 while (http == NULL);
c8f9565c 247
a4e23897 248 fprintf(stderr, "INFO: Connected to %s...\n", hostname);
249
c8f9565c 250 /*
251 * Build a URI for the printer and fill the standard IPP attributes for
8ce7c000 252 * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it
253 * might contain username:password information...
c8f9565c 254 */
255
3f9cb6c6 256 snprintf(uri, sizeof(uri), "%s://%s:%d%s", method, hostname, port, resource);
c8f9565c 257
258 /*
97fcaf92 259 * First validate the destination and see if the device supports multiple
260 * copies. We have to do this because some IPP servers (e.g. HP JetDirect)
261 * don't support the copies attribute...
c8f9565c 262 */
263
25512894 264 language = cupsLangDefault();
265 charset_sup = NULL;
266 copies_sup = NULL;
2922de55 267 format_sup = NULL;
25512894 268 version = 1;
2922de55 269 supported = NULL;
c8f9565c 270
97fcaf92 271 do
c8f9565c 272 {
273 /*
97fcaf92 274 * Build the IPP request...
c8f9565c 275 */
276
97fcaf92 277 request = ippNew();
0a3ac972 278 request->request.op.version[1] = version;
279 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
280 request->request.op.request_id = 1;
c8f9565c 281
97fcaf92 282 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
67436e05 283 "attributes-charset", NULL, "utf-8");
97fcaf92 284
285 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
286 "attributes-natural-language", NULL,
67436e05 287 language != NULL ? language->language : "en");
c8f9565c 288
97fcaf92 289 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
290 NULL, uri);
c8f9565c 291
97fcaf92 292 /*
293 * Do the request...
294 */
c8f9565c 295
a4e23897 296 fputs("DEBUG: Getting supported attributes...\n", stderr);
297
b5cb0608 298 if ((supported = cupsDoRequest(http, request, resource)) == NULL)
299 ipp_status = cupsLastError();
300 else
0a3ac972 301 ipp_status = supported->request.status.status_code;
b5cb0608 302
303 if (ipp_status > IPP_OK_CONFLICT)
c8f9565c 304 {
b5cb0608 305 if (ipp_status == IPP_PRINTER_BUSY ||
306 ipp_status == IPP_SERVICE_UNAVAILABLE)
c8f9565c 307 {
b5cb0608 308 fputs("INFO: Printer busy; will retry in 10 seconds...\n", stderr);
d1c2727f 309 report_printer_state(supported);
97fcaf92 310 sleep(10);
97fcaf92 311 }
b5cb0608 312 else if ((ipp_status == IPP_BAD_REQUEST ||
313 ipp_status == IPP_VERSION_NOT_SUPPORTED) && version == 1)
c8f9565c 314 {
b5cb0608 315 /*
316 * Switch to IPP/1.0...
317 */
97fcaf92 318
b5cb0608 319 fputs("INFO: Printer does not support IPP/1.1, trying IPP/1.0...\n", stderr);
320 version = 0;
a4e23897 321 httpReconnect(http);
c8f9565c 322 }
97fcaf92 323 else
d1c2727f 324 fprintf(stderr, "ERROR: Unable to get printer status (%s)!\n",
b5cb0608 325 ippErrorString(ipp_status));
d1c2727f 326
327 if (supported)
328 ippDelete(supported);
329
330 continue;
97fcaf92 331 }
b5cb0608 332 else if ((copies_sup = ippFindAttribute(supported, "copies-supported",
333 IPP_TAG_RANGE)) != NULL)
97fcaf92 334 {
b5cb0608 335 /*
336 * Has the "copies-supported" attribute - does it have an upper
337 * bound > 1?
338 */
97fcaf92 339
b5cb0608 340 if (copies_sup->values[0].range.upper <= 1)
341 copies_sup = NULL; /* No */
342 }
97fcaf92 343
b5cb0608 344 charset_sup = ippFindAttribute(supported, "charset-supported",
345 IPP_TAG_CHARSET);
346 format_sup = ippFindAttribute(supported, "document-format-supported",
347 IPP_TAG_MIMETYPE);
348
349 if (format_sup)
350 {
351 fprintf(stderr, "DEBUG: document-format-supported (%d values)\n",
352 format_sup->num_values);
353 for (i = 0; i < format_sup->num_values; i ++)
354 fprintf(stderr, "DEBUG: [%d] = \"%s\"\n", i,
355 format_sup->values[i].string.text);
c8f9565c 356 }
d1c2727f 357
358 report_printer_state(supported);
c8f9565c 359 }
97fcaf92 360 while (ipp_status > IPP_OK_CONFLICT);
c8f9565c 361
997cf8b0 362 /*
363 * See if the printer is accepting jobs and is not stopped; if either
364 * condition is true and we are printing to a class, requeue the job...
365 */
366
367 if (getenv("CLASS") != NULL)
368 {
369 printer_state = ippFindAttribute(supported, "printer-state",
370 IPP_TAG_ENUM);
371 printer_accepting = ippFindAttribute(supported, "printer-is-accepting-jobs",
372 IPP_TAG_BOOLEAN);
373
374 if (printer_state == NULL ||
375 printer_state->values[0].integer > IPP_PRINTER_PROCESSING ||
376 printer_accepting == NULL ||
377 !printer_accepting->values[0].boolean)
378 {
379 /*
380 * If the CLASS environment variable is set, the job was submitted
381 * to a class and not to a specific queue. In this case, we want
382 * to abort immediately so that the job can be requeued on the next
383 * available printer in the class.
384 */
385
386 fprintf(stderr, "INFO: Unable to queue job on %s, queuing on next printer in class...\n",
387 hostname);
388
389 ippDelete(supported);
390 httpClose(http);
391
392 if (argc == 6)
393 unlink(filename);
394
395 /*
396 * Sleep 5 seconds to keep the job from requeuing too rapidly...
397 */
398
399 sleep(5);
400
401 return (1);
402 }
403 }
404
4ff40357 405 /*
406 * Now that we are "connected" to the port, ignore SIGTERM so that we
407 * can finish out any page data the driver sends (e.g. to eject the
d1c2727f 408 * current page... Only ignore SIGTERM if we are printing data from
409 * stdin (otherwise you can't cancel raw jobs...)
4ff40357 410 */
411
d1c2727f 412 if (argc < 7)
413 {
4ff40357 414#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
d1c2727f 415 sigset(SIGTERM, SIG_IGN);
4ff40357 416#elif defined(HAVE_SIGACTION)
d1c2727f 417 memset(&action, 0, sizeof(action));
4ff40357 418
d1c2727f 419 sigemptyset(&action.sa_mask);
420 action.sa_handler = SIG_IGN;
421 sigaction(SIGTERM, &action, NULL);
4ff40357 422#else
d1c2727f 423 signal(SIGTERM, SIG_IGN);
4ff40357 424#endif /* HAVE_SIGSET */
d1c2727f 425 }
4ff40357 426
c8f9565c 427 /*
97fcaf92 428 * See if the printer supports multiple copies...
c8f9565c 429 */
430
d1c2727f 431 if (copies_sup || argc < 7)
97fcaf92 432 copies = 1;
0c5b0932 433 else
97fcaf92 434 copies = atoi(argv[4]);
0c5b0932 435
25512894 436 /*
437 * Figure out the character set to use...
438 */
439
440 charset = language ? cupsLangEncoding(language) : "us-ascii";
441
442 if (charset_sup)
443 {
444 /*
445 * See if IPP server supports the requested character set...
446 */
447
448 for (i = 0; i < charset_sup->num_values; i ++)
449 if (strcasecmp(charset, charset_sup->values[i].string.text) == 0)
450 break;
451
452 /*
453 * If not, choose us-ascii or utf-8...
454 */
455
456 if (i >= charset_sup->num_values)
457 {
458 /*
459 * See if us-ascii is supported...
460 */
461
462 for (i = 0; i < charset_sup->num_values; i ++)
463 if (strcasecmp("us-ascii", charset_sup->values[i].string.text) == 0)
464 break;
465
466 if (i < charset_sup->num_values)
467 charset = "us-ascii";
468 else
469 charset = "utf-8";
470 }
471 }
472
c8f9565c 473 /*
97fcaf92 474 * Then issue the print-job request...
c8f9565c 475 */
476
d1c2727f 477 reasons = 0;
478
97fcaf92 479 while (copies > 0)
c8f9565c 480 {
481 /*
97fcaf92 482 * Build the IPP request...
c8f9565c 483 */
484
97fcaf92 485 request = ippNew();
0a3ac972 486 request->request.op.version[1] = version;
487 request->request.op.operation_id = IPP_PRINT_JOB;
488 request->request.op.request_id = 1;
c8f9565c 489
97fcaf92 490 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
25512894 491 "attributes-charset", NULL, charset);
8ce7c000 492
97fcaf92 493 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
494 "attributes-natural-language", NULL,
67436e05 495 language != NULL ? language->language : "en");
c8f9565c 496
97fcaf92 497 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
498 NULL, uri);
c8f9565c 499
97fcaf92 500 fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri);
501
753453e4 502 if (argv[2][0])
503 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
504 NULL, argv[2]);
97fcaf92 505
506 fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]);
507
753453e4 508 if (argv[3][0])
509 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
510 argv[3]);
c8f9565c 511
97fcaf92 512 fprintf(stderr, "DEBUG: job-name = \"%s\"\n", argv[3]);
8ce7c000 513
c8f9565c 514 /*
97fcaf92 515 * Handle options on the command-line...
c8f9565c 516 */
517
97fcaf92 518 options = NULL;
519 num_options = cupsParseOptions(argv[5], 0, &options);
520
753453e4 521 if (argc > 6)
522 content_type = getenv("CONTENT_TYPE");
523 else
524 content_type = "application/vnd.cups-raw";
525
526 if (content_type != NULL && format_sup != NULL)
36aa99bb 527 {
528 for (i = 0; i < format_sup->num_values; i ++)
529 if (strcasecmp(content_type, format_sup->values[i].string.text) == 0)
530 break;
531
532 if (i < format_sup->num_values)
533 num_options = cupsAddOption("document-format", content_type,
534 num_options, &options);
535 }
97fcaf92 536
753453e4 537 if (copies_sup)
538 {
539 /*
540 * Only send options if the destination printer supports the copies
541 * attribute. This is a hack for the HP JetDirect implementation of
542 * IPP, which does not accept extension attributes and incorrectly
543 * reports a client-error-bad-request error instead of the
544 * successful-ok-unsupported-attributes status. In short, at least
545 * some HP implementations of IPP are non-compliant.
546 */
547
548 cupsEncodeOptions(request, num_options, options);
549 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies",
550 atoi(argv[4]));
551 }
552
183914a3 553 cupsFreeOptions(num_options, options);
c8f9565c 554
a4e23897 555 /*
556 * If copies aren't supported, then we are likely dealing with an HP
557 * JetDirect. The HP IPP implementation seems to close the connection
558 * after every request (that is, it does *not* implement HTTP Keep-
559 * Alive, which is REQUIRED by HTTP/1.1...
560 */
561
562 if (!copies_sup)
563 httpReconnect(http);
564
cb555bcf 565 /*
b5cb0608 566 * Do the request...
cb555bcf 567 */
568
b5cb0608 569 if ((response = cupsDoFileRequest(http, request, resource, filename)) == NULL)
570 ipp_status = cupsLastError();
571 else
0a3ac972 572 ipp_status = response->request.status.status_code;
b5cb0608 573
574 if (ipp_status > IPP_OK_CONFLICT)
575 {
753453e4 576 job_id = 0;
577
b5cb0608 578 if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
579 ipp_status == IPP_PRINTER_BUSY)
580 {
581 fputs("INFO: Printer is busy; retrying print job...\n", stderr);
582 sleep(10);
583 }
584 else
585 fprintf(stderr, "ERROR: Print file was not accepted (%s)!\n",
586 ippErrorString(ipp_status));
587 }
588 else if ((job_id_attr = ippFindAttribute(response, "job-id",
589 IPP_TAG_INTEGER)) == NULL)
97fcaf92 590 {
b5cb0608 591 fputs("INFO: Print file accepted - job ID unknown.\n", stderr);
592 job_id = 0;
593 }
594 else
595 {
596 job_id = job_id_attr->values[0].integer;
597 fprintf(stderr, "INFO: Print file accepted - job ID %d.\n", job_id);
97fcaf92 598 }
cb555bcf 599
b5cb0608 600 if (response)
601 ippDelete(response);
602
753453e4 603 if (ipp_status <= IPP_OK_CONFLICT && argc > 6)
b5cb0608 604 {
605 fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1);
606 copies --;
607 }
608 else if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
609 ipp_status != IPP_PRINTER_BUSY)
610 break;
8ce7c000 611
c8f9565c 612 /*
b5cb0608 613 * Wait for the job to complete...
c8f9565c 614 */
615
b5cb0608 616 if (!job_id)
617 continue;
618
619 fputs("INFO: Waiting for job to complete...\n", stderr);
620
97fcaf92 621 for (;;)
c8f9565c 622 {
97fcaf92 623 /*
b5cb0608 624 * Build an IPP_GET_JOB_ATTRIBUTES request...
97fcaf92 625 */
626
b5cb0608 627 request = ippNew();
0a3ac972 628 request->request.op.version[1] = version;
629 request->request.op.operation_id = IPP_GET_JOB_ATTRIBUTES;
630 request->request.op.request_id = 1;
97fcaf92 631
b5cb0608 632 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
633 "attributes-charset", NULL, charset);
3f9cb6c6 634
b5cb0608 635 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
636 "attributes-natural-language", NULL,
637 language != NULL ? language->language : "en");
97fcaf92 638
b5cb0608 639 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
640 NULL, uri);
3f9cb6c6 641
b5cb0608 642 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
643 job_id);
c8f9565c 644
ee8b7dd3 645 if (argv[2][0])
646 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
647 NULL, argv[2]);
648
b5cb0608 649 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
650 "requested-attributes", NULL, "job-state");
97fcaf92 651
652 /*
b5cb0608 653 * Do the request...
97fcaf92 654 */
655
a4e23897 656 if (!copies_sup)
657 httpReconnect(http);
658
b5cb0608 659 if ((response = cupsDoRequest(http, request, resource)) == NULL)
660 ipp_status = cupsLastError();
661 else
0a3ac972 662 ipp_status = response->request.status.status_code;
97fcaf92 663
b5cb0608 664 if (ipp_status == IPP_NOT_FOUND)
97fcaf92 665 {
b5cb0608 666 /*
d1c2727f 667 * Job has gone away and/or the server has no job history...
b5cb0608 668 */
97fcaf92 669
b5cb0608 670 ippDelete(response);
d1c2727f 671
672 ipp_status = IPP_OK;
b5cb0608 673 break;
97fcaf92 674 }
675
b5cb0608 676 if (ipp_status > IPP_OK_CONFLICT)
6a536282 677 {
b5cb0608 678 if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
679 ipp_status != IPP_PRINTER_BUSY)
97fcaf92 680 {
b5cb0608 681 if (response)
682 ippDelete(response);
683
684 fprintf(stderr, "ERROR: Unable to get job %d attributes (%s)!\n",
685 job_id, ippErrorString(ipp_status));
686 break;
97fcaf92 687 }
6a536282 688 }
b5cb0608 689 else if ((job_state = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL)
97fcaf92 690 {
b5cb0608 691 /*
753453e4 692 * Stop polling if the job is finished or pending-held...
b5cb0608 693 */
97fcaf92 694
753453e4 695 if (job_state->values[0].integer > IPP_JOB_PROCESSING ||
696 job_state->values[0].integer == IPP_JOB_HELD)
97fcaf92 697 {
b5cb0608 698 ippDelete(response);
699 break;
97fcaf92 700 }
97fcaf92 701 }
702
d1c2727f 703 if (response)
704 ippDelete(response);
705
b5cb0608 706 /*
d1c2727f 707 * Now check on the printer state...
b5cb0608 708 */
c8f9565c 709
d1c2727f 710 request = ippNew();
0a3ac972 711 request->request.op.version[1] = version;
712 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
713 request->request.op.request_id = 1;
d1c2727f 714
715 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
716 "attributes-charset", NULL, charset);
717
718 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
719 "attributes-natural-language", NULL,
720 language != NULL ? language->language : "en");
721
722 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
723 NULL, uri);
724
ee8b7dd3 725 if (argv[2][0])
726 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
727 NULL, argv[2]);
728
d1c2727f 729 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
ee8b7dd3 730 "requested-attributes", NULL, "printer-state-reasons");
d1c2727f 731
732 /*
733 * Do the request...
734 */
735
a4e23897 736 if (!copies_sup)
737 httpReconnect(http);
738
d1c2727f 739 if ((response = cupsDoRequest(http, request, resource)) != NULL)
740 {
741 reasons = report_printer_state(response);
b5cb0608 742 ippDelete(response);
d1c2727f 743 }
744
745 /*
746 * Wait 10 seconds before polling again...
747 */
97fcaf92 748
b5cb0608 749 sleep(10);
97fcaf92 750 }
c8f9565c 751 }
752
753 /*
754 * Free memory...
755 */
756
757 httpClose(http);
c8f9565c 758
2922de55 759 if (supported)
760 ippDelete(supported);
761
c8f9565c 762 /*
97fcaf92 763 * Close and remove the temporary file if necessary...
c8f9565c 764 */
765
97fcaf92 766 if (argc < 7)
767 unlink(filename);
c8f9565c 768
769 /*
770 * Return the queue status...
771 */
772
d1c2727f 773 if (ipp_status <= IPP_OK_CONFLICT && reasons == 0)
753453e4 774 fputs("INFO: Ready to print.\n", stderr);
b5cb0608 775
776 return (ipp_status > IPP_OK_CONFLICT);
777}
778
779
780/*
781 * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
782 */
783
784const char * /* O - Password */
785password_cb(const char *prompt) /* I - Prompt (not used) */
786{
787 (void)prompt;
788
789 return (password);
c8f9565c 790}
791
792
793/*
d1c2727f 794 * 'report_printer_state()' - Report the printer state.
795 */
796
d8076497 797int /* O - Number of reasons shown */
d1c2727f 798report_printer_state(ipp_t *ipp) /* I - IPP response */
799{
800 int i; /* Looping var */
d8076497 801 int count; /* Count of reasons shown... */
d1c2727f 802 ipp_attribute_t *reasons; /* printer-state-reasons */
803 const char *message; /* Message to show */
d8076497 804 char unknown[1024]; /* Unknown message string */
d1c2727f 805
806
807 if ((reasons = ippFindAttribute(ipp, "printer-state-reasons",
808 IPP_TAG_KEYWORD)) == NULL)
809 return (0);
810
d8076497 811 for (i = 0, count = 0; i < reasons->num_values; i ++)
d1c2727f 812 {
813 message = NULL;
814
815 if (strncmp(reasons->values[i].string.text, "media-needed", 12) == 0)
816 message = "Media tray needs to be filled.";
817 else if (strncmp(reasons->values[i].string.text, "media-jam", 9) == 0)
818 message = "Media jam!";
819 else if (strncmp(reasons->values[i].string.text, "moving-to-paused", 16) == 0 ||
820 strncmp(reasons->values[i].string.text, "paused", 6) == 0 ||
821 strncmp(reasons->values[i].string.text, "shutdown", 8) == 0)
822 message = "Printer off-line.";
823 else if (strncmp(reasons->values[i].string.text, "toner-low", 9) == 0)
824 message = "Toner low.";
825 else if (strncmp(reasons->values[i].string.text, "toner-empty", 11) == 0)
826 message = "Out of toner!";
827 else if (strncmp(reasons->values[i].string.text, "cover-open", 10) == 0)
828 message = "Cover open.";
829 else if (strncmp(reasons->values[i].string.text, "interlock-open", 14) == 0)
830 message = "Interlock open.";
831 else if (strncmp(reasons->values[i].string.text, "door-open", 9) == 0)
832 message = "Door open.";
833 else if (strncmp(reasons->values[i].string.text, "input-tray-missing", 18) == 0)
834 message = "Media tray missing!";
835 else if (strncmp(reasons->values[i].string.text, "media-low", 9) == 0)
836 message = "Media tray almost empty.";
837 else if (strncmp(reasons->values[i].string.text, "media-empty", 11) == 0)
838 message = "Media tray empty!";
839 else if (strncmp(reasons->values[i].string.text, "output-tray-missing", 19) == 0)
840 message = "Output tray missing!";
841 else if (strncmp(reasons->values[i].string.text, "output-area-almost-full", 23) == 0)
842 message = "Output bin almost full.";
843 else if (strncmp(reasons->values[i].string.text, "output-area-full", 16) == 0)
844 message = "Output bin full!";
845 else if (strncmp(reasons->values[i].string.text, "marker-supply-low", 17) == 0)
846 message = "Ink/toner almost empty.";
847 else if (strncmp(reasons->values[i].string.text, "marker-supply-empty", 19) == 0)
848 message = "Ink/toner empty!";
849 else if (strncmp(reasons->values[i].string.text, "marker-waste-almost-full", 24) == 0)
850 message = "Ink/toner waste bin almost full.";
851 else if (strncmp(reasons->values[i].string.text, "marker-waste-full", 17) == 0)
852 message = "Ink/toner waste bin full!";
853 else if (strncmp(reasons->values[i].string.text, "fuser-over-temp", 15) == 0)
854 message = "Fuser temperature high!";
855 else if (strncmp(reasons->values[i].string.text, "fuser-under-temp", 16) == 0)
856 message = "Fuser temperature low!";
857 else if (strncmp(reasons->values[i].string.text, "opc-near-eol", 12) == 0)
858 message = "OPC almost at end-of-life.";
859 else if (strncmp(reasons->values[i].string.text, "opc-life-over", 13) == 0)
860 message = "OPC at end-of-life!";
861 else if (strncmp(reasons->values[i].string.text, "developer-low", 13) == 0)
862 message = "Developer almost empty.";
863 else if (strncmp(reasons->values[i].string.text, "developer-empty", 15) == 0)
864 message = "Developer empty!";
d8076497 865 else if (strstr(reasons->values[i].string.text, "error") != NULL)
866 {
867 message = unknown;
868
869 snprintf(unknown, sizeof(unknown), "Unknown printer error (%s)!",
870 reasons->values[i].string.text);
871 }
d1c2727f 872
873 if (message)
874 {
d8076497 875 count ++;
d1c2727f 876 if (strstr(reasons->values[i].string.text, "error"))
877 fprintf(stderr, "ERROR: %s\n", message);
878 else if (strstr(reasons->values[i].string.text, "warning"))
879 fprintf(stderr, "WARNING: %s\n", message);
880 else
881 fprintf(stderr, "INFO: %s\n", message);
882 }
883 }
884
d8076497 885 return (count);
d1c2727f 886}
887
888
889
890/*
997cf8b0 891 * End of "$Id: ipp.c,v 1.38.2.14 2002/07/23 21:20:25 mike Exp $".
c8f9565c 892 */