]> 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 5495 2006-05-05 17:58:07Z 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[32768]; /* 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, strerror(EISDIR));
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 DEBUG_printf(("cupsDoFileRequest: http->error=%d (%s)\n", http->error,
282 strerror(http->error)));
283
284 #ifdef WIN32
285 if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH &&
286 http->error != ETIMEDOUT)
287 #else
288 if (http->error != ENETDOWN && http->error != ENETUNREACH &&
289 http->error != ETIMEDOUT)
290 #endif /* WIN32 */
291 continue;
292 else
293 break;
294 }
295 #ifdef HAVE_SSL
296 else if (status == HTTP_UPGRADE_REQUIRED)
297 {
298 /* Flush any error message... */
299 httpFlush(http);
300
301 /* Reconnect... */
302 if (httpReconnect(http))
303 {
304 status = HTTP_ERROR;
305 break;
306 }
307
308 /* Upgrade with encryption... */
309 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
310
311 /* Try again, this time with encryption enabled... */
312 continue;
313 }
314 #endif /* HAVE_SSL */
315 else if (status != HTTP_OK)
316 {
317 DEBUG_printf(("cupsDoFileRequest: error %d...\n", status));
318
319 /*
320 * Flush any error message...
321 */
322
323 httpFlush(http);
324 break;
325 }
326 else
327 {
328 /*
329 * Read the response...
330 */
331
332 DEBUG_puts("cupsDoFileRequest: response...");
333
334 response = ippNew();
335
336 while ((state = ippRead(http, response)) != IPP_DATA)
337 if (state == IPP_ERROR)
338 {
339 /*
340 * Delete the response...
341 */
342
343 DEBUG_puts("IPP read error!");
344 ippDelete(response);
345 response = NULL;
346
347 _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno));
348
349 break;
350 }
351 }
352 }
353
354 /*
355 * Close the file if needed...
356 */
357
358 if (filename != NULL)
359 fclose(file);
360
361 /*
362 * Flush any remaining data...
363 */
364
365 httpFlush(http);
366
367 /*
368 * Delete the original request and return the response...
369 */
370
371 ippDelete(request);
372
373 if (response)
374 {
375 ipp_attribute_t *attr; /* status-message attribute */
376
377
378 attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
379
380 _cupsSetError(response->request.status.status_code,
381 attr ? attr->values[0].string.text :
382 ippErrorString(response->request.status.status_code));
383 }
384 else if (status != HTTP_OK)
385 {
386 switch (status)
387 {
388 case HTTP_NOT_FOUND :
389 _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
390 break;
391
392 case HTTP_UNAUTHORIZED :
393 _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
394 break;
395
396 case HTTP_FORBIDDEN :
397 _cupsSetError(IPP_FORBIDDEN, httpStatus(status));
398 break;
399
400 case HTTP_BAD_REQUEST :
401 _cupsSetError(IPP_BAD_REQUEST, httpStatus(status));
402 break;
403
404 case HTTP_REQUEST_TOO_LARGE :
405 _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status));
406 break;
407
408 case HTTP_NOT_IMPLEMENTED :
409 _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status));
410 break;
411
412 case HTTP_NOT_SUPPORTED :
413 _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status));
414 break;
415
416 default :
417 DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
418 status));
419 _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
420 break;
421 }
422 }
423
424 return (response);
425 }
426
427
428 /*
429 * 'cupsDoRequest()' - Do an IPP request.
430 *
431 * This function sends the IPP request to the specified server, retrying
432 * and authenticating as necessary. The request is freed with ippDelete()
433 * after receiving a valid IPP response.
434 */
435
436 ipp_t * /* O - Response data */
437 cupsDoRequest(http_t *http, /* I - HTTP connection to server */
438 ipp_t *request, /* I - IPP request */
439 const char *resource) /* I - HTTP resource for POST */
440 {
441 return (cupsDoFileRequest(http, request, resource, NULL));
442 }
443
444
445 /*
446 * '_cupsSetError()' - Set the last IPP status code and status-message.
447 */
448
449 void
450 _cupsSetError(ipp_status_t status, /* I - IPP status code */
451 const char *message) /* I - status-message value */
452 {
453 _cups_globals_t *cg; /* Global data */
454
455
456 cg = _cupsGlobals();
457 cg->last_error = status;
458
459 if (cg->last_status_message)
460 {
461 free(cg->last_status_message);
462
463 cg->last_status_message = NULL;
464 }
465
466 if (message)
467 cg->last_status_message = strdup(message);
468 }
469
470
471 /*
472 * End of "$Id: request.c 5495 2006-05-05 17:58:07Z mike $".
473 */