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