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