]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/request.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / request.c
1 /*
2 * "$Id: request.c 5362 2006-03-31 15:26:12Z mike $"
3 *
4 * IPP utilities for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
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.txt" 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
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * cupsDoFileRequest() - Do an IPP request with a file.
29 * cupsDoRequest() - Do an IPP request.
30 * _cupsSetError() - Set the last IPP status code and status-message.
31 */
32
33 /*
34 * Include necessary headers...
35 */
36
37 #include "globals.h"
38 #include "debug.h"
39 #include <stdlib.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <sys/stat.h>
43 #if defined(WIN32) || defined(__EMX__)
44 # include <io.h>
45 #else
46 # include <unistd.h>
47 #endif /* WIN32 || __EMX__ */
48
49
50 /*
51 * 'cupsDoFileRequest()' - Do an IPP request with a file.
52 *
53 * This function sends the IPP request to the specified server, retrying
54 * and authenticating as necessary. The request is freed with ippDelete()
55 * after receiving a valid IPP response.
56 */
57
58 ipp_t * /* O - Response data */
59 cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */
60 ipp_t *request, /* I - IPP request */
61 const char *resource, /* I - HTTP resource for POST */
62 const char *filename) /* I - File to send or NULL for none */
63 {
64 ipp_t *response; /* IPP response data */
65 size_t length; /* Content-Length value */
66 http_status_t status; /* Status of HTTP request */
67 int got_status; /* Did we get the status? */
68 ipp_state_t state; /* State of IPP processing */
69 FILE *file; /* File to send */
70 struct stat fileinfo; /* File information */
71 int bytes; /* Number of bytes read/written */
72 char buffer[65536]; /* Output buffer */
73
74
75 DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n",
76 http, request, resource ? resource : "(null)",
77 filename ? filename : "(null)"));
78
79 if (http == NULL || request == NULL || resource == NULL)
80 {
81 if (request != NULL)
82 ippDelete(request);
83
84 _cupsSetError(IPP_INTERNAL_ERROR, NULL);
85
86 return (NULL);
87 }
88
89 /*
90 * See if we have a file to send...
91 */
92
93 if (filename != NULL)
94 {
95 if (stat(filename, &fileinfo))
96 {
97 /*
98 * Can't get file information!
99 */
100
101 _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
102 strerror(errno));
103
104 ippDelete(request);
105
106 return (NULL);
107 }
108
109 #ifdef WIN32
110 if (fileinfo.st_mode & _S_IFDIR)
111 #else
112 if (S_ISDIR(fileinfo.st_mode))
113 #endif /* WIN32 */
114 {
115 /*
116 * Can't send a directory...
117 */
118
119 ippDelete(request);
120
121 _cupsSetError(IPP_NOT_POSSIBLE, NULL);
122
123 return (NULL);
124 }
125
126 if ((file = fopen(filename, "rb")) == NULL)
127 {
128 /*
129 * Can't open file!
130 */
131
132 _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
133 strerror(errno));
134
135 ippDelete(request);
136
137 return (NULL);
138 }
139 }
140 else
141 file = NULL;
142
143 /*
144 * Loop until we can send the request without authorization problems.
145 */
146
147 response = NULL;
148 status = HTTP_ERROR;
149
150 while (response == NULL)
151 {
152 DEBUG_puts("cupsDoFileRequest: setup...");
153
154 /*
155 * Setup the HTTP variables needed...
156 */
157
158 length = ippLength(request);
159 if (filename)
160 length += fileinfo.st_size;
161
162 httpClearFields(http);
163 httpSetLength(http, length);
164 httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
165 httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
166 httpSetExpect(http, HTTP_CONTINUE);
167
168 DEBUG_printf(("cupsDoFileRequest: authstring=\"%s\"\n", http->authstring));
169
170 /*
171 * Try the request...
172 */
173
174 DEBUG_puts("cupsDoFileRequest: post...");
175
176 if (httpPost(http, resource))
177 {
178 if (httpReconnect(http))
179 {
180 status = HTTP_ERROR;
181 break;
182 }
183 else
184 continue;
185 }
186
187 /*
188 * Send the IPP data...
189 */
190
191 DEBUG_puts("cupsDoFileRequest: ipp write...");
192
193 request->state = IPP_IDLE;
194 status = HTTP_CONTINUE;
195 got_status = 0;
196
197 while ((state = ippWrite(http, request)) != IPP_DATA)
198 if (state == IPP_ERROR)
199 break;
200 else if (httpCheck(http))
201 {
202 got_status = 1;
203
204 if ((status = httpUpdate(http)) != HTTP_CONTINUE)
205 break;
206 }
207
208 if (!got_status)
209 {
210 /*
211 * Wait up to 1 second to get the 100-continue response...
212 */
213
214 if (httpWait(http, 1000))
215 status = httpUpdate(http);
216 }
217 else if (httpCheck(http))
218 status = httpUpdate(http);
219
220 if (status == HTTP_CONTINUE && state == IPP_DATA && filename)
221 {
222 DEBUG_puts("cupsDoFileRequest: file write...");
223
224 /*
225 * Send the file...
226 */
227
228 rewind(file);
229
230 while ((bytes = (int)fread(buffer, 1, sizeof(buffer), file)) > 0)
231 {
232 if (httpCheck(http))
233 {
234 if ((status = httpUpdate(http)) != HTTP_CONTINUE)
235 break;
236 }
237
238 if (httpWrite2(http, buffer, bytes) < bytes)
239 break;
240 }
241 }
242
243 /*
244 * Get the server's return status...
245 */
246
247 DEBUG_puts("cupsDoFileRequest: update...");
248
249 while (status == HTTP_CONTINUE)
250 status = httpUpdate(http);
251
252 DEBUG_printf(("cupsDoFileRequest: status = %d\n", status));
253
254 if (status == HTTP_UNAUTHORIZED)
255 {
256 DEBUG_puts("cupsDoFileRequest: unauthorized...");
257
258 /*
259 * Flush any error message...
260 */
261
262 httpFlush(http);
263
264 /*
265 * See if we can do authentication...
266 */
267
268 if (cupsDoAuthentication(http, "POST", resource))
269 break;
270
271 if (httpReconnect(http))
272 {
273 status = HTTP_ERROR;
274 break;
275 }
276
277 continue;
278 }
279 else if (status == HTTP_ERROR)
280 {
281 #ifdef WIN32
282 if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH)
283 #else
284 if (http->error != ENETDOWN && http->error != ENETUNREACH)
285 #endif /* WIN32 */
286 continue;
287 else
288 break;
289 }
290 #ifdef HAVE_SSL
291 else if (status == HTTP_UPGRADE_REQUIRED)
292 {
293 /* Flush any error message... */
294 httpFlush(http);
295
296 /* Reconnect... */
297 if (httpReconnect(http))
298 {
299 status = HTTP_ERROR;
300 break;
301 }
302
303 /* Upgrade with encryption... */
304 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
305
306 /* Try again, this time with encryption enabled... */
307 continue;
308 }
309 #endif /* HAVE_SSL */
310 else if (status != HTTP_OK)
311 {
312 DEBUG_printf(("cupsDoFileRequest: error %d...\n", status));
313
314 /*
315 * Flush any error message...
316 */
317
318 httpFlush(http);
319 break;
320 }
321 else
322 {
323 /*
324 * Read the response...
325 */
326
327 DEBUG_puts("cupsDoFileRequest: response...");
328
329 response = ippNew();
330
331 if (ippRead(http, response) == IPP_ERROR)
332 {
333 /*
334 * Delete the response...
335 */
336
337 DEBUG_puts("IPP read error!");
338 ippDelete(response);
339 response = NULL;
340
341 _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno));
342
343 break;
344 }
345 }
346 }
347
348 /*
349 * Close the file if needed...
350 */
351
352 if (filename != NULL)
353 fclose(file);
354
355 /*
356 * Flush any remaining data...
357 */
358
359 httpFlush(http);
360
361 /*
362 * Delete the original request and return the response...
363 */
364
365 ippDelete(request);
366
367 if (response)
368 {
369 ipp_attribute_t *attr; /* status-message attribute */
370
371
372 attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
373
374 _cupsSetError(response->request.status.status_code,
375 attr ? attr->values[0].string.text :
376 ippErrorString(response->request.status.status_code));
377 }
378 else if (status != HTTP_OK)
379 {
380 switch (status)
381 {
382 case HTTP_NOT_FOUND :
383 _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
384 break;
385
386 case HTTP_UNAUTHORIZED :
387 _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
388 break;
389
390 case HTTP_FORBIDDEN :
391 _cupsSetError(IPP_FORBIDDEN, httpStatus(status));
392 break;
393
394 case HTTP_BAD_REQUEST :
395 _cupsSetError(IPP_BAD_REQUEST, httpStatus(status));
396 break;
397
398 case HTTP_REQUEST_TOO_LARGE :
399 _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status));
400 break;
401
402 case HTTP_NOT_IMPLEMENTED :
403 _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status));
404 break;
405
406 case HTTP_NOT_SUPPORTED :
407 _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status));
408 break;
409
410 default :
411 DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
412 status));
413 _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
414 break;
415 }
416 }
417
418 return (response);
419 }
420
421
422 /*
423 * 'cupsDoRequest()' - Do an IPP request.
424 *
425 * This function sends the IPP request to the specified server, retrying
426 * and authenticating as necessary. The request is freed with ippDelete()
427 * after receiving a valid IPP response.
428 */
429
430 ipp_t * /* O - Response data */
431 cupsDoRequest(http_t *http, /* I - HTTP connection to server */
432 ipp_t *request, /* I - IPP request */
433 const char *resource) /* I - HTTP resource for POST */
434 {
435 return (cupsDoFileRequest(http, request, resource, NULL));
436 }
437
438
439 /*
440 * '_cupsSetError()' - Set the last IPP status code and status-message.
441 */
442
443 void
444 _cupsSetError(ipp_status_t status, /* I - IPP status code */
445 const char *message) /* I - status-message value */
446 {
447 _cups_globals_t *cg; /* Global data */
448
449
450 cg = _cupsGlobals();
451 cg->last_error = status;
452
453 if (cg->last_status_message)
454 {
455 free(cg->last_status_message);
456
457 cg->last_status_message = NULL;
458 }
459
460 if (message)
461 cg->last_status_message = strdup(message);
462 }
463
464
465 /*
466 * End of "$Id: request.c 5362 2006-03-31 15:26:12Z mike $".
467 */