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