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