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