]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/ipp.c
Fixed minor bug in attribute reading code - didn't handle "unsupported"
[thirdparty/cups.git] / backend / ipp.c
CommitLineData
c8f9565c 1/*
970017a4 2 * "$Id: ipp.c,v 1.11 1999/10/10 15:40:07 mike Exp $"
c8f9565c 3 *
4 * IPP backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-1999 by Easy Software Products, all rights reserved.
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 */
71 FILE *fp; /* File to print */
72 http_t *http; /* HTTP connection */
73 ipp_t *request, /* IPP request */
74 *response; /* IPP response */
75 ipp_attribute_t *job_id; /* job-id attribute */
76 cups_lang_t *language; /* Default language */
77 struct stat fileinfo; /* File statistics */
78 size_t nbytes, /* Number of bytes written */
79 tbytes; /* Total bytes written */
80 char buffer[8192]; /* Output buffer */
81
82
83 if (argc < 6 || argc > 7)
84 {
85 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
86 argv[0]);
87 return (1);
88 }
89
90 /*
91 * If we have 7 arguments, print the file named on the command-line.
92 * Otherwise, print stdin...
93 */
94
95 if (argc == 6)
96 fp = stdin;
97 else if ((fp = fopen(argv[6], "rb")) == NULL)
98 {
99 perror("ERROR: Unable to open print file");
100 return (1);
101 }
102 else
103 stat(argv[6], &fileinfo);
104
105 /*
106 * Extract the hostname and printer name from the URI...
107 */
108
109 httpSeparate(argv[0], method, username, hostname, &port, resource);
110
111 /*
112 * Try connecting to the remote server...
113 */
114
115 fprintf(stderr, "INFO: Connecting to %s...\n", hostname);
116
117 if ((http = httpConnect(hostname, port)) == NULL)
118 {
119 perror("ERROR: Unable to connect to IPP host");
120
121 if (fp != stdin)
122 fclose(fp);
123 return (1);
124 }
125
126 /*
127 * Build a URI for the printer and fill the standard IPP attributes for
8ce7c000 128 * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it
129 * might contain username:password information...
c8f9565c 130 */
131
132 request = ippNew();
133 request->request.op.operation_id = IPP_PRINT_JOB;
134 request->request.op.request_id = 1;
135
970017a4 136 snprintf(uri, sizeof(uri), "%s://%s:%d%s", method, hostname, port, resource);
c8f9565c 137
138 language = cupsLangDefault();
139
140 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
141 "attributes-charset", NULL, cupsLangEncoding(language));
142
143 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
144 "attributes-natural-language", NULL,
145 language != NULL ? language->language : "C");
146
147 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
148 NULL, uri);
149
6d0582d2 150 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
c8f9565c 151 NULL, argv[2]);
152
6d0582d2 153 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, argv[3]);
c8f9565c 154
155 /*
156 * Handle options on the command-line...
157 */
158
159 options = NULL;
160 num_options = cupsParseOptions(argv[5], 0, &options);
161
162 if (cupsGetOption("raw", num_options, options))
6d0582d2 163 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
c8f9565c 164 NULL, "application/vnd.cups-raw");
165 else
6d0582d2 166 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
c8f9565c 167 NULL, "application/octet-stream");
168
6d0582d2 169 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", atoi(argv[4]));
170
c8f9565c 171 for (i = 0; i < num_options; i ++)
172 {
173 /*
174 * Skip the "raw" option - handled above...
175 */
176
177 if (strcmp(options[i].name, "raw") == 0)
178 continue;
179
180 /*
181 * See what the option value is; for compatibility with older interface
182 * scripts, we have to support single-argument options as well as
183 * option=value, option=low-high, and option=MxN.
184 */
185
186 option = options[i].name;
187 val = options[i].value;
188
189 if (*val == '\0')
190 val = NULL;
191
192 if (val != NULL)
193 {
194 if (strcasecmp(val, "true") == 0 ||
195 strcasecmp(val, "on") == 0 ||
196 strcasecmp(val, "yes") == 0)
197 {
198 /*
199 * Boolean value - true...
200 */
201
202 n = 1;
203 val = "";
204 }
205 else if (strcasecmp(val, "false") == 0 ||
206 strcasecmp(val, "off") == 0 ||
207 strcasecmp(val, "no") == 0)
208 {
209 /*
210 * Boolean value - false...
211 */
212
213 n = 0;
214 val = "";
215 }
216
217 n = strtol(val, &s, 0);
218 }
219 else
220 {
221 if (strncmp(option, "no", 2) == 0)
222 {
223 option += 2;
224 n = 0;
225 }
226 else
227 n = 1;
228
229 s = "";
230 }
231
232 if (*s != '\0' && *s != '-' && (*s != 'x' || s == val))
233 /*
234 * String value(s)...
235 */
236 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, option, NULL, val);
237 else if (val != NULL)
238 {
239 /*
240 * Numeric value, range, or resolution...
241 */
242
243 if (*s == '-')
244 {
245 n2 = strtol(s + 1, NULL, 0);
246 ippAddRange(request, IPP_TAG_JOB, option, n, n2);
247 }
248 else if (*s == 'x')
249 {
250 n2 = strtol(s + 1, &s, 0);
251
252 if (strcmp(s, "dpc") == 0)
253 ippAddResolution(request, IPP_TAG_JOB, option, IPP_RES_PER_CM, n, n2);
254 else if (strcmp(s, "dpi") == 0)
255 ippAddResolution(request, IPP_TAG_JOB, option, IPP_RES_PER_INCH, n, n2);
256 else
257 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, option, NULL, val);
258 }
259 else
260 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, option, n);
261 }
262 else
263 /*
264 * Boolean value...
265 */
266 ippAddBoolean(request, IPP_TAG_JOB, option, (char)n);
267 }
268
269 /*
270 * Now fill in the HTTP request stuff...
271 */
272
273 httpClearFields(http);
274 httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
275 httpEncode64(password, username);
276 httpSetField(http, HTTP_FIELD_AUTHORIZATION, password);
277
278 if (fp != stdin)
279 {
4ee2f874 280 sprintf(buffer, "%u", ippLength(request) + (size_t)fileinfo.st_size);
c8f9565c 281 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, buffer);
282 }
0c5b0932 283 else
284 httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
285
c8f9565c 286 /*
287 * Do the request...
288 */
289
290 for (;;)
291 {
292 /*
293 * POST the request, retrying as needed...
294 */
295
296 if (httpPost(http, resource))
2cd0cbe5 297 {
298 fputs("INFO: Unable to POST print request; retrying...\n", stderr);
299 sleep(10);
300 httpReconnect(http);
301 continue;
302 }
c8f9565c 303
8ce7c000 304 fputs("INFO: POST successful, sending IPP request...\n", stderr);
305
c8f9565c 306 /*
307 * Send the IPP request...
308 */
309
310 request->state = IPP_IDLE;
311
c882c785 312 if (ippWrite(http, request) == IPP_ERROR)
c8f9565c 313 {
c882c785 314 fputs("ERROR: Unable to send IPP request!\n", stderr);
c8f9565c 315 status = HTTP_ERROR;
316 break;
317 }
318
e7502c46 319 fputs("INFO: IPP request sent, sending print file...\n", stderr);
8ce7c000 320
c8f9565c 321 /*
322 * Then send the file...
323 */
324
325 tbytes = 0;
326 while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
327 {
328 tbytes += nbytes;
329 fprintf(stderr, "INFO: Sending print file, %uk...\n", tbytes / 1024);
330
331 if (httpWrite(http, buffer, nbytes) < nbytes)
332 {
333 perror("ERROR: Unable to send print file to printer");
334 status = HTTP_ERROR;
335 break;
336 }
337 }
338
cb555bcf 339 /*
340 * If we are chunking the output from stdin, make sure we end up with
341 * a 0-length chunk at the end...
342 */
343
344 if (fp == stdin)
345 httpWrite(http, buffer, 0);
346
8ce7c000 347 fputs("INFO: Print file sent; checking status...\n", stderr);
348
c8f9565c 349 /*
350 * Finally, check the status from the HTTP server...
351 */
352
353 while ((status = httpUpdate(http)) == HTTP_CONTINUE);
354
355 if (status == HTTP_OK)
356 {
357 response = ippNew();
358 ippRead(http, response);
359
360 if (response->request.status.status_code > IPP_OK_CONFLICT)
361 fprintf(stderr, "ERROR: Print file was not accepted (%04x)!\n",
362 response->request.status.status_code);
363 else if ((job_id = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL)
364 fputs("INFO: Print file accepted - job ID unknown.\n", stderr);
365 else
366 fprintf(stderr, "INFO: Print file accepted - job ID %d.\n",
367 job_id->values[0].integer);
368 }
369 else
370 {
371 response = NULL;
372 httpFlush(http);
373
374 fprintf(stderr, "ERROR: Print request was not accepted (%d)!\n", status);
375 }
376
377 break;
378 }
379
380 /*
381 * Free memory...
382 */
383
384 httpClose(http);
385 if (request != NULL)
386 ippDelete(request);
387 if (response != NULL)
388 ippDelete(response);
389
390 /*
391 * Close the print file as needed...
392 */
393
394 if (fp != stdin)
395 fclose(fp);
396
397 /*
398 * Return the queue status...
399 */
400
401 return (status != HTTP_OK);
402}
403
404
405/*
970017a4 406 * End of "$Id: ipp.c,v 1.11 1999/10/10 15:40:07 mike Exp $".
c8f9565c 407 */