]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/ipp.c
Add -E support to GUI commands.
[thirdparty/cups.git] / backend / ipp.c
CommitLineData
c8f9565c 1/*
d2935a0f 2 * "$Id: ipp.c,v 1.34 2001/01/22 15:03:19 mike Exp $"
c8f9565c 3 *
4 * IPP backend for the Common UNIX Printing System (CUPS).
5 *
d2935a0f 6 * Copyright 1997-2001 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 *
24 * Contents:
25 *
6d0582d2 26 * main() - Send a file to the printer or server.
c8f9565c 27 */
28
29/*
30 * Include necessary headers.
31 */
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <errno.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <cups/cups.h>
39#include <cups/language.h>
40#include <cups/string.h>
4ff40357 41#include <signal.h>
c8f9565c 42
43
44/*
45 * 'main()' - Send a file to the printer or server.
46 *
47 * Usage:
48 *
49 * printer-uri job-id user title copies options [file]
50 */
51
52int /* O - Exit status */
53main(int argc, /* I - Number of command-line arguments (6 or 7) */
54 char *argv[]) /* I - Command-line arguments */
55{
25512894 56 int i; /* Looping var */
c8f9565c 57 int num_options; /* Number of printer options */
3079988e 58 cups_option_t *options; /* Printer options */
c8f9565c 59 char method[255], /* Method in URI */
60 hostname[1024], /* Hostname */
61 username[255], /* Username info */
62 resource[1024], /* Resource info (printer name) */
63 filename[1024]; /* File to print */
64 int port; /* Port number (not used) */
65 char password[255], /* Password info */
66 uri[HTTP_MAX_URI];/* Updated URI without user/pass */
67 http_status_t status; /* Status of HTTP job */
97fcaf92 68 ipp_status_t ipp_status; /* Status of IPP request */
c8f9565c 69 FILE *fp; /* File to print */
70 http_t *http; /* HTTP connection */
71 ipp_t *request, /* IPP request */
72 *response; /* IPP response */
73 ipp_attribute_t *job_id; /* job-id attribute */
97fcaf92 74 ipp_attribute_t *copies_sup; /* copies-supported attribute */
25512894 75 ipp_attribute_t *charset_sup; /* charset-supported attribute */
36aa99bb 76 ipp_attribute_t *format_sup; /* document-format-supported attribute */
25512894 77 const char *charset; /* Character set to use */
c8f9565c 78 cups_lang_t *language; /* Default language */
79 struct stat fileinfo; /* File statistics */
80 size_t nbytes, /* Number of bytes written */
81 tbytes; /* Total bytes written */
82 char buffer[8192]; /* Output buffer */
97fcaf92 83 int copies; /* Number of copies remaining */
0a3944d6 84 const char *content_type; /* CONTENT_TYPE environment variable */
4ff40357 85#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
86 struct sigaction action; /* Actions for POSIX signals */
87#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
5a2c7855 88 int version; /* IPP version */
c8f9565c 89
90
68edc300 91 if (argc == 1)
92 {
183914a3 93 char *s;
94
d4c438d4 95 if ((s = strrchr(argv[0], '/')) != NULL)
96 s ++;
97 else
98 s = argv[0];
99
100 printf("network %s \"Unknown\" \"Internet Printing Protocol\"\n", s);
68edc300 101 return (0);
102 }
103 else if (argc < 6 || argc > 7)
c8f9565c 104 {
105 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
106 argv[0]);
107 return (1);
108 }
109
110 /*
111 * If we have 7 arguments, print the file named on the command-line.
97fcaf92 112 * Otherwise, copy stdin to a temporary file and print the temporary
113 * file.
c8f9565c 114 */
115
116 if (argc == 6)
97fcaf92 117 {
118 /*
119 * Copy stdin to a temporary file...
120 */
121
122 FILE *fp; /* Temporary file */
123 char buffer[8192]; /* Buffer for copying */
124 int bytes; /* Number of bytes read */
125
126
127 if ((fp = fopen(cupsTempFile(filename, sizeof(filename)), "w")) == NULL)
128 {
129 perror("ERROR: unable to create temporary file");
130 return (1);
131 }
132
133 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
134 if (fwrite(buffer, 1, bytes, fp) < bytes)
135 {
136 perror("ERROR: unable to write to temporary file");
137 fclose(fp);
138 unlink(filename);
139 return (1);
140 }
141
142 fclose(fp);
143 }
144 else
145 {
146 strncpy(filename, argv[6], sizeof(filename) - 1);
147 filename[sizeof(filename) - 1] = '\0';
148 }
149
150 /*
151 * Open the print file...
152 */
153
154 if ((fp = fopen(filename, "rb")) == NULL)
c8f9565c 155 {
156 perror("ERROR: Unable to open print file");
157 return (1);
158 }
159 else
97fcaf92 160 stat(filename, &fileinfo);
c8f9565c 161
162 /*
163 * Extract the hostname and printer name from the URI...
164 */
165
166 httpSeparate(argv[0], method, username, hostname, &port, resource);
167
168 /*
169 * Try connecting to the remote server...
170 */
171
97fcaf92 172 do
c8f9565c 173 {
97fcaf92 174 fprintf(stderr, "INFO: Connecting to %s...\n", hostname);
c8f9565c 175
97fcaf92 176 if ((http = httpConnect(hostname, port)) == NULL)
d21a7597 177 {
97fcaf92 178 if (errno == ECONNREFUSED)
179 {
180 fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...",
181 hostname);
182 sleep(30);
183 }
184 else
185 {
186 perror("ERROR: Unable to connect to IPP host");
2cc18dd2 187 sleep(30);
97fcaf92 188 }
d21a7597 189 }
c8f9565c 190 }
97fcaf92 191 while (http == NULL);
c8f9565c 192
193 /*
194 * Build a URI for the printer and fill the standard IPP attributes for
8ce7c000 195 * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it
196 * might contain username:password information...
c8f9565c 197 */
198
3f9cb6c6 199 snprintf(uri, sizeof(uri), "%s://%s:%d%s", method, hostname, port, resource);
c8f9565c 200
201 /*
97fcaf92 202 * First validate the destination and see if the device supports multiple
203 * copies. We have to do this because some IPP servers (e.g. HP JetDirect)
204 * don't support the copies attribute...
c8f9565c 205 */
206
25512894 207 language = cupsLangDefault();
208 charset_sup = NULL;
209 copies_sup = NULL;
210 version = 1;
c8f9565c 211
97fcaf92 212 do
c8f9565c 213 {
214 /*
97fcaf92 215 * Build the IPP request...
c8f9565c 216 */
217
97fcaf92 218 request = ippNew();
5a2c7855 219 request->request.op.version[1] = version;
97fcaf92 220 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
221 request->request.op.request_id = 1;
c8f9565c 222
97fcaf92 223 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
67436e05 224 "attributes-charset", NULL, "utf-8");
97fcaf92 225
226 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
227 "attributes-natural-language", NULL,
67436e05 228 language != NULL ? language->language : "en");
c8f9565c 229
97fcaf92 230 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
231 NULL, uri);
c8f9565c 232
97fcaf92 233 /*
234 * Now fill in the HTTP request stuff...
235 */
c8f9565c 236
97fcaf92 237 httpClearFields(http);
238 httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
239 if (username[0])
c8f9565c 240 {
97fcaf92 241 httpEncode64(password, username);
242 httpSetField(http, HTTP_FIELD_AUTHORIZATION, password);
243 }
c8f9565c 244
97fcaf92 245 sprintf(buffer, "%u", ippLength(request));
246 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, buffer);
c8f9565c 247
97fcaf92 248 /*
249 * Do the request...
250 */
c8f9565c 251
36aa99bb 252 for (response = NULL, ipp_status = IPP_BAD_REQUEST;;)
c8f9565c 253 {
97fcaf92 254 /*
255 * POST the request, retrying as needed...
256 */
257
258 if (httpPost(http, resource))
c8f9565c 259 {
97fcaf92 260 fputs("INFO: Unable to POST get-printer-attributes request; retrying...\n", stderr);
261 sleep(10);
262 httpReconnect(http);
263 continue;
c8f9565c 264 }
c8f9565c 265
97fcaf92 266 fputs("INFO: POST successful, sending IPP request...\n", stderr);
c8f9565c 267
c8f9565c 268 /*
97fcaf92 269 * Send the IPP request...
c8f9565c 270 */
97fcaf92 271
272 request->state = IPP_IDLE;
273
274 if (ippWrite(http, request) == IPP_ERROR)
275 {
276 fputs("ERROR: Unable to send IPP request!\n", stderr);
277 status = HTTP_ERROR;
278 break;
279 }
280
281 fputs("INFO: IPP request sent, getting status...\n", stderr);
282
c8f9565c 283 /*
97fcaf92 284 * Finally, check the status from the HTTP server...
c8f9565c 285 */
286
97fcaf92 287 while ((status = httpUpdate(http)) == HTTP_CONTINUE);
288
289 if (status == HTTP_OK)
c8f9565c 290 {
97fcaf92 291 response = ippNew();
292 ippRead(http, response);
293
294 ipp_status = response->request.status.status_code;
d21a7597 295
97fcaf92 296 if (ipp_status > IPP_OK_CONFLICT)
297 {
298 if (ipp_status == IPP_PRINTER_BUSY ||
299 ipp_status == IPP_SERVICE_UNAVAILABLE)
300 {
301 fputs("INFO: Printer busy; will retry in 10 seconds...\n", stderr);
302 sleep(10);
303 }
5a2c7855 304 else if (ipp_status == IPP_BAD_REQUEST && version == 1)
305 {
306 /*
307 * Switch to IPP/1.0...
308 */
309
310 fputs("INFO: Printer does not support IPP/1.1, trying IPP/1.0...\n", stderr);
311 version = 0;
312 }
97fcaf92 313 else
314 {
315 fprintf(stderr, "ERROR: Printer will not accept print file (%x)!\n",
316 ipp_status);
5a2c7855 317 fprintf(stderr, "ERROR: %s\n", ippErrorString(ipp_status));
97fcaf92 318 status = HTTP_ERROR;
319 }
320 }
321 else if ((copies_sup = ippFindAttribute(response, "copies-supported",
322 IPP_TAG_RANGE)) != NULL)
323 {
324 /*
325 * Has the "copies-supported" attribute - does it have an upper
326 * bound > 1?
327 */
328
329 if (copies_sup->values[0].range.upper <= 1)
330 copies_sup = NULL; /* No */
331 }
332
25512894 333 charset_sup = ippFindAttribute(response, "charset-supported",
334 IPP_TAG_CHARSET);
36aa99bb 335 format_sup = ippFindAttribute(response, "document-format-supported",
336 IPP_TAG_MIMETYPE);
c8f9565c 337 }
97fcaf92 338 else
c8f9565c 339 {
d21a7597 340 response = NULL;
341
97fcaf92 342 if (status == HTTP_ERROR)
343 {
344 fprintf(stderr, "WARNING: Did not receive the IPP response (%d)\n",
345 errno);
346 status = HTTP_OK;
347 ipp_status = IPP_PRINTER_BUSY;
348 }
349 else
d21a7597 350 {
5a2c7855 351 fprintf(stderr, "ERROR: Validate request was not accepted (%d)!\n",
352 status);
d21a7597 353 ipp_status = IPP_FORBIDDEN;
354 }
c8f9565c 355 }
97fcaf92 356
357 httpFlush(http);
358
359 break;
360 }
361
362 if (status != HTTP_OK)
363 {
364 if (fp != stdin)
365 fclose(fp);
366
367 httpClose(http);
368
369 return (1);
c8f9565c 370 }
5a2c7855 371 else if (ipp_status > IPP_OK_CONFLICT)
372 httpReconnect(http);
c8f9565c 373 }
97fcaf92 374 while (ipp_status > IPP_OK_CONFLICT);
c8f9565c 375
4ff40357 376 /*
377 * Now that we are "connected" to the port, ignore SIGTERM so that we
378 * can finish out any page data the driver sends (e.g. to eject the
379 * current page...
380 */
381
382#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
383 sigset(SIGTERM, SIG_IGN);
384#elif defined(HAVE_SIGACTION)
385 memset(&action, 0, sizeof(action));
386
387 sigemptyset(&action.sa_mask);
388 action.sa_handler = SIG_IGN;
389 sigaction(SIGTERM, &action, NULL);
390#else
391 signal(SIGTERM, SIG_IGN);
392#endif /* HAVE_SIGSET */
393
c8f9565c 394 /*
97fcaf92 395 * See if the printer supports multiple copies...
c8f9565c 396 */
397
97fcaf92 398 if (copies_sup)
399 copies = 1;
0c5b0932 400 else
97fcaf92 401 copies = atoi(argv[4]);
0c5b0932 402
25512894 403 /*
404 * Figure out the character set to use...
405 */
406
407 charset = language ? cupsLangEncoding(language) : "us-ascii";
408
409 if (charset_sup)
410 {
411 /*
412 * See if IPP server supports the requested character set...
413 */
414
415 for (i = 0; i < charset_sup->num_values; i ++)
416 if (strcasecmp(charset, charset_sup->values[i].string.text) == 0)
417 break;
418
419 /*
420 * If not, choose us-ascii or utf-8...
421 */
422
423 if (i >= charset_sup->num_values)
424 {
425 /*
426 * See if us-ascii is supported...
427 */
428
429 for (i = 0; i < charset_sup->num_values; i ++)
430 if (strcasecmp("us-ascii", charset_sup->values[i].string.text) == 0)
431 break;
432
433 if (i < charset_sup->num_values)
434 charset = "us-ascii";
435 else
436 charset = "utf-8";
437 }
438 }
439
440 if (response)
441 ippDelete(response);
442
c8f9565c 443 /*
97fcaf92 444 * Then issue the print-job request...
c8f9565c 445 */
446
97fcaf92 447 while (copies > 0)
c8f9565c 448 {
449 /*
97fcaf92 450 * Build the IPP request...
c8f9565c 451 */
452
97fcaf92 453 request = ippNew();
5a2c7855 454 request->request.op.version[1] = version;
97fcaf92 455 request->request.op.operation_id = IPP_PRINT_JOB;
456 request->request.op.request_id = 1;
c8f9565c 457
97fcaf92 458 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
25512894 459 "attributes-charset", NULL, charset);
8ce7c000 460
97fcaf92 461 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
462 "attributes-natural-language", NULL,
67436e05 463 language != NULL ? language->language : "en");
c8f9565c 464
97fcaf92 465 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
466 NULL, uri);
c8f9565c 467
97fcaf92 468 fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri);
469
470 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
471 NULL, argv[2]);
472
473 fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]);
474
475 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
476 argv[3]);
c8f9565c 477
97fcaf92 478 fprintf(stderr, "DEBUG: job-name = \"%s\"\n", argv[3]);
8ce7c000 479
c8f9565c 480 /*
97fcaf92 481 * Handle options on the command-line...
c8f9565c 482 */
483
97fcaf92 484 options = NULL;
485 num_options = cupsParseOptions(argv[5], 0, &options);
486
36aa99bb 487 if ((content_type = getenv("CONTENT_TYPE")) != NULL && format_sup != NULL)
488 {
489 for (i = 0; i < format_sup->num_values; i ++)
490 if (strcasecmp(content_type, format_sup->values[i].string.text) == 0)
491 break;
492
493 if (i < format_sup->num_values)
494 num_options = cupsAddOption("document-format", content_type,
495 num_options, &options);
496 }
97fcaf92 497
183914a3 498 cupsEncodeOptions(request, num_options, options);
499 cupsFreeOptions(num_options, options);
c8f9565c 500
168c50b6 501 if (copies_sup)
502 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", atoi(argv[4]));
503
cb555bcf 504 /*
97fcaf92 505 * Now fill in the HTTP request stuff...
cb555bcf 506 */
507
97fcaf92 508 httpClearFields(http);
509 httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
510 if (username[0])
511 {
512 httpEncode64(password, username);
513 httpSetField(http, HTTP_FIELD_AUTHORIZATION, password);
514 }
cb555bcf 515
97fcaf92 516 sprintf(buffer, "%u", ippLength(request) + (size_t)fileinfo.st_size);
517 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, buffer);
8ce7c000 518
c8f9565c 519 /*
97fcaf92 520 * Do the request...
c8f9565c 521 */
522
97fcaf92 523 for (;;)
c8f9565c 524 {
97fcaf92 525 /*
526 * POST the request, retrying as needed...
527 */
528
529 httpReconnect(http);
c8f9565c 530
97fcaf92 531 if (httpPost(http, resource))
3f9cb6c6 532 {
97fcaf92 533 fputs("INFO: Unable to POST print request; retrying...\n", stderr);
534 sleep(10);
535 continue;
536 }
537
538 fputs("INFO: POST successful, sending IPP request...\n", stderr);
3f9cb6c6 539
97fcaf92 540 /*
541 * Send the IPP request...
542 */
543
544 request->state = IPP_IDLE;
3f9cb6c6 545
97fcaf92 546 if (ippWrite(http, request) == IPP_ERROR)
547 {
548 fputs("ERROR: Unable to send IPP request!\n", stderr);
549 status = HTTP_ERROR;
550 break;
3f9cb6c6 551 }
c8f9565c 552
97fcaf92 553 fputs("INFO: IPP request sent, sending print file...\n", stderr);
554
555 /*
556 * Then send the file...
557 */
558
559 rewind(fp);
560
561 tbytes = 0;
562 while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
563 {
564 tbytes += nbytes;
565 fprintf(stderr, "INFO: Sending print file, %uk...\n", tbytes / 1024);
566
567 if (httpWrite(http, buffer, nbytes) < nbytes)
568 {
569 perror("ERROR: Unable to send print file to printer");
570 status = HTTP_ERROR;
571 break;
572 }
573 }
574
575 fputs("INFO: Print file sent; checking status...\n", stderr);
576
577 /*
578 * Finally, check the status from the HTTP server...
579 */
580
581 while ((status = httpUpdate(http)) == HTTP_CONTINUE);
582
583 if (status == HTTP_OK)
6a536282 584 {
97fcaf92 585 response = ippNew();
586 ippRead(http, response);
587
588 if ((ipp_status = response->request.status.status_code) > IPP_OK_CONFLICT)
589 {
590 if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
591 ipp_status == IPP_PRINTER_BUSY)
592 {
593 fputs("INFO: Printer is busy; retrying print job...\n", stderr);
594 sleep(10);
595 }
596 else
5a2c7855 597 {
97fcaf92 598 fprintf(stderr, "ERROR: Print file was not accepted (%04x)!\n",
599 response->request.status.status_code);
5a2c7855 600 fprintf(stderr, "ERROR: %s\n", ippErrorString(ipp_status));
601 }
97fcaf92 602 }
603 else if ((job_id = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL)
604 fputs("INFO: Print file accepted - job ID unknown.\n", stderr);
605 else
606 fprintf(stderr, "INFO: Print file accepted - job ID %d.\n",
607 job_id->values[0].integer);
6a536282 608 }
609 else
97fcaf92 610 {
611 response = NULL;
612 ipp_status = IPP_PRINTER_BUSY;
613
614 if (status == HTTP_ERROR)
615 {
616 fprintf(stderr, "WARNING: Did not receive the IPP response (%d)\n",
617 errno);
618 status = HTTP_OK;
619 }
620 else
621 fprintf(stderr, "ERROR: Print request was not accepted (%d)!\n", status);
622 }
623
624 httpFlush(http);
625
626 break;
c8f9565c 627 }
628
97fcaf92 629 if (request != NULL)
630 ippDelete(request);
631 if (response != NULL)
632 ippDelete(response);
633
634 if (ipp_status <= IPP_OK_CONFLICT)
635 {
636 fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1);
637 copies --;
638 }
48419d23 639 else if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
640 ipp_status != IPP_PRINTER_BUSY)
641 break;
c8f9565c 642 }
643
644 /*
645 * Free memory...
646 */
647
648 httpClose(http);
c8f9565c 649
650 /*
97fcaf92 651 * Close and remove the temporary file if necessary...
c8f9565c 652 */
653
97fcaf92 654 fclose(fp);
3f9cb6c6 655
97fcaf92 656 if (argc < 7)
657 unlink(filename);
c8f9565c 658
659 /*
660 * Return the queue status...
661 */
662
663 return (status != HTTP_OK);
664}
665
666
667/*
d2935a0f 668 * End of "$Id: ipp.c,v 1.34 2001/01/22 15:03:19 mike Exp $".
c8f9565c 669 */