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