]>
Commit | Line | Data |
---|---|---|
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 | ||
50 | int /* O - Exit status */ | |
51 | main(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 | */ |