]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/ipp.c
Fixed a boneheaded mistake in the IPP backend - was erroring out when
[thirdparty/cups.git] / backend / ipp.c
CommitLineData
c8f9565c 1/*
c882c785 2 * "$Id: ipp.c,v 1.4 1999/06/25 15:04:55 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 *
26 */
27
28/*
29 * Include necessary headers.
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <errno.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <cups/cups.h>
38#include <cups/language.h>
39#include <cups/string.h>
40
41
42/*
43 * 'main()' - Send a file to the printer or server.
44 *
45 * Usage:
46 *
47 * printer-uri job-id user title copies options [file]
48 */
49
50int /* O - Exit status */
51main(int argc, /* I - Number of command-line arguments (6 or 7) */
52 char *argv[]) /* I - Command-line arguments */
53{
54 int i; /* Looping var */
55 int n, n2; /* Attribute values */
56 char *option, /* Name of option */
57 *val, /* Pointer to option value */
58 *s; /* Pointer into option value */
59 int num_options; /* Number of printer options */
60 cups_option_t *options; /* Printer options */
61 char method[255], /* Method in URI */
62 hostname[1024], /* Hostname */
63 username[255], /* Username info */
64 resource[1024], /* Resource info (printer name) */
65 filename[1024]; /* File to print */
66 int port; /* Port number (not used) */
67 char password[255], /* Password info */
68 uri[HTTP_MAX_URI];/* Updated URI without user/pass */
69 http_status_t status; /* Status of HTTP job */
70 FILE *fp; /* File to print */
71 http_t *http; /* HTTP connection */
72 ipp_t *request, /* IPP request */
73 *response; /* IPP response */
74 ipp_attribute_t *job_id; /* job-id attribute */
75 cups_lang_t *language; /* Default language */
76 struct stat fileinfo; /* File statistics */
77 size_t nbytes, /* Number of bytes written */
78 tbytes; /* Total bytes written */
79 char buffer[8192]; /* Output buffer */
80
81
82 if (argc < 6 || argc > 7)
83 {
84 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
85 argv[0]);
86 return (1);
87 }
88
89 /*
90 * If we have 7 arguments, print the file named on the command-line.
91 * Otherwise, print stdin...
92 */
93
94 if (argc == 6)
95 fp = stdin;
96 else if ((fp = fopen(argv[6], "rb")) == NULL)
97 {
98 perror("ERROR: Unable to open print file");
99 return (1);
100 }
101 else
102 stat(argv[6], &fileinfo);
103
104 /*
105 * Extract the hostname and printer name from the URI...
106 */
107
108 httpSeparate(argv[0], method, username, hostname, &port, resource);
109
110 /*
111 * Try connecting to the remote server...
112 */
113
114 fprintf(stderr, "INFO: Connecting to %s...\n", hostname);
115
116 if ((http = httpConnect(hostname, port)) == NULL)
117 {
118 perror("ERROR: Unable to connect to IPP host");
119
120 if (fp != stdin)
121 fclose(fp);
122 return (1);
123 }
124
125 /*
126 * Build a URI for the printer and fill the standard IPP attributes for
127 * an IPP_PRINT_FILE request...
128 */
129
130 request = ippNew();
131 request->request.op.operation_id = IPP_PRINT_JOB;
132 request->request.op.request_id = 1;
133
134 sprintf(uri, "%s://%s:%d/%s", method, hostname, port, resource);
135
136 language = cupsLangDefault();
137
138 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
139 "attributes-charset", NULL, cupsLangEncoding(language));
140
141 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
142 "attributes-natural-language", NULL,
143 language != NULL ? language->language : "C");
144
145 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
146 NULL, uri);
147
148 ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, "requesting-user-name",
149 NULL, argv[2]);
150
151 ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, argv[3]);
152
153 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", atoi(argv[4]));
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))
163 ippAddString(request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
164 NULL, "application/vnd.cups-raw");
165 else
166 ippAddString(request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
167 NULL, "application/octet-stream");
168
169 for (i = 0; i < num_options; i ++)
170 {
171 /*
172 * Skip the "raw" option - handled above...
173 */
174
175 if (strcmp(options[i].name, "raw") == 0)
176 continue;
177
178 /*
179 * See what the option value is; for compatibility with older interface
180 * scripts, we have to support single-argument options as well as
181 * option=value, option=low-high, and option=MxN.
182 */
183
184 option = options[i].name;
185 val = options[i].value;
186
187 if (*val == '\0')
188 val = NULL;
189
190 if (val != NULL)
191 {
192 if (strcasecmp(val, "true") == 0 ||
193 strcasecmp(val, "on") == 0 ||
194 strcasecmp(val, "yes") == 0)
195 {
196 /*
197 * Boolean value - true...
198 */
199
200 n = 1;
201 val = "";
202 }
203 else if (strcasecmp(val, "false") == 0 ||
204 strcasecmp(val, "off") == 0 ||
205 strcasecmp(val, "no") == 0)
206 {
207 /*
208 * Boolean value - false...
209 */
210
211 n = 0;
212 val = "";
213 }
214
215 n = strtol(val, &s, 0);
216 }
217 else
218 {
219 if (strncmp(option, "no", 2) == 0)
220 {
221 option += 2;
222 n = 0;
223 }
224 else
225 n = 1;
226
227 s = "";
228 }
229
230 if (*s != '\0' && *s != '-' && (*s != 'x' || s == val))
231 /*
232 * String value(s)...
233 */
234 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, option, NULL, val);
235 else if (val != NULL)
236 {
237 /*
238 * Numeric value, range, or resolution...
239 */
240
241 if (*s == '-')
242 {
243 n2 = strtol(s + 1, NULL, 0);
244 ippAddRange(request, IPP_TAG_JOB, option, n, n2);
245 }
246 else if (*s == 'x')
247 {
248 n2 = strtol(s + 1, &s, 0);
249
250 if (strcmp(s, "dpc") == 0)
251 ippAddResolution(request, IPP_TAG_JOB, option, IPP_RES_PER_CM, n, n2);
252 else if (strcmp(s, "dpi") == 0)
253 ippAddResolution(request, IPP_TAG_JOB, option, IPP_RES_PER_INCH, n, n2);
254 else
255 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, option, NULL, val);
256 }
257 else
258 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, option, n);
259 }
260 else
261 /*
262 * Boolean value...
263 */
264 ippAddBoolean(request, IPP_TAG_JOB, option, (char)n);
265 }
266
267 /*
268 * Now fill in the HTTP request stuff...
269 */
270
271 httpClearFields(http);
272 httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
273 httpEncode64(password, username);
274 httpSetField(http, HTTP_FIELD_AUTHORIZATION, password);
275
276 if (fp != stdin)
277 {
4ee2f874 278 sprintf(buffer, "%u", ippLength(request) + (size_t)fileinfo.st_size);
c8f9565c 279 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, buffer);
280 }
281
282 /*
283 * Do the request...
284 */
285
286 for (;;)
287 {
288 /*
289 * POST the request, retrying as needed...
290 */
291
292 if (httpPost(http, resource))
293 if (httpPost(http, resource))
294 {
295 fputs("INFO: Unable to POST print request; retrying...\n", stderr);
296 sleep(10);
297 continue;
298 }
299
300 /*
301 * Send the IPP request...
302 */
303
304 request->state = IPP_IDLE;
305
c882c785 306 if (ippWrite(http, request) == IPP_ERROR)
c8f9565c 307 {
c882c785 308 fputs("ERROR: Unable to send IPP request!\n", stderr);
c8f9565c 309 status = HTTP_ERROR;
310 break;
311 }
312
313 /*
314 * Then send the file...
315 */
316
317 tbytes = 0;
318 while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
319 {
320 tbytes += nbytes;
321 fprintf(stderr, "INFO: Sending print file, %uk...\n", tbytes / 1024);
322
323 if (httpWrite(http, buffer, nbytes) < nbytes)
324 {
325 perror("ERROR: Unable to send print file to printer");
326 status = HTTP_ERROR;
327 break;
328 }
329 }
330
331 httpWrite(http, buffer, 0);
332
333 /*
334 * Finally, check the status from the HTTP server...
335 */
336
337 while ((status = httpUpdate(http)) == HTTP_CONTINUE);
338
339 if (status == HTTP_OK)
340 {
341 response = ippNew();
342 ippRead(http, response);
343
344 if (response->request.status.status_code > IPP_OK_CONFLICT)
345 fprintf(stderr, "ERROR: Print file was not accepted (%04x)!\n",
346 response->request.status.status_code);
347 else if ((job_id = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL)
348 fputs("INFO: Print file accepted - job ID unknown.\n", stderr);
349 else
350 fprintf(stderr, "INFO: Print file accepted - job ID %d.\n",
351 job_id->values[0].integer);
352 }
353 else
354 {
355 response = NULL;
356 httpFlush(http);
357
358 fprintf(stderr, "ERROR: Print request was not accepted (%d)!\n", status);
359 }
360
361 break;
362 }
363
364 /*
365 * Free memory...
366 */
367
368 httpClose(http);
369 if (request != NULL)
370 ippDelete(request);
371 if (response != NULL)
372 ippDelete(response);
373
374 /*
375 * Close the print file as needed...
376 */
377
378 if (fp != stdin)
379 fclose(fp);
380
381 /*
382 * Return the queue status...
383 */
384
385 return (status != HTTP_OK);
386}
387
388
389/*
c882c785 390 * End of "$Id: ipp.c,v 1.4 1999/06/25 15:04:55 mike Exp $".
c8f9565c 391 */