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