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