]>
Commit | Line | Data |
---|---|---|
3b960317 | 1 | /* |
fba7409c | 2 | * "$Id: util.c,v 1.81.2.13 2002/05/27 14:47:13 mike Exp $" |
3b960317 | 3 | * |
4 | * Printing utilities for the Common UNIX Printing System (CUPS). | |
5 | * | |
839c43aa | 6 | * Copyright 1997-2002 by Easy Software Products. |
3b960317 | 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 | |
8784b6a6 | 17 | * 44141 Airport View Drive, Suite 204 |
3b960317 | 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 | * | |
dab1a4d8 | 24 | * This file is subject to the Apple OS-Developed Software exception. |
25 | * | |
3b960317 | 26 | * Contents: |
27 | * | |
3270670b | 28 | * cupsCancelJob() - Cancel a print job. |
018b8ca8 | 29 | * cupsDoFileRequest() - Do an IPP request... |
b5cb0608 | 30 | * cupsFreeJobs() - Free memory used by job data. |
3270670b | 31 | * cupsGetClasses() - Get a list of printer classes. |
32 | * cupsGetDefault() - Get the default printer or class. | |
b5cb0608 | 33 | * cupsGetJobs() - Get the jobs from the server. |
3270670b | 34 | * cupsGetPPD() - Get the PPD file for a printer. |
35 | * cupsGetPrinters() - Get a list of printers. | |
486cdc15 | 36 | * cupsLastError() - Return the last IPP error that occurred. |
3270670b | 37 | * cupsPrintFile() - Print a file to a printer or class. |
c7c24dd7 | 38 | * cupsPrintFiles() - Print one or more files to a printer or class. |
3270670b | 39 | * cups_connect() - Connect to the specified host... |
d2122fde | 40 | * cups_local_auth() - Get the local authorization certificate if |
41 | * available/applicable... | |
3b960317 | 42 | */ |
43 | ||
44 | /* | |
45 | * Include necessary headers... | |
46 | */ | |
47 | ||
48 | #include "cups.h" | |
4a73831b | 49 | #include "language.h" |
50 | #include "string.h" | |
51 | #include "debug.h" | |
aeabf506 | 52 | #include <stdlib.h> |
53 | #include <ctype.h> | |
4a73831b | 54 | #include <errno.h> |
04115410 | 55 | #include <fcntl.h> |
4a73831b | 56 | #include <sys/stat.h> |
d23a857a | 57 | #if defined(WIN32) || defined(__EMX__) |
58 | # include <io.h> | |
59 | #else | |
60 | # include <unistd.h> | |
61 | #endif /* WIN32 || __EMX__ */ | |
3b960317 | 62 | |
63 | ||
113aba7a | 64 | /* |
65 | * Local globals... | |
66 | */ | |
67 | ||
3095105a | 68 | static http_t *cups_server = NULL; /* Current server connection */ |
69 | static ipp_status_t last_error = IPP_OK; /* Last IPP error */ | |
83e740a5 | 70 | static char authstring[1024] = ""; /* Authorization string */ |
d23a857a | 71 | |
72 | ||
73 | /* | |
74 | * Local functions... | |
75 | */ | |
76 | ||
063e1ac7 | 77 | static char *cups_connect(const char *name, char *printer, char *hostname); |
d2122fde | 78 | static int cups_local_auth(http_t *http); |
113aba7a | 79 | |
80 | ||
8431231f | 81 | /* |
82 | * 'cupsCancelJob()' - Cancel a print job. | |
83 | */ | |
84 | ||
d23a857a | 85 | int /* O - 1 on success, 0 on failure */ |
063e1ac7 | 86 | cupsCancelJob(const char *name, /* I - Name of printer or class */ |
87 | int job) /* I - Job ID */ | |
3b960317 | 88 | { |
d23a857a | 89 | char printer[HTTP_MAX_URI], /* Printer name */ |
90 | hostname[HTTP_MAX_URI], /* Hostname */ | |
91 | uri[HTTP_MAX_URI]; /* Printer URI */ | |
92 | ipp_t *request, /* IPP request */ | |
93 | *response; /* IPP response */ | |
94 | cups_lang_t *language; /* Language info */ | |
95 | ||
96 | ||
97 | /* | |
98 | * See if we can connect to the server... | |
99 | */ | |
100 | ||
101 | if (!cups_connect(name, printer, hostname)) | |
9aebebc3 | 102 | { |
103 | last_error = IPP_SERVICE_UNAVAILABLE; | |
2bffb563 | 104 | return (0); |
9aebebc3 | 105 | } |
d23a857a | 106 | |
107 | /* | |
108 | * Build an IPP_CANCEL_JOB request, which requires the following | |
109 | * attributes: | |
110 | * | |
111 | * attributes-charset | |
112 | * attributes-natural-language | |
113 | * printer-uri | |
114 | * job-id | |
8b06ca19 | 115 | * [requesting-user-name] |
d23a857a | 116 | */ |
117 | ||
118 | request = ippNew(); | |
119 | ||
0a3ac972 | 120 | request->request.op.operation_id = IPP_CANCEL_JOB; |
121 | request->request.op.request_id = 1; | |
d23a857a | 122 | |
123 | language = cupsLangDefault(); | |
124 | ||
125 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
126 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
127 | ||
128 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
129 | "attributes-natural-language", NULL, | |
130 | language != NULL ? language->language : "C"); | |
131 | ||
04de52f8 | 132 | snprintf(uri, sizeof(uri), "ipp://%s:%d/printers/%s", hostname, ippPort(), printer); |
d23a857a | 133 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
134 | NULL, uri); | |
135 | ||
6d0582d2 | 136 | ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job); |
d23a857a | 137 | |
8b06ca19 | 138 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", |
139 | NULL, cupsUser()); | |
140 | ||
d23a857a | 141 | /* |
142 | * Do the request... | |
143 | */ | |
144 | ||
145 | if ((response = cupsDoRequest(cups_server, request, "/jobs/")) == NULL) | |
8b06ca19 | 146 | { |
147 | last_error = IPP_BAD_REQUEST; | |
d23a857a | 148 | return (0); |
8b06ca19 | 149 | } |
150 | else | |
151 | { | |
0a3ac972 | 152 | last_error = response->request.status.status_code; |
8b06ca19 | 153 | ippDelete(response); |
d23a857a | 154 | |
8b06ca19 | 155 | return (1); |
156 | } | |
3b960317 | 157 | } |
158 | ||
159 | ||
113aba7a | 160 | /* |
3270670b | 161 | * 'cupsDoFileRequest()' - Do an IPP request... |
113aba7a | 162 | */ |
163 | ||
3270670b | 164 | ipp_t * /* O - Response data */ |
063e1ac7 | 165 | cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */ |
166 | ipp_t *request, /* I - IPP request */ | |
167 | const char *resource, /* I - HTTP resource for POST */ | |
168 | const char *filename) /* I - File to send or NULL */ | |
113aba7a | 169 | { |
83e740a5 | 170 | ipp_t *response; /* IPP response data */ |
171 | char length[255]; /* Content-Length field */ | |
172 | http_status_t status; /* Status of HTTP request */ | |
173 | FILE *file; /* File to send */ | |
174 | struct stat fileinfo; /* File information */ | |
175 | int bytes; /* Number of bytes read/written */ | |
753453e4 | 176 | char buffer[32768]; /* Output buffer */ |
83e740a5 | 177 | const char *password; /* Password string */ |
178 | char realm[HTTP_MAX_VALUE], /* realm="xyz" string */ | |
179 | nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */ | |
180 | plain[255], /* Plaintext username:password */ | |
d2e58bfa | 181 | encode[512]; /* Encoded username:password */ |
3026be56 | 182 | char prompt[1024]; /* Prompt string */ |
113aba7a | 183 | |
184 | ||
0f6a2276 | 185 | if (http == NULL || request == NULL || resource == NULL) |
186 | { | |
187 | if (request != NULL) | |
188 | ippDelete(request); | |
189 | ||
190 | last_error = IPP_INTERNAL_ERROR; | |
191 | return (NULL); | |
192 | } | |
193 | ||
880dc0ce | 194 | DEBUG_printf(("cupsDoFileRequest(%p, %08x, \'%s\', \'%s\')\n", |
3270670b | 195 | http, request, resource, filename ? filename : "(null)")); |
113aba7a | 196 | |
197 | /* | |
3270670b | 198 | * See if we have a file to send... |
113aba7a | 199 | */ |
200 | ||
3270670b | 201 | if (filename != NULL) |
202 | { | |
203 | if (stat(filename, &fileinfo)) | |
204 | { | |
205 | /* | |
206 | * Can't get file information! | |
207 | */ | |
113aba7a | 208 | |
3270670b | 209 | ippDelete(request); |
9aebebc3 | 210 | last_error = IPP_NOT_FOUND; |
3270670b | 211 | return (NULL); |
212 | } | |
113aba7a | 213 | |
fba7409c | 214 | if (S_ISDIR(fileinfo.st_mode)) |
215 | { | |
216 | /* | |
217 | * Can't send a directory... | |
218 | */ | |
219 | ||
220 | ippDelete(request); | |
221 | last_error = IPP_NOT_POSSIBLE; | |
222 | return (NULL); | |
223 | } | |
224 | ||
3270670b | 225 | if ((file = fopen(filename, "rb")) == NULL) |
877378d9 | 226 | { |
3270670b | 227 | /* |
228 | * Can't open file! | |
229 | */ | |
230 | ||
877378d9 | 231 | ippDelete(request); |
9aebebc3 | 232 | last_error = IPP_NOT_FOUND; |
877378d9 | 233 | return (NULL); |
234 | } | |
3270670b | 235 | } |
d21a7597 | 236 | else |
237 | file = NULL; | |
113aba7a | 238 | |
239 | /* | |
3270670b | 240 | * Loop until we can send the request without authorization problems. |
113aba7a | 241 | */ |
242 | ||
3270670b | 243 | response = NULL; |
d21a7597 | 244 | status = HTTP_ERROR; |
d23a857a | 245 | |
3270670b | 246 | while (response == NULL) |
d23a857a | 247 | { |
3270670b | 248 | DEBUG_puts("cupsDoFileRequest: setup..."); |
249 | ||
d23a857a | 250 | /* |
3270670b | 251 | * Setup the HTTP variables needed... |
d23a857a | 252 | */ |
253 | ||
3270670b | 254 | if (filename != NULL) |
753453e4 | 255 | sprintf(length, "%lu", (unsigned long)(ippLength(request) + |
256 | (size_t)fileinfo.st_size)); | |
3270670b | 257 | else |
753453e4 | 258 | sprintf(length, "%lu", (unsigned long)ippLength(request)); |
d23a857a | 259 | |
3270670b | 260 | httpClearFields(http); |
261 | httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length); | |
262 | httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); | |
263 | httpSetField(http, HTTP_FIELD_AUTHORIZATION, authstring); | |
264 | ||
265 | /* | |
266 | * Try the request... | |
267 | */ | |
268 | ||
269 | DEBUG_puts("cupsDoFileRequest: post..."); | |
270 | ||
271 | if (httpPost(http, resource)) | |
dbb05cda | 272 | { |
273 | if (httpReconnect(http)) | |
274 | { | |
9d13ae31 | 275 | status = HTTP_ERROR; |
dbb05cda | 276 | break; |
277 | } | |
278 | else | |
279 | continue; | |
280 | } | |
3270670b | 281 | |
282 | /* | |
283 | * Send the IPP data and wait for the response... | |
284 | */ | |
285 | ||
286 | DEBUG_puts("cupsDoFileRequest: ipp write..."); | |
287 | ||
288 | request->state = IPP_IDLE; | |
018b8ca8 | 289 | if (ippWrite(http, request) != IPP_ERROR) |
290 | if (filename != NULL) | |
291 | { | |
292 | DEBUG_puts("cupsDoFileRequest: file write..."); | |
d23a857a | 293 | |
018b8ca8 | 294 | /* |
295 | * Send the file... | |
296 | */ | |
d23a857a | 297 | |
018b8ca8 | 298 | rewind(file); |
d23a857a | 299 | |
018b8ca8 | 300 | while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) |
301 | if (httpWrite(http, buffer, bytes) < bytes) | |
302 | break; | |
303 | } | |
d23a857a | 304 | |
d23a857a | 305 | /* |
3270670b | 306 | * Get the server's return status... |
d23a857a | 307 | */ |
308 | ||
3270670b | 309 | DEBUG_puts("cupsDoFileRequest: update..."); |
d23a857a | 310 | |
018b8ca8 | 311 | while ((status = httpUpdate(http)) == HTTP_CONTINUE); |
312 | ||
018b8ca8 | 313 | if (status == HTTP_UNAUTHORIZED) |
3270670b | 314 | { |
315 | DEBUG_puts("cupsDoFileRequest: unauthorized..."); | |
113aba7a | 316 | |
3270670b | 317 | /* |
318 | * Flush any error message... | |
319 | */ | |
320 | ||
321 | httpFlush(http); | |
322 | ||
d2122fde | 323 | /* |
324 | * See if we can do local authentication... | |
325 | */ | |
326 | ||
327 | if (cups_local_auth(http)) | |
328 | continue; | |
329 | ||
330 | /* | |
331 | * Nope - get a password from the user... | |
332 | */ | |
333 | ||
04de52f8 | 334 | snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(), |
3026be56 | 335 | http->hostname); |
3095105a | 336 | |
3026be56 | 337 | if ((password = cupsGetPassword(prompt)) != NULL) |
3270670b | 338 | { |
339 | /* | |
340 | * Got a password; send it to the server... | |
341 | */ | |
113aba7a | 342 | |
018b8ca8 | 343 | if (!password[0]) |
344 | break; | |
3270670b | 345 | |
83e740a5 | 346 | if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0) |
347 | { | |
348 | /* | |
349 | * Basic authentication... | |
350 | */ | |
351 | ||
04de52f8 | 352 | snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), password); |
83e740a5 | 353 | httpEncode64(encode, plain); |
04de52f8 | 354 | snprintf(authstring, sizeof(authstring), "Basic %s", encode); |
83e740a5 | 355 | } |
356 | else | |
357 | { | |
358 | /* | |
359 | * Digest authentication... | |
360 | */ | |
361 | ||
362 | httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm); | |
363 | httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce); | |
364 | ||
365 | httpMD5(cupsUser(), realm, password, encode); | |
366 | httpMD5Final(nonce, "POST", resource, encode); | |
04de52f8 | 367 | snprintf(authstring, sizeof(authstring), |
83e740a5 | 368 | "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " |
369 | "response=\"%s\"", cupsUser(), realm, nonce, encode); | |
370 | } | |
3270670b | 371 | continue; |
372 | } | |
3da4463c | 373 | else |
374 | break; | |
3270670b | 375 | } |
77be8777 | 376 | else if (status == HTTP_ERROR) |
377 | { | |
c3026ddc | 378 | #ifdef WIN32 |
977acbd3 | 379 | if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH) |
380 | #else | |
77be8777 | 381 | if (http->error != ENETDOWN && http->error != ENETUNREACH) |
c3026ddc | 382 | #endif /* WIN32 */ |
77be8777 | 383 | continue; |
384 | else | |
385 | break; | |
386 | } | |
b5cb0608 | 387 | #ifdef HAVE_LIBSSL |
388 | else if (status == HTTP_UPGRADE_REQUIRED) | |
389 | { | |
390 | /* | |
391 | * Flush any error message... | |
392 | */ | |
393 | ||
394 | httpFlush(http); | |
395 | ||
396 | /* | |
397 | * Try again, this time with encryption enabled... | |
398 | */ | |
399 | ||
400 | continue; | |
401 | } | |
402 | #endif /* HAVE_LIBSSL */ | |
77be8777 | 403 | else if (status != HTTP_OK) |
113aba7a | 404 | { |
3270670b | 405 | DEBUG_printf(("cupsDoFileRequest: error %d...\n", status)); |
d23a857a | 406 | |
407 | /* | |
3270670b | 408 | * Flush any error message... |
d23a857a | 409 | */ |
410 | ||
69ee1496 | 411 | httpFlush(http); |
3270670b | 412 | break; |
413 | } | |
414 | else | |
415 | { | |
416 | /* | |
417 | * Read the response... | |
418 | */ | |
419 | ||
420 | DEBUG_puts("cupsDoFileRequest: response..."); | |
421 | ||
422 | response = ippNew(); | |
423 | ||
424 | if (ippRead(http, response) == IPP_ERROR) | |
425 | { | |
426 | /* | |
427 | * Delete the response... | |
428 | */ | |
429 | ||
430 | ippDelete(response); | |
431 | response = NULL; | |
432 | ||
9aebebc3 | 433 | last_error = IPP_SERVICE_UNAVAILABLE; |
3270670b | 434 | break; |
435 | } | |
113aba7a | 436 | } |
437 | } | |
438 | ||
3270670b | 439 | /* |
440 | * Close the file if needed... | |
441 | */ | |
442 | ||
443 | if (filename != NULL) | |
444 | fclose(file); | |
445 | ||
f37fe731 | 446 | /* |
447 | * Flush any remaining data... | |
448 | */ | |
449 | ||
450 | httpFlush(http); | |
451 | ||
113aba7a | 452 | /* |
453 | * Delete the original request and return the response... | |
454 | */ | |
455 | ||
456 | ippDelete(request); | |
457 | ||
9aebebc3 | 458 | if (response) |
0a3ac972 | 459 | last_error = response->request.status.status_code; |
9aebebc3 | 460 | else if (status == HTTP_NOT_FOUND) |
461 | last_error = IPP_NOT_FOUND; | |
462 | else if (status == HTTP_UNAUTHORIZED) | |
463 | last_error = IPP_NOT_AUTHORIZED; | |
464 | else if (status != HTTP_OK) | |
465 | last_error = IPP_SERVICE_UNAVAILABLE; | |
466 | ||
113aba7a | 467 | return (response); |
468 | } | |
469 | ||
470 | ||
b5cb0608 | 471 | /* |
472 | * 'cupsFreeJobs()' - Free memory used by job data. | |
473 | */ | |
474 | ||
475 | void | |
476 | cupsFreeJobs(int num_jobs,/* I - Number of jobs */ | |
477 | cups_job_t *jobs) /* I - Jobs */ | |
478 | { | |
479 | int i; /* Looping var */ | |
480 | ||
481 | ||
482 | if (num_jobs <= 0 || jobs == NULL) | |
483 | return; | |
484 | ||
485 | for (i = 0; i < num_jobs; i ++) | |
486 | { | |
487 | free(jobs[i].dest); | |
488 | free(jobs[i].user); | |
489 | free(jobs[i].format); | |
490 | free(jobs[i].title); | |
491 | } | |
492 | ||
493 | free(jobs); | |
494 | } | |
495 | ||
496 | ||
8431231f | 497 | /* |
498 | * 'cupsGetClasses()' - Get a list of printer classes. | |
499 | */ | |
500 | ||
d23a857a | 501 | int /* O - Number of classes */ |
502 | cupsGetClasses(char ***classes) /* O - Classes */ | |
3b960317 | 503 | { |
d23a857a | 504 | int n; /* Number of classes */ |
505 | ipp_t *request, /* IPP Request */ | |
506 | *response; /* IPP Response */ | |
507 | ipp_attribute_t *attr; /* Current attribute */ | |
508 | cups_lang_t *language; /* Default language */ | |
a9b97a87 | 509 | char **temp; /* Temporary pointer */ |
d23a857a | 510 | |
511 | ||
0f6a2276 | 512 | if (classes == NULL) |
513 | { | |
514 | last_error = IPP_INTERNAL_ERROR; | |
515 | return (0); | |
516 | } | |
517 | ||
d23a857a | 518 | /* |
519 | * Try to connect to the server... | |
520 | */ | |
521 | ||
522 | if (!cups_connect("default", NULL, NULL)) | |
9aebebc3 | 523 | { |
524 | last_error = IPP_SERVICE_UNAVAILABLE; | |
2bffb563 | 525 | return (0); |
9aebebc3 | 526 | } |
d23a857a | 527 | |
528 | /* | |
529 | * Build a CUPS_GET_CLASSES request, which requires the following | |
530 | * attributes: | |
531 | * | |
532 | * attributes-charset | |
533 | * attributes-natural-language | |
27d555e8 | 534 | * requested-attributes |
d23a857a | 535 | */ |
536 | ||
537 | request = ippNew(); | |
538 | ||
0a3ac972 | 539 | request->request.op.operation_id = CUPS_GET_CLASSES; |
540 | request->request.op.request_id = 1; | |
d23a857a | 541 | |
542 | language = cupsLangDefault(); | |
543 | ||
544 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
a9b97a87 | 545 | "attributes-charset", NULL, cupsLangEncoding(language)); |
d23a857a | 546 | |
547 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
a9b97a87 | 548 | "attributes-natural-language", NULL, language->language); |
d23a857a | 549 | |
27d555e8 | 550 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, |
551 | "requested-attributes", NULL, "printer-name"); | |
552 | ||
d23a857a | 553 | /* |
554 | * Do the request and get back a response... | |
555 | */ | |
556 | ||
557 | n = 0; | |
558 | *classes = NULL; | |
559 | ||
a9b97a87 | 560 | if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) |
d23a857a | 561 | { |
0a3ac972 | 562 | last_error = response->request.status.status_code; |
8b06ca19 | 563 | |
d23a857a | 564 | for (attr = response->attrs; attr != NULL; attr = attr->next) |
fbc6b634 | 565 | if (attr->name != NULL && |
566 | strcasecmp(attr->name, "printer-name") == 0 && | |
d23a857a | 567 | attr->value_tag == IPP_TAG_NAME) |
568 | { | |
569 | if (n == 0) | |
a9b97a87 | 570 | temp = malloc(sizeof(char *)); |
d23a857a | 571 | else |
a9b97a87 | 572 | temp = realloc(*classes, sizeof(char *) * (n + 1)); |
d23a857a | 573 | |
a9b97a87 | 574 | if (temp == NULL) |
d23a857a | 575 | { |
a9b97a87 | 576 | /* |
577 | * Ran out of memory! | |
578 | */ | |
579 | ||
580 | while (n > 0) | |
581 | { | |
582 | n --; | |
583 | free((*classes)[n]); | |
584 | } | |
585 | ||
586 | free(*classes); | |
d23a857a | 587 | ippDelete(response); |
588 | return (0); | |
589 | } | |
590 | ||
a9b97a87 | 591 | *classes = temp; |
592 | temp[n] = strdup(attr->values[0].string.text); | |
d23a857a | 593 | n ++; |
594 | } | |
595 | ||
596 | ippDelete(response); | |
597 | } | |
8b06ca19 | 598 | else |
599 | last_error = IPP_BAD_REQUEST; | |
d23a857a | 600 | |
601 | return (n); | |
3b960317 | 602 | } |
603 | ||
604 | ||
8431231f | 605 | /* |
606 | * 'cupsGetDefault()' - Get the default printer or class. | |
607 | */ | |
608 | ||
063e1ac7 | 609 | const char * /* O - Default printer or NULL */ |
4a73831b | 610 | cupsGetDefault(void) |
611 | { | |
113aba7a | 612 | ipp_t *request, /* IPP Request */ |
613 | *response; /* IPP Response */ | |
614 | ipp_attribute_t *attr; /* Current attribute */ | |
615 | cups_lang_t *language; /* Default language */ | |
9aebebc3 | 616 | const char *var; /* Environment variable */ |
ddcb19a4 | 617 | static char def_printer[256];/* Default printer */ |
113aba7a | 618 | |
619 | ||
620 | /* | |
621 | * First see if the LPDEST or PRINTER environment variables are | |
9aebebc3 | 622 | * set... However, if PRINTER is set to "lp", ignore it to work |
623 | * around a "feature" in most Linux distributions - the default | |
624 | * user login scripts set PRINTER to "lp"... | |
113aba7a | 625 | */ |
626 | ||
9aebebc3 | 627 | if ((var = getenv("LPDEST")) != NULL) |
628 | return (var); | |
629 | else if ((var = getenv("PRINTER")) != NULL && strcmp(var, "lp") != 0) | |
630 | return (var); | |
113aba7a | 631 | |
632 | /* | |
633 | * Try to connect to the server... | |
634 | */ | |
635 | ||
d23a857a | 636 | if (!cups_connect("default", NULL, NULL)) |
9aebebc3 | 637 | { |
638 | last_error = IPP_SERVICE_UNAVAILABLE; | |
d23a857a | 639 | return (NULL); |
9aebebc3 | 640 | } |
113aba7a | 641 | |
642 | /* | |
643 | * Build a CUPS_GET_DEFAULT request, which requires the following | |
644 | * attributes: | |
645 | * | |
646 | * attributes-charset | |
647 | * attributes-natural-language | |
648 | */ | |
649 | ||
650 | request = ippNew(); | |
651 | ||
0a3ac972 | 652 | request->request.op.operation_id = CUPS_GET_DEFAULT; |
653 | request->request.op.request_id = 1; | |
113aba7a | 654 | |
655 | language = cupsLangDefault(); | |
656 | ||
d23a857a | 657 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, |
658 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
113aba7a | 659 | |
d23a857a | 660 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, |
661 | "attributes-natural-language", NULL, language->language); | |
113aba7a | 662 | |
663 | /* | |
664 | * Do the request and get back a response... | |
665 | */ | |
666 | ||
8b06ca19 | 667 | if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) |
113aba7a | 668 | { |
0a3ac972 | 669 | last_error = response->request.status.status_code; |
8b06ca19 | 670 | |
113aba7a | 671 | if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL) |
672 | { | |
def978d5 | 673 | strlcpy(def_printer, attr->values[0].string.text, sizeof(def_printer)); |
113aba7a | 674 | ippDelete(response); |
675 | return (def_printer); | |
676 | } | |
677 | ||
678 | ippDelete(response); | |
679 | } | |
8b06ca19 | 680 | else |
681 | last_error = IPP_BAD_REQUEST; | |
113aba7a | 682 | |
683 | return (NULL); | |
4a73831b | 684 | } |
685 | ||
686 | ||
b5cb0608 | 687 | /* |
688 | * 'cupsGetJobs()' - Get the jobs from the server. | |
689 | */ | |
690 | ||
691 | int /* O - Number of jobs */ | |
692 | cupsGetJobs(cups_job_t **jobs, /* O - Job data */ | |
693 | const char *mydest, /* I - Only show jobs for dest? */ | |
694 | int myjobs, /* I - Only show my jobs? */ | |
695 | int completed) /* I - Only show completed jobs? */ | |
696 | { | |
697 | int n; /* Number of jobs */ | |
698 | ipp_t *request, /* IPP Request */ | |
699 | *response; /* IPP Response */ | |
700 | ipp_attribute_t *attr; /* Current attribute */ | |
701 | cups_lang_t *language; /* Default language */ | |
702 | cups_job_t *temp; /* Temporary pointer */ | |
703 | int id, /* job-id */ | |
704 | priority, /* job-priority */ | |
705 | size; /* job-k-octets */ | |
706 | ipp_jstate_t state; /* job-state */ | |
707 | time_t completed_time, /* time-at-completed */ | |
708 | creation_time, /* time-at-creation */ | |
709 | processing_time; /* time-at-processing */ | |
710 | const char *dest, /* job-printer-uri */ | |
711 | *format, /* document-format */ | |
712 | *title, /* job-name */ | |
713 | *user; /* job-originating-user-name */ | |
714 | char uri[HTTP_MAX_URI]; /* URI for jobs */ | |
715 | static const char *attrs[] = /* Requested attributes */ | |
716 | { | |
717 | "job-id", | |
718 | "job-priority", | |
719 | "job-k-octets", | |
720 | "job-state", | |
721 | "time-at-completed", | |
722 | "time-at-creation", | |
723 | "time-at-processing", | |
724 | "job-printer-uri", | |
725 | "document-format", | |
726 | "job-name", | |
727 | "job-originating-user-name" | |
728 | }; | |
729 | ||
730 | ||
731 | if (jobs == NULL) | |
732 | { | |
733 | last_error = IPP_INTERNAL_ERROR; | |
734 | return (0); | |
735 | } | |
736 | ||
737 | /* | |
738 | * Try to connect to the server... | |
739 | */ | |
740 | ||
741 | if (!cups_connect("default", NULL, NULL)) | |
742 | { | |
743 | last_error = IPP_SERVICE_UNAVAILABLE; | |
744 | return (0); | |
745 | } | |
746 | ||
747 | /* | |
748 | * Build an IPP_GET_JOBS request, which requires the following | |
749 | * attributes: | |
750 | * | |
751 | * attributes-charset | |
752 | * attributes-natural-language | |
753 | * printer-uri | |
754 | * requesting-user-name | |
755 | * which-jobs | |
756 | * my-jobs | |
757 | * requested-attributes | |
758 | */ | |
759 | ||
760 | request = ippNew(); | |
761 | ||
0a3ac972 | 762 | request->request.op.operation_id = IPP_GET_JOBS; |
763 | request->request.op.request_id = 1; | |
b5cb0608 | 764 | |
765 | language = cupsLangDefault(); | |
766 | ||
767 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
768 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
769 | ||
770 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
771 | "attributes-natural-language", NULL, language->language); | |
772 | ||
773 | if (mydest) | |
774 | snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", mydest); | |
775 | else | |
776 | strcpy(uri, "ipp://localhost/jobs"); | |
777 | ||
778 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, | |
779 | "printer-uri", NULL, uri); | |
780 | ||
781 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, | |
782 | "requesting-user-name", NULL, cupsUser()); | |
783 | ||
784 | if (myjobs) | |
785 | ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); | |
786 | ||
787 | if (completed) | |
788 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
789 | "which-jobs", NULL, "completed"); | |
790 | ||
791 | ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
792 | "requested-attributes", sizeof(attrs) / sizeof(attrs[0]), | |
793 | NULL, attrs); | |
794 | ||
795 | /* | |
796 | * Do the request and get back a response... | |
797 | */ | |
798 | ||
799 | n = 0; | |
800 | *jobs = NULL; | |
801 | ||
802 | if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) | |
803 | { | |
0a3ac972 | 804 | last_error = response->request.status.status_code; |
b5cb0608 | 805 | |
806 | for (attr = response->attrs; attr != NULL; attr = attr->next) | |
807 | { | |
808 | /* | |
809 | * Skip leading attributes until we hit a job... | |
810 | */ | |
811 | ||
812 | while (attr != NULL && attr->group_tag != IPP_TAG_JOB) | |
813 | attr = attr->next; | |
814 | ||
815 | if (attr == NULL) | |
816 | break; | |
817 | ||
818 | /* | |
819 | * Pull the needed attributes from this job... | |
820 | */ | |
821 | ||
822 | id = 0; | |
823 | size = 0; | |
824 | priority = 50; | |
825 | state = IPP_JOB_PENDING; | |
826 | user = NULL; | |
827 | dest = NULL; | |
828 | format = NULL; | |
829 | title = NULL; | |
830 | creation_time = 0; | |
831 | completed_time = 0; | |
832 | processing_time = 0; | |
833 | ||
834 | while (attr != NULL && attr->group_tag == IPP_TAG_JOB) | |
835 | { | |
836 | if (strcmp(attr->name, "job-id") == 0 && | |
837 | attr->value_tag == IPP_TAG_INTEGER) | |
838 | id = attr->values[0].integer; | |
839 | else if (strcmp(attr->name, "job-state") == 0 && | |
840 | attr->value_tag == IPP_TAG_ENUM) | |
841 | state = (ipp_jstate_t)attr->values[0].integer; | |
842 | else if (strcmp(attr->name, "job-priority") == 0 && | |
843 | attr->value_tag == IPP_TAG_INTEGER) | |
844 | priority = attr->values[0].integer; | |
845 | else if (strcmp(attr->name, "job-k-octets") == 0 && | |
846 | attr->value_tag == IPP_TAG_INTEGER) | |
847 | size = attr->values[0].integer; | |
848 | else if (strcmp(attr->name, "time-at-completed") == 0 && | |
849 | attr->value_tag == IPP_TAG_INTEGER) | |
850 | completed_time = attr->values[0].integer; | |
851 | else if (strcmp(attr->name, "time-at-creation") == 0 && | |
852 | attr->value_tag == IPP_TAG_INTEGER) | |
853 | creation_time = attr->values[0].integer; | |
854 | else if (strcmp(attr->name, "time-at-processing") == 0 && | |
855 | attr->value_tag == IPP_TAG_INTEGER) | |
856 | processing_time = attr->values[0].integer; | |
857 | else if (strcmp(attr->name, "job-printer-uri") == 0 && | |
858 | attr->value_tag == IPP_TAG_URI) | |
859 | { | |
860 | if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL) | |
861 | dest ++; | |
862 | } | |
863 | else if (strcmp(attr->name, "job-originating-user-name") == 0 && | |
864 | attr->value_tag == IPP_TAG_NAME) | |
865 | user = attr->values[0].string.text; | |
866 | else if (strcmp(attr->name, "document-format") == 0 && | |
867 | attr->value_tag == IPP_TAG_MIMETYPE) | |
868 | format = attr->values[0].string.text; | |
869 | else if (strcmp(attr->name, "job-name") == 0 && | |
59168282 | 870 | (attr->value_tag == IPP_TAG_TEXT || |
871 | attr->value_tag == IPP_TAG_NAME)) | |
b5cb0608 | 872 | title = attr->values[0].string.text; |
873 | ||
874 | attr = attr->next; | |
875 | } | |
876 | ||
877 | /* | |
878 | * See if we have everything needed... | |
879 | */ | |
880 | ||
59168282 | 881 | if (dest == NULL || title == NULL || user == NULL || id == 0) |
b5cb0608 | 882 | { |
883 | if (attr == NULL) | |
884 | break; | |
885 | else | |
886 | continue; | |
887 | } | |
888 | ||
59168282 | 889 | if (format == NULL) |
890 | format = "application/octet-stream"; | |
891 | ||
b5cb0608 | 892 | /* |
893 | * Allocate memory for the job... | |
894 | */ | |
895 | ||
896 | if (n == 0) | |
897 | temp = malloc(sizeof(cups_job_t)); | |
898 | else | |
899 | temp = realloc(*jobs, sizeof(cups_job_t) * (n + 1)); | |
900 | ||
901 | if (temp == NULL) | |
902 | { | |
903 | /* | |
904 | * Ran out of memory! | |
905 | */ | |
906 | ||
907 | cupsFreeJobs(n, *jobs); | |
908 | *jobs = NULL; | |
909 | ||
910 | ippDelete(response); | |
911 | return (0); | |
912 | } | |
913 | ||
914 | *jobs = temp; | |
915 | temp += n; | |
916 | n ++; | |
917 | ||
918 | /* | |
919 | * Copy the data over... | |
920 | */ | |
921 | ||
922 | temp->dest = strdup(dest); | |
923 | temp->user = strdup(user); | |
924 | temp->format = strdup(format); | |
925 | temp->title = strdup(title); | |
926 | temp->id = id; | |
927 | temp->priority = priority; | |
928 | temp->state = state; | |
929 | temp->size = size; | |
930 | temp->completed_time = completed_time; | |
931 | temp->creation_time = creation_time; | |
932 | temp->processing_time = processing_time; | |
59168282 | 933 | |
934 | if (attr == NULL) | |
935 | break; | |
b5cb0608 | 936 | } |
937 | ||
938 | ippDelete(response); | |
939 | } | |
940 | else | |
941 | last_error = IPP_BAD_REQUEST; | |
942 | ||
943 | return (n); | |
944 | } | |
945 | ||
946 | ||
8431231f | 947 | /* |
948 | * 'cupsGetPPD()' - Get the PPD file for a printer. | |
949 | */ | |
950 | ||
83e740a5 | 951 | const char * /* O - Filename for PPD file */ |
952 | cupsGetPPD(const char *name) /* I - Printer name */ | |
3b960317 | 953 | { |
ce314a94 | 954 | int i; /* Looping var */ |
bc16fd64 | 955 | ipp_t *request, /* IPP request */ |
956 | *response; /* IPP response */ | |
957 | ipp_attribute_t *attr; /* Current attribute */ | |
958 | cups_lang_t *language; /* Local language */ | |
1b5bf964 | 959 | int fd; /* PPD file */ |
d23a857a | 960 | int bytes; /* Number of bytes read */ |
961 | char buffer[8192]; /* Buffer for file */ | |
962 | char printer[HTTP_MAX_URI], /* Printer name */ | |
bc16fd64 | 963 | method[HTTP_MAX_URI], /* Method/scheme name */ |
964 | username[HTTP_MAX_URI], /* Username:password */ | |
d23a857a | 965 | hostname[HTTP_MAX_URI], /* Hostname */ |
966 | resource[HTTP_MAX_URI]; /* Resource name */ | |
bc16fd64 | 967 | int port; /* Port number */ |
3095105a | 968 | const char *password; /* Password string */ |
83e740a5 | 969 | char realm[HTTP_MAX_VALUE], /* realm="xyz" string */ |
970 | nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */ | |
971 | plain[255], /* Plaintext username:password */ | |
d2e58bfa | 972 | encode[512]; /* Encoded username:password */ |
3095105a | 973 | http_status_t status; /* HTTP status from server */ |
3026be56 | 974 | char prompt[1024]; /* Prompt string */ |
3095105a | 975 | static char filename[HTTP_MAX_URI]; /* Local filename */ |
ce314a94 | 976 | static const char *requested_attrs[] =/* Requested attributes */ |
977 | { | |
978 | "printer-uri-supported", | |
979 | "printer-type", | |
980 | "member-uris" | |
981 | }; | |
d23a857a | 982 | |
983 | ||
0f6a2276 | 984 | if (name == NULL) |
985 | { | |
986 | last_error = IPP_INTERNAL_ERROR; | |
987 | return (NULL); | |
988 | } | |
989 | ||
d23a857a | 990 | /* |
991 | * See if we can connect to the server... | |
992 | */ | |
993 | ||
994 | if (!cups_connect(name, printer, hostname)) | |
9aebebc3 | 995 | { |
996 | last_error = IPP_SERVICE_UNAVAILABLE; | |
d23a857a | 997 | return (NULL); |
9aebebc3 | 998 | } |
d23a857a | 999 | |
ce314a94 | 1000 | /* |
1001 | * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following | |
1002 | * attributes: | |
1003 | * | |
1004 | * attributes-charset | |
1005 | * attributes-natural-language | |
1006 | * printer-uri | |
1007 | * requested-attributes | |
1008 | */ | |
1009 | ||
1010 | request = ippNew(); | |
1011 | ||
0a3ac972 | 1012 | request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; |
1013 | request->request.op.request_id = 1; | |
bc16fd64 | 1014 | |
ce314a94 | 1015 | language = cupsLangDefault(); |
bc16fd64 | 1016 | |
ce314a94 | 1017 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, |
1018 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
bc16fd64 | 1019 | |
ce314a94 | 1020 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, |
1021 | "attributes-natural-language", NULL, language->language); | |
bc16fd64 | 1022 | |
c6e1ca5d | 1023 | snprintf(buffer, sizeof(buffer), "ipp://localhost/printers/%s", printer); |
ce314a94 | 1024 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, |
1025 | "printer-uri", NULL, buffer); | |
bc16fd64 | 1026 | |
ce314a94 | 1027 | ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME, |
1028 | "requested-attributes", | |
1029 | sizeof(requested_attrs) / sizeof(requested_attrs[0]), | |
1030 | NULL, requested_attrs); | |
bc16fd64 | 1031 | |
ce314a94 | 1032 | /* |
1033 | * Do the request and get back a response... | |
1034 | */ | |
bc16fd64 | 1035 | |
ce314a94 | 1036 | if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) |
1037 | { | |
0a3ac972 | 1038 | last_error = response->request.status.status_code; |
ce314a94 | 1039 | printer[0] = '\0'; |
1040 | hostname[0] = '\0'; | |
bc16fd64 | 1041 | |
ce314a94 | 1042 | if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL) |
bc16fd64 | 1043 | { |
ce314a94 | 1044 | /* |
1045 | * Get the first actual server and printer name in the class... | |
1046 | */ | |
bc16fd64 | 1047 | |
ce314a94 | 1048 | for (i = 0; i < attr->num_values; i ++) |
bc16fd64 | 1049 | { |
ce314a94 | 1050 | httpSeparate(attr->values[0].string.text, method, username, hostname, |
bc16fd64 | 1051 | &port, resource); |
ce314a94 | 1052 | if (strncmp(resource, "/printers/", 10) == 0) |
1053 | { | |
1054 | /* | |
1055 | * Found a printer! | |
1056 | */ | |
bc16fd64 | 1057 | |
def978d5 | 1058 | strlcpy(printer, resource + 10, sizeof(printer)); |
ce314a94 | 1059 | break; |
1060 | } | |
bc16fd64 | 1061 | } |
ce314a94 | 1062 | } |
1063 | else if ((attr = ippFindAttribute(response, "printer-uri-supported", | |
1064 | IPP_TAG_URI)) != NULL) | |
1065 | { | |
1066 | /* | |
1067 | * Get the actual server and printer names... | |
1068 | */ | |
bc16fd64 | 1069 | |
ce314a94 | 1070 | httpSeparate(attr->values[0].string.text, method, username, hostname, |
1071 | &port, resource); | |
def978d5 | 1072 | strlcpy(printer, strrchr(resource, '/') + 1, sizeof(printer)); |
bc16fd64 | 1073 | } |
1074 | ||
ce314a94 | 1075 | ippDelete(response); |
bc16fd64 | 1076 | |
1077 | /* | |
ce314a94 | 1078 | * Remap local hostname to localhost... |
bc16fd64 | 1079 | */ |
1080 | ||
ce314a94 | 1081 | gethostname(buffer, sizeof(buffer)); |
bc16fd64 | 1082 | |
ce314a94 | 1083 | if (strcasecmp(buffer, hostname) == 0) |
1084 | strcpy(hostname, "localhost"); | |
1085 | } | |
1086 | ||
1087 | cupsLangFree(language); | |
1088 | ||
1089 | if (!printer[0]) | |
1090 | return (NULL); | |
1091 | ||
1092 | /* | |
1093 | * Reconnect to the correct server as needed... | |
1094 | */ | |
1095 | ||
1096 | if (strcasecmp(cups_server->hostname, hostname) != 0) | |
1097 | { | |
1098 | httpClose(cups_server); | |
1099 | ||
b5cb0608 | 1100 | if ((cups_server = httpConnectEncrypt(hostname, ippPort(), |
1101 | cupsEncryption())) == NULL) | |
ce314a94 | 1102 | { |
1103 | last_error = IPP_SERVICE_UNAVAILABLE; | |
1104 | return (NULL); | |
bc16fd64 | 1105 | } |
1106 | } | |
1107 | ||
d23a857a | 1108 | /* |
082b40d2 | 1109 | * Get a temp file... |
d23a857a | 1110 | */ |
1111 | ||
1b5bf964 | 1112 | if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) |
1113 | { | |
1114 | /* | |
1115 | * Can't open file; close the server connection and return NULL... | |
1116 | */ | |
1117 | ||
1118 | httpFlush(cups_server); | |
1119 | httpClose(cups_server); | |
1120 | cups_server = NULL; | |
1121 | return (NULL); | |
1122 | } | |
d23a857a | 1123 | |
1124 | /* | |
e269c4f8 | 1125 | * And send a request to the HTTP server... |
d23a857a | 1126 | */ |
1127 | ||
04de52f8 | 1128 | snprintf(resource, sizeof(resource), "/printers/%s.ppd", printer); |
d23a857a | 1129 | |
3095105a | 1130 | do |
d23a857a | 1131 | { |
3095105a | 1132 | httpClearFields(cups_server); |
1133 | httpSetField(cups_server, HTTP_FIELD_HOST, hostname); | |
1134 | httpSetField(cups_server, HTTP_FIELD_AUTHORIZATION, authstring); | |
1135 | ||
1136 | if (httpGet(cups_server, resource)) | |
1137 | { | |
dbb05cda | 1138 | if (httpReconnect(cups_server)) |
1139 | { | |
1140 | status = HTTP_ERROR; | |
1141 | break; | |
1142 | } | |
1143 | else | |
1144 | { | |
1145 | status = HTTP_UNAUTHORIZED; | |
1146 | continue; | |
1147 | } | |
3095105a | 1148 | } |
1149 | ||
1150 | while ((status = httpUpdate(cups_server)) == HTTP_CONTINUE); | |
1151 | ||
1152 | if (status == HTTP_UNAUTHORIZED) | |
1153 | { | |
1154 | DEBUG_puts("cupsGetPPD: unauthorized..."); | |
1155 | ||
1156 | /* | |
1157 | * Flush any error message... | |
1158 | */ | |
1159 | ||
1160 | httpFlush(cups_server); | |
1161 | ||
d2122fde | 1162 | /* |
1163 | * See if we can do local authentication... | |
1164 | */ | |
1165 | ||
1166 | if (cups_local_auth(cups_server)) | |
1167 | continue; | |
1168 | ||
1169 | /* | |
1170 | * Nope, get a password from the user... | |
1171 | */ | |
1172 | ||
04de52f8 | 1173 | snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(), |
3026be56 | 1174 | cups_server->hostname); |
3095105a | 1175 | |
3026be56 | 1176 | if ((password = cupsGetPassword(prompt)) != NULL) |
3095105a | 1177 | { |
1178 | /* | |
1179 | * Got a password; send it to the server... | |
1180 | */ | |
1181 | ||
1182 | if (!password[0]) | |
1183 | break; | |
3095105a | 1184 | |
83e740a5 | 1185 | if (strncmp(cups_server->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Basic", 5) == 0) |
1186 | { | |
1187 | /* | |
1188 | * Basic authentication... | |
1189 | */ | |
1190 | ||
04de52f8 | 1191 | snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), password); |
83e740a5 | 1192 | httpEncode64(encode, plain); |
04de52f8 | 1193 | snprintf(authstring, sizeof(authstring), "Basic %s", encode); |
83e740a5 | 1194 | } |
1195 | else | |
1196 | { | |
1197 | /* | |
1198 | * Digest authentication... | |
1199 | */ | |
1200 | ||
1201 | httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm); | |
1202 | httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce); | |
1203 | ||
1204 | httpMD5(cupsUser(), realm, password, encode); | |
1205 | httpMD5Final(nonce, "GET", resource, encode); | |
04de52f8 | 1206 | snprintf(authstring, sizeof(authstring), |
83e740a5 | 1207 | "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " |
1208 | "response=\"%s\"", cupsUser(), realm, nonce, encode); | |
1209 | } | |
3095105a | 1210 | continue; |
1211 | } | |
1212 | else | |
d23a857a | 1213 | break; |
3095105a | 1214 | } |
d23a857a | 1215 | } |
b5cb0608 | 1216 | while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED); |
d23a857a | 1217 | |
1218 | /* | |
1b5bf964 | 1219 | * See if we actually got the file or an error... |
d23a857a | 1220 | */ |
1221 | ||
1b5bf964 | 1222 | if (status != HTTP_OK) |
d23a857a | 1223 | { |
1b5bf964 | 1224 | unlink(filename); |
bc16fd64 | 1225 | httpFlush(cups_server); |
d23a857a | 1226 | httpClose(cups_server); |
1227 | cups_server = NULL; | |
1228 | return (NULL); | |
1229 | } | |
1230 | ||
1b5bf964 | 1231 | /* |
1232 | * OK, we need to copy the file... | |
1233 | */ | |
1234 | ||
d23a857a | 1235 | while ((bytes = httpRead(cups_server, buffer, sizeof(buffer))) > 0) |
1b5bf964 | 1236 | write(fd, buffer, bytes); |
d23a857a | 1237 | |
1b5bf964 | 1238 | close(fd); |
d23a857a | 1239 | |
1240 | return (filename); | |
3b960317 | 1241 | } |
1242 | ||
1243 | ||
8431231f | 1244 | /* |
1245 | * 'cupsGetPrinters()' - Get a list of printers. | |
1246 | */ | |
1247 | ||
d23a857a | 1248 | int /* O - Number of printers */ |
1249 | cupsGetPrinters(char ***printers) /* O - Printers */ | |
3b960317 | 1250 | { |
d23a857a | 1251 | int n; /* Number of printers */ |
1252 | ipp_t *request, /* IPP Request */ | |
1253 | *response; /* IPP Response */ | |
1254 | ipp_attribute_t *attr; /* Current attribute */ | |
1255 | cups_lang_t *language; /* Default language */ | |
a9b97a87 | 1256 | char **temp; /* Temporary pointer */ |
d23a857a | 1257 | |
1258 | ||
0f6a2276 | 1259 | if (printers == NULL) |
1260 | { | |
1261 | last_error = IPP_INTERNAL_ERROR; | |
1262 | return (0); | |
1263 | } | |
1264 | ||
d23a857a | 1265 | /* |
1266 | * Try to connect to the server... | |
1267 | */ | |
1268 | ||
1269 | if (!cups_connect("default", NULL, NULL)) | |
9aebebc3 | 1270 | { |
1271 | last_error = IPP_SERVICE_UNAVAILABLE; | |
2bffb563 | 1272 | return (0); |
9aebebc3 | 1273 | } |
d23a857a | 1274 | |
1275 | /* | |
1276 | * Build a CUPS_GET_PRINTERS request, which requires the following | |
1277 | * attributes: | |
1278 | * | |
1279 | * attributes-charset | |
1280 | * attributes-natural-language | |
27d555e8 | 1281 | * requested-attributes |
d23a857a | 1282 | */ |
1283 | ||
1284 | request = ippNew(); | |
1285 | ||
0a3ac972 | 1286 | request->request.op.operation_id = CUPS_GET_PRINTERS; |
1287 | request->request.op.request_id = 1; | |
d23a857a | 1288 | |
1289 | language = cupsLangDefault(); | |
1290 | ||
1291 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
a9b97a87 | 1292 | "attributes-charset", NULL, cupsLangEncoding(language)); |
d23a857a | 1293 | |
1294 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
a9b97a87 | 1295 | "attributes-natural-language", NULL, language->language); |
d23a857a | 1296 | |
27d555e8 | 1297 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, |
1298 | "requested-attributes", NULL, "printer-name"); | |
1299 | ||
d23a857a | 1300 | /* |
1301 | * Do the request and get back a response... | |
1302 | */ | |
1303 | ||
1304 | n = 0; | |
1305 | *printers = NULL; | |
1306 | ||
a9b97a87 | 1307 | if ((response = cupsDoRequest(cups_server, request, "/")) != NULL) |
d23a857a | 1308 | { |
0a3ac972 | 1309 | last_error = response->request.status.status_code; |
8b06ca19 | 1310 | |
d23a857a | 1311 | for (attr = response->attrs; attr != NULL; attr = attr->next) |
fbc6b634 | 1312 | if (attr->name != NULL && |
1313 | strcasecmp(attr->name, "printer-name") == 0 && | |
d23a857a | 1314 | attr->value_tag == IPP_TAG_NAME) |
1315 | { | |
1316 | if (n == 0) | |
a9b97a87 | 1317 | temp = malloc(sizeof(char *)); |
d23a857a | 1318 | else |
a9b97a87 | 1319 | temp = realloc(*printers, sizeof(char *) * (n + 1)); |
d23a857a | 1320 | |
a9b97a87 | 1321 | if (temp == NULL) |
d23a857a | 1322 | { |
a9b97a87 | 1323 | /* |
1324 | * Ran out of memory! | |
1325 | */ | |
1326 | ||
1327 | while (n > 0) | |
1328 | { | |
1329 | n --; | |
1330 | free((*printers)[n]); | |
1331 | } | |
1332 | ||
1333 | free(*printers); | |
d23a857a | 1334 | ippDelete(response); |
1335 | return (0); | |
1336 | } | |
1337 | ||
a9b97a87 | 1338 | *printers = temp; |
1339 | temp[n] = strdup(attr->values[0].string.text); | |
d23a857a | 1340 | n ++; |
1341 | } | |
1342 | ||
1343 | ippDelete(response); | |
1344 | } | |
8b06ca19 | 1345 | else |
1346 | last_error = IPP_BAD_REQUEST; | |
d23a857a | 1347 | |
1348 | return (n); | |
3b960317 | 1349 | } |
1350 | ||
1351 | ||
8b06ca19 | 1352 | /* |
1353 | * 'cupsLastError()' - Return the last IPP error that occurred. | |
1354 | */ | |
1355 | ||
1356 | ipp_status_t /* O - IPP error code */ | |
1357 | cupsLastError(void) | |
1358 | { | |
1359 | return (last_error); | |
1360 | } | |
1361 | ||
1362 | ||
4a73831b | 1363 | /* |
1364 | * 'cupsPrintFile()' - Print a file to a printer or class. | |
1365 | */ | |
1366 | ||
1367 | int /* O - Job ID */ | |
063e1ac7 | 1368 | cupsPrintFile(const char *name, /* I - Printer or class name */ |
1369 | const char *filename, /* I - File to print */ | |
1370 | const char *title, /* I - Title of job */ | |
4a73831b | 1371 | int num_options,/* I - Number of options */ |
1372 | cups_option_t *options) /* I - Options */ | |
501b59e2 | 1373 | { |
183914a3 | 1374 | DEBUG_printf(("cupsPrintFile(\'%s\', \'%s\', %d, %p)\n", |
880dc0ce | 1375 | name, filename, num_options, options)); |
501b59e2 | 1376 | |
1377 | return (cupsPrintFiles(name, 1, &filename, title, num_options, options)); | |
1378 | } | |
1379 | ||
1380 | ||
1381 | /* | |
1382 | * 'cupsPrintFiles()' - Print one or more files to a printer or class. | |
1383 | */ | |
1384 | ||
1385 | int /* O - Job ID */ | |
1386 | cupsPrintFiles(const char *name, /* I - Printer or class name */ | |
1387 | int num_files, /* I - Number of files */ | |
1388 | const char **files, /* I - File(s) to print */ | |
1389 | const char *title, /* I - Title of job */ | |
1390 | int num_options,/* I - Number of options */ | |
1391 | cups_option_t *options) /* I - Options */ | |
3b960317 | 1392 | { |
d23a857a | 1393 | int i; /* Looping var */ |
501b59e2 | 1394 | const char *val; /* Pointer to option value */ |
d23a857a | 1395 | ipp_t *request; /* IPP request */ |
1396 | ipp_t *response; /* IPP response */ | |
1397 | ipp_attribute_t *attr; /* IPP job-id attribute */ | |
1398 | char hostname[HTTP_MAX_URI], /* Hostname */ | |
1399 | printer[HTTP_MAX_URI], /* Printer or class name */ | |
1400 | uri[HTTP_MAX_URI]; /* Printer URI */ | |
1401 | cups_lang_t *language; /* Language to use */ | |
d23a857a | 1402 | int jobid; /* New job ID */ |
1403 | ||
4a73831b | 1404 | |
183914a3 | 1405 | DEBUG_printf(("cupsPrintFiles(\'%s\', %d, %p, %d, %p)\n", |
880dc0ce | 1406 | name, num_files, files, num_options, options)); |
4a73831b | 1407 | |
501b59e2 | 1408 | if (name == NULL || num_files < 1 || files == NULL) |
4a73831b | 1409 | return (0); |
1410 | ||
4a73831b | 1411 | /* |
1412 | * Setup a connection and request data... | |
1413 | */ | |
1414 | ||
d23a857a | 1415 | if (!cups_connect(name, printer, hostname)) |
1416 | { | |
1417 | DEBUG_printf(("cupsPrintFile: Unable to open connection - %s.\n", | |
1418 | strerror(errno))); | |
9aebebc3 | 1419 | last_error = IPP_SERVICE_UNAVAILABLE; |
d23a857a | 1420 | return (0); |
1421 | } | |
4a73831b | 1422 | |
501b59e2 | 1423 | language = cupsLangDefault(); |
1424 | ||
4a73831b | 1425 | /* |
1426 | * Build a standard CUPS URI for the printer and fill the standard IPP | |
1427 | * attributes... | |
1428 | */ | |
1429 | ||
c7c24dd7 | 1430 | if ((request = ippNew()) == NULL) |
1431 | return (0); | |
1432 | ||
0a3ac972 | 1433 | request->request.op.operation_id = num_files == 1 ? IPP_PRINT_JOB : |
501b59e2 | 1434 | IPP_CREATE_JOB; |
0a3ac972 | 1435 | request->request.op.request_id = 1; |
4a73831b | 1436 | |
04de52f8 | 1437 | snprintf(uri, sizeof(uri), "ipp://%s:%d/printers/%s", hostname, ippPort(), printer); |
4a73831b | 1438 | |
d23a857a | 1439 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, |
1440 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
4a73831b | 1441 | |
d23a857a | 1442 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, |
1443 | "attributes-natural-language", NULL, | |
1444 | language != NULL ? language->language : "C"); | |
4a73831b | 1445 | |
d23a857a | 1446 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", |
1447 | NULL, uri); | |
4a73831b | 1448 | |
6d0582d2 | 1449 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", |
ac4c1450 | 1450 | NULL, cupsUser()); |
4a73831b | 1451 | |
d23a857a | 1452 | if (title) |
6d0582d2 | 1453 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title); |
d23a857a | 1454 | |
4a73831b | 1455 | /* |
183914a3 | 1456 | * Then add all options... |
4a73831b | 1457 | */ |
1458 | ||
183914a3 | 1459 | cupsEncodeOptions(request, num_options, options); |
4a73831b | 1460 | |
1461 | /* | |
501b59e2 | 1462 | * Do the request... |
4a73831b | 1463 | */ |
1464 | ||
04de52f8 | 1465 | snprintf(uri, sizeof(uri), "/printers/%s", printer); |
4a73831b | 1466 | |
501b59e2 | 1467 | if (num_files == 1) |
1468 | response = cupsDoFileRequest(cups_server, request, uri, *files); | |
1469 | else | |
1470 | response = cupsDoRequest(cups_server, request, uri); | |
1471 | ||
1472 | if (response == NULL) | |
3270670b | 1473 | jobid = 0; |
0a3ac972 | 1474 | else if (response->request.status.status_code > IPP_OK_CONFLICT) |
4a73831b | 1475 | { |
3270670b | 1476 | DEBUG_printf(("IPP response code was 0x%x!\n", |
0a3ac972 | 1477 | response->request.status.status_code)); |
4a73831b | 1478 | jobid = 0; |
1479 | } | |
3270670b | 1480 | else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL) |
4a73831b | 1481 | { |
3270670b | 1482 | DEBUG_puts("No job ID!"); |
4a73831b | 1483 | jobid = 0; |
1484 | } | |
1485 | else | |
3270670b | 1486 | jobid = attr->values[0].integer; |
4a73831b | 1487 | |
3270670b | 1488 | if (response != NULL) |
1489 | ippDelete(response); | |
4a73831b | 1490 | |
501b59e2 | 1491 | /* |
1492 | * Handle multiple file jobs if the create-job operation worked... | |
1493 | */ | |
1494 | ||
1495 | if (jobid > 0 && num_files > 1) | |
1496 | for (i = 0; i < num_files; i ++) | |
1497 | { | |
1498 | /* | |
1499 | * Build a standard CUPS URI for the job and fill the standard IPP | |
1500 | * attributes... | |
1501 | */ | |
1502 | ||
c7c24dd7 | 1503 | if ((request = ippNew()) == NULL) |
1504 | return (0); | |
1505 | ||
0a3ac972 | 1506 | request->request.op.operation_id = IPP_SEND_DOCUMENT; |
1507 | request->request.op.request_id = 1; | |
501b59e2 | 1508 | |
04de52f8 | 1509 | snprintf(uri, sizeof(uri), "ipp://%s:%d/jobs/%d", hostname, ippPort(), |
501b59e2 | 1510 | jobid); |
1511 | ||
1512 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
1513 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
1514 | ||
1515 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
1516 | "attributes-natural-language", NULL, | |
1517 | language != NULL ? language->language : "C"); | |
1518 | ||
1519 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", | |
1520 | NULL, uri); | |
1521 | ||
1522 | /* | |
1523 | * Handle raw print files... | |
1524 | */ | |
1525 | ||
1526 | if (cupsGetOption("raw", num_options, options)) | |
1527 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", | |
1528 | NULL, "application/vnd.cups-raw"); | |
1529 | else if ((val = cupsGetOption("document-format", num_options, options)) != NULL) | |
1530 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", | |
1531 | NULL, val); | |
1532 | else | |
1533 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", | |
1534 | NULL, "application/octet-stream"); | |
1535 | ||
1536 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", | |
1537 | NULL, cupsUser()); | |
1538 | ||
1539 | /* | |
1540 | * Is this the last document? | |
1541 | */ | |
1542 | ||
1543 | if (i == (num_files - 1)) | |
1544 | ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); | |
1545 | ||
1546 | /* | |
1547 | * Send the file... | |
1548 | */ | |
1549 | ||
04de52f8 | 1550 | snprintf(uri, sizeof(uri), "/printers/%s", printer); |
501b59e2 | 1551 | |
1552 | if ((response = cupsDoFileRequest(cups_server, request, uri, | |
1553 | files[i])) != NULL) | |
1554 | ippDelete(response); | |
1555 | } | |
1556 | ||
4a73831b | 1557 | return (jobid); |
3b960317 | 1558 | } |
1559 | ||
1560 | ||
1561 | /* | |
d23a857a | 1562 | * 'cups_connect()' - Connect to the specified host... |
1563 | */ | |
1564 | ||
063e1ac7 | 1565 | static char * /* I - Printer name or NULL */ |
1566 | cups_connect(const char *name, /* I - Destination (printer[@host]) */ | |
970017a4 | 1567 | char *printer, /* O - Printer name [HTTP_MAX_URI] */ |
1568 | char *hostname) /* O - Hostname [HTTP_MAX_URI] */ | |
d23a857a | 1569 | { |
1b5bf964 | 1570 | char hostbuf[HTTP_MAX_URI]; /* Name of host */ |
d23a857a | 1571 | static char printerbuf[HTTP_MAX_URI]; |
1b5bf964 | 1572 | /* Name of printer or class */ |
d23a857a | 1573 | |
1574 | ||
b5cb0608 | 1575 | DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name, printer, hostname)); |
1576 | ||
d23a857a | 1577 | if (name == NULL) |
8b06ca19 | 1578 | { |
1579 | last_error = IPP_BAD_REQUEST; | |
d23a857a | 1580 | return (NULL); |
8b06ca19 | 1581 | } |
d23a857a | 1582 | |
04d61d56 | 1583 | if (sscanf(name, "%1023[^@]@%1023s", printerbuf, hostbuf) == 1) |
def978d5 | 1584 | strlcpy(hostbuf, cupsServer(), sizeof(hostbuf)); |
d23a857a | 1585 | |
1586 | if (hostname != NULL) | |
def978d5 | 1587 | strlcpy(hostname, hostbuf, HTTP_MAX_URI); |
d23a857a | 1588 | else |
1589 | hostname = hostbuf; | |
1590 | ||
1591 | if (printer != NULL) | |
def978d5 | 1592 | strlcpy(printer, printerbuf, HTTP_MAX_URI); |
d23a857a | 1593 | else |
1594 | printer = printerbuf; | |
1595 | ||
1596 | if (cups_server != NULL) | |
1597 | { | |
1598 | if (strcasecmp(cups_server->hostname, hostname) == 0) | |
1599 | return (printer); | |
1600 | ||
1601 | httpClose(cups_server); | |
1602 | } | |
1603 | ||
b5cb0608 | 1604 | DEBUG_printf(("connecting to %s on port %d...\n", hostname, ippPort())); |
1605 | ||
1606 | if ((cups_server = httpConnectEncrypt(hostname, ippPort(), | |
1607 | cupsEncryption())) == NULL) | |
8b06ca19 | 1608 | { |
1609 | last_error = IPP_SERVICE_UNAVAILABLE; | |
d23a857a | 1610 | return (NULL); |
8b06ca19 | 1611 | } |
d23a857a | 1612 | else |
1613 | return (printer); | |
1614 | } | |
1615 | ||
1616 | ||
1617 | /* | |
d2122fde | 1618 | * 'cups_local_auth()' - Get the local authorization certificate if |
1619 | * available/applicable... | |
1620 | */ | |
1621 | ||
1622 | static int /* O - 1 if available, 0 if not */ | |
1623 | cups_local_auth(http_t *http) /* I - Connection */ | |
1624 | { | |
1625 | #if defined(WIN32) || defined(__EMX__) | |
1626 | /* | |
1627 | * Currently WIN32 and OS-2 do not support the CUPS server... | |
1628 | */ | |
1629 | ||
1630 | return (0); | |
1631 | #else | |
a6988fb1 | 1632 | int pid; /* Current process ID */ |
1633 | FILE *fp; /* Certificate file */ | |
1634 | char filename[1024], /* Certificate filename */ | |
1635 | certificate[33];/* Certificate string */ | |
1636 | const char *root; /* Server root directory */ | |
d2122fde | 1637 | |
1638 | ||
1639 | /* | |
1640 | * See if we are accessing localhost... | |
1641 | */ | |
1642 | ||
99de6da0 | 1643 | if (strcasecmp(http->hostname, "localhost") != 0) |
1644 | return (0); | |
1645 | ||
1646 | if (!httpAddrLocalhost(&(http->hostaddr))) | |
d2122fde | 1647 | return (0); |
1648 | ||
1649 | /* | |
1650 | * Try opening a certificate file for this PID. If that fails, | |
1651 | * try the root certificate... | |
1652 | */ | |
1653 | ||
a6988fb1 | 1654 | if ((root = getenv("CUPS_SERVERROOT")) == NULL) |
1655 | root = CUPS_SERVERROOT; | |
1656 | ||
d2122fde | 1657 | pid = getpid(); |
a6988fb1 | 1658 | snprintf(filename, sizeof(filename), "%s/certs/%d", root, pid); |
d2122fde | 1659 | if ((fp = fopen(filename, "r")) == NULL && pid > 0) |
a6988fb1 | 1660 | { |
1661 | snprintf(filename, sizeof(filename), "%s/certs/0", root); | |
1662 | fp = fopen(filename, "r"); | |
1663 | } | |
d2122fde | 1664 | |
1665 | if (fp == NULL) | |
1666 | return (0); | |
1667 | ||
1668 | /* | |
1669 | * Read the certificate from the file... | |
1670 | */ | |
1671 | ||
1672 | fgets(certificate, sizeof(certificate), fp); | |
1673 | fclose(fp); | |
1674 | ||
1675 | /* | |
1676 | * Set the authorization string and return... | |
1677 | */ | |
1678 | ||
a6988fb1 | 1679 | snprintf(authstring, sizeof(authstring), "Local %s", certificate); |
d2122fde | 1680 | |
1681 | return (1); | |
1682 | #endif /* WIN32 || __EMX__ */ | |
1683 | } | |
1684 | ||
1685 | ||
1686 | /* | |
fba7409c | 1687 | * End of "$Id: util.c,v 1.81.2.13 2002/05/27 14:47:13 mike Exp $". |
3b960317 | 1688 | */ |