]> 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/*
b423cd4c 2 * "$Id: util.c 5165 2006-02-24 21:20:30Z 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 */
803 http_t *http2; /* Alternate HTTP connection */
ef416fc2 804 int fd; /* PPD file */
fa73b229 805 char localhost[HTTP_MAX_URI],/* Local hostname */
ef416fc2 806 hostname[HTTP_MAX_URI], /* Hostname */
807 resource[HTTP_MAX_URI]; /* Resource name */
808 int port; /* Port number */
809 http_status_t status; /* HTTP status from server */
810 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
ef416fc2 811
812
813 /*
814 * Range check input...
815 */
816
817 DEBUG_printf(("cupsGetPPD2(http=%p, name=\"%s\")\n", http,
818 name ? name : "(null)"));
819
820 if (!http || !name)
821 {
b423cd4c 822 if (!http)
823 _cupsSetError(IPP_INTERNAL_ERROR, "No HTTP connection!");
824 else
825 _cupsSetError(IPP_INTERNAL_ERROR, "No printer name!");
ef416fc2 826
827 return (NULL);
828 }
829
830 /*
fa73b229 831 * Try finding a printer URI for this printer...
ef416fc2 832 */
833
fa73b229 834 if (!cups_get_printer_uri(http, name, hostname, sizeof(hostname), &port,
835 resource, sizeof(resource), 0))
ef416fc2 836 return (NULL);
ef416fc2 837
838 /*
fa73b229 839 * Remap local hostname to localhost...
840 */
841
842 httpGetHostname(localhost, sizeof(localhost));
843
844 if (!strcasecmp(localhost, hostname))
845 strcpy(hostname, "localhost");
846
847 /*
848 * Get the port number we are connected to...
ef416fc2 849 */
850
851#ifdef AF_INET6
852 if (http->hostaddr->addr.sa_family == AF_INET6)
853 http_port = ntohs(http->hostaddr->ipv6.sin6_port);
854 else
855#endif /* AF_INET6 */
856 if (http->hostaddr->addr.sa_family == AF_INET)
857 http_port = ntohs(http->hostaddr->ipv4.sin_port);
858 else
859 http_port = ippPort();
860
ef416fc2 861 /*
862 * Reconnect to the correct server as needed...
863 */
864
865 if (!strcasecmp(http->hostname, hostname) && port == http_port)
866 http2 = http;
867 else if ((http2 = httpConnectEncrypt(hostname, port,
868 cupsEncryption())) == NULL)
869 {
870 DEBUG_puts("Unable to connect to server!");
871
872 return (NULL);
873 }
874
875 /*
876 * Get a temp file...
877 */
878
879 if ((fd = cupsTempFd(cg->ppd_filename, sizeof(cg->ppd_filename))) < 0)
880 {
881 /*
882 * Can't open file; close the server connection and return NULL...
883 */
884
ecdc0628 885 _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
ef416fc2 886
887 if (http2 != http)
888 httpClose(http2);
889
890 return (NULL);
891 }
892
893 /*
894 * And send a request to the HTTP server...
895 */
896
fa73b229 897 strlcat(resource, ".ppd", sizeof(resource));
ef416fc2 898
899 status = cupsGetFd(http2, resource, fd);
900
901 close(fd);
902
903 if (http2 != http)
904 httpClose(http2);
905
906 /*
907 * See if we actually got the file or an error...
908 */
909
910 if (status != HTTP_OK)
911 {
912 switch (status)
913 {
914 case HTTP_NOT_FOUND :
ecdc0628 915 _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
ef416fc2 916 break;
917
918 case HTTP_UNAUTHORIZED :
ecdc0628 919 _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
ef416fc2 920 break;
921
922 default :
923 DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
924 status));
ecdc0628 925 _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
ef416fc2 926 break;
927 }
928
929 unlink(cg->ppd_filename);
930
931 return (NULL);
932 }
933
934 /*
935 * Return the PPD file...
936 */
937
938 return (cg->ppd_filename);
939}
940
941
942/*
943 * 'cupsGetPrinters()' - Get a list of printers from the default server.
944 *
945 * This function is deprecated - use cupsGetDests() instead.
946 *
947 * @deprecated@
948 */
949
950int /* O - Number of printers */
951cupsGetPrinters(char ***printers) /* O - Printers */
952{
953 int n; /* Number of printers */
954 ipp_t *request, /* IPP Request */
955 *response; /* IPP Response */
956 ipp_attribute_t *attr; /* Current attribute */
957 cups_lang_t *language; /* Default language */
958 char **temp; /* Temporary pointer */
959 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
960
961
962 if (printers == NULL)
963 {
ecdc0628 964 _cupsSetError(IPP_INTERNAL_ERROR, NULL);
ef416fc2 965
966 return (0);
967 }
968
969 /*
970 * Try to connect to the server...
971 */
972
973 if (!cups_connect("default", NULL, NULL))
974 {
975 DEBUG_puts("Unable to connect to server!");
976
977 return (0);
978 }
979
980 /*
981 * Build a CUPS_GET_PRINTERS request, which requires the following
982 * attributes:
983 *
984 * attributes-charset
985 * attributes-natural-language
986 * requested-attributes
987 */
988
989 request = ippNew();
990
991 request->request.op.operation_id = CUPS_GET_PRINTERS;
992 request->request.op.request_id = 1;
993
994 language = cupsLangDefault();
995
996 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
997 "attributes-charset", NULL, cupsLangEncoding(language));
998
999 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1000 "attributes-natural-language", NULL, language->language);
1001
1002 cupsLangFree(language);
1003
1004 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1005 "requested-attributes", NULL, "printer-name");
1006
1007 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1008 "printer-type", 0);
1009
1010 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM,
1011 "printer-type-mask", CUPS_PRINTER_CLASS);
1012
1013 /*
1014 * Do the request and get back a response...
1015 */
1016
1017 n = 0;
1018 *printers = NULL;
1019
1020 if ((response = cupsDoRequest(cg->http, request, "/")) != NULL)
1021 {
1022 for (attr = response->attrs; attr != NULL; attr = attr->next)
1023 if (attr->name != NULL &&
1024 strcasecmp(attr->name, "printer-name") == 0 &&
1025 attr->value_tag == IPP_TAG_NAME)
1026 {
1027 if (n == 0)
1028 temp = malloc(sizeof(char *));
1029 else
1030 temp = realloc(*printers, sizeof(char *) * (n + 1));
1031
1032 if (temp == NULL)
1033 {
1034 /*
1035 * Ran out of memory!
1036 */
1037
1038 while (n > 0)
1039 {
1040 n --;
1041 free((*printers)[n]);
1042 }
1043
1044 free(*printers);
1045 ippDelete(response);
1046 return (0);
1047 }
1048
1049 *printers = temp;
1050 temp[n] = strdup(attr->values[0].string.text);
1051 n ++;
1052 }
1053
1054 ippDelete(response);
1055 }
1056
1057 return (n);
1058}
1059
1060
1061/*
1062 * 'cupsLastError()' - Return the last IPP status code.
1063 */
1064
1065ipp_status_t /* O - IPP status code from last request */
1066cupsLastError(void)
1067{
1068 return (_cupsGlobals()->last_error);
1069}
1070
1071
1072/*
1073 * 'cupsLastErrorString()' - Return the last IPP status-message.
1074 *
1075 * @since CUPS 1.2@
1076 */
1077
1078const char * /* O - status-message text from last request */
1079cupsLastErrorString(void)
1080{
1081 return (_cupsGlobals()->last_status_message);
1082}
1083
1084
1085/*
1086 * 'cupsPrintFile()' - Print a file to a printer or class on the default server.
1087 */
1088
1089int /* O - Job ID */
1090cupsPrintFile(const char *name, /* I - Printer or class name */
1091 const char *filename, /* I - File to print */
1092 const char *title, /* I - Title of job */
1093 int num_options,/* I - Number of options */
1094 cups_option_t *options) /* I - Options */
1095{
1096 DEBUG_printf(("cupsPrintFile(name=\"%s\", filename=\"%s\", "
1097 "title=\"%s\", num_options=%d, options=%p)\n",
1098 name, filename, title, num_options, options));
1099
1100 return (cupsPrintFiles(name, 1, &filename, title, num_options, options));
1101}
1102
1103
1104/*
1105 * 'cupsPrintFile2()' - Print a file to a printer or class on the specified server.
1106 *
1107 * @since CUPS 1.1.21@
1108 */
1109
1110int /* O - Job ID */
1111cupsPrintFile2(http_t *http, /* I - HTTP connection */
1112 const char *name, /* I - Printer or class name */
1113 const char *filename, /* I - File to print */
1114 const char *title, /* I - Title of job */
1115 int num_options,
1116 /* I - Number of options */
1117 cups_option_t *options) /* I - Options */
1118{
1119 DEBUG_printf(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\", "
1120 "title=\"%s\", num_options=%d, options=%p)\n",
1121 http, name, filename, title, num_options, options));
1122
1123 return (cupsPrintFiles2(http, name, 1, &filename, title, num_options, options));
1124}
1125
1126
1127/*
fa73b229 1128 * 'cupsPrintFiles()' - Print one or more files to a printer or class on the
1129 * default server.
ef416fc2 1130 */
1131
1132int /* O - Job ID */
1133cupsPrintFiles(const char *name, /* I - Printer or class name */
1134 int num_files, /* I - Number of files */
1135 const char **files, /* I - File(s) to print */
1136 const char *title, /* I - Title of job */
1137 int num_options,
1138 /* I - Number of options */
1139 cups_option_t *options) /* I - Options */
1140{
1141 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
1142
1143 DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, "
1144 "files=%p, title=\"%s\", num_options=%d, options=%p)\n",
1145 name, num_files, files, title, num_options, options));
1146
1147
1148 /*
1149 * Setup a connection and request data...
1150 */
1151
1152 if (!cups_connect(name, NULL, NULL))
1153 {
1154 DEBUG_printf(("cupsPrintFiles: Unable to open connection - %s.\n",
1155 strerror(errno)));
1156 DEBUG_puts("Unable to connect to server!");
1157
1158 return (0);
1159 }
1160
1161 /*
1162 * Print the file(s)...
1163 */
1164
1165 return (cupsPrintFiles2(cg->http, name, num_files, files, title,
1166 num_options, options));
1167}
1168
1169
1170
1171/*
fa73b229 1172 * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the
1173 * specified server.
ef416fc2 1174 *
1175 * @since CUPS 1.1.21@
1176 */
1177
1178int /* O - Job ID */
1179cupsPrintFiles2(http_t *http, /* I - HTTP connection */
1180 const char *name, /* I - Printer or class name */
1181 int num_files,/* I - Number of files */
1182 const char **files, /* I - File(s) to print */
1183 const char *title, /* I - Title of job */
1184 int num_options,
1185 /* I - Number of options */
1186 cups_option_t *options) /* I - Options */
1187{
1188 int i; /* Looping var */
1189 const char *val; /* Pointer to option value */
1190 ipp_t *request; /* IPP request */
1191 ipp_t *response; /* IPP response */
1192 ipp_attribute_t *attr; /* IPP job-id attribute */
1193 char uri[HTTP_MAX_URI]; /* Printer URI */
1194 cups_lang_t *language; /* Language to use */
1195 int jobid; /* New job ID */
bd7854cb 1196 const char *base; /* Basename of current filename */
ef416fc2 1197
1198
1199 DEBUG_printf(("cupsPrintFiles(http=%p, name=\"%s\", num_files=%d, "
1200 "files=%p, title=\"%s\", num_options=%d, options=%p)\n",
1201 http, name, num_files, files, title, num_options, options));
1202
1203 /*
1204 * Range check input...
1205 */
1206
1207 if (!http || !name || num_files < 1 || files == NULL)
1208 {
ecdc0628 1209 _cupsSetError(IPP_INTERNAL_ERROR, NULL);
ef416fc2 1210
1211 return (0);
1212 }
1213
1214 /*
1215 * Setup the printer URI...
1216 */
1217
a4d04587 1218 if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1219 "localhost", 0, "/printers/%s", name) != HTTP_URI_OK)
ef416fc2 1220 {
ecdc0628 1221 _cupsSetError(IPP_INTERNAL_ERROR, NULL);
ef416fc2 1222
1223 return (0);
1224 }
1225
1226 /*
1227 * Setup the request data...
1228 */
1229
1230 language = cupsLangDefault();
1231
1232 /*
1233 * Build a standard CUPS URI for the printer and fill the standard IPP
1234 * attributes...
1235 */
1236
1237 if ((request = ippNew()) == NULL)
1238 {
ecdc0628 1239 _cupsSetError(IPP_INTERNAL_ERROR, NULL);
ef416fc2 1240
1241 return (0);
1242 }
1243
1244 request->request.op.operation_id = num_files == 1 ? IPP_PRINT_JOB :
1245 IPP_CREATE_JOB;
1246 request->request.op.request_id = 1;
1247
1248 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1249 "attributes-charset", NULL, cupsLangEncoding(language));
1250
1251 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1252 "attributes-natural-language", NULL,
1253 language != NULL ? language->language : "C");
1254
1255 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1256 NULL, uri);
1257
1258 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1259 NULL, cupsUser());
1260
1261 if (title)
1262 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
1263 title);
1264
1265 /*
1266 * Then add all options...
1267 */
1268
1269 cupsEncodeOptions(request, num_options, options);
1270
1271 /*
1272 * Do the request...
1273 */
1274
1275 snprintf(uri, sizeof(uri), "/printers/%s", name);
1276
1277 if (num_files == 1)
1278 response = cupsDoFileRequest(http, request, uri, *files);
1279 else
1280 response = cupsDoRequest(http, request, uri);
1281
1282 if (response == NULL)
1283 jobid = 0;
1284 else if (response->request.status.status_code > IPP_OK_CONFLICT)
1285 {
1286 DEBUG_printf(("IPP response code was 0x%x!\n",
1287 response->request.status.status_code));
1288 jobid = 0;
1289 }
1290 else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL)
1291 {
1292 DEBUG_puts("No job ID!");
1293
ecdc0628 1294 _cupsSetError(IPP_INTERNAL_ERROR, NULL);
ef416fc2 1295
1296 jobid = 0;
1297 }
1298 else
1299 jobid = attr->values[0].integer;
1300
1301 if (response != NULL)
1302 ippDelete(response);
1303
1304 /*
1305 * Handle multiple file jobs if the create-job operation worked...
1306 */
1307
1308 if (jobid > 0 && num_files > 1)
1309 for (i = 0; i < num_files; i ++)
1310 {
1311 /*
1312 * Build a standard CUPS URI for the job and fill the standard IPP
1313 * attributes...
1314 */
1315
1316 if ((request = ippNew()) == NULL)
1317 return (0);
1318
1319 request->request.op.operation_id = IPP_SEND_DOCUMENT;
1320 request->request.op.request_id = 1;
1321
1322 snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", jobid);
1323
1324 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1325 "attributes-charset", NULL, cupsLangEncoding(language));
1326
1327 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1328 "attributes-natural-language", NULL,
1329 language != NULL ? language->language : "C");
1330
1331 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
1332 NULL, uri);
1333
1334 /*
1335 * Handle raw print files...
1336 */
1337
1338 if (cupsGetOption("raw", num_options, options))
fa73b229 1339 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1340 "document-format", NULL, "application/vnd.cups-raw");
1341 else if ((val = cupsGetOption("document-format", num_options,
1342 options)) != NULL)
1343 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1344 "document-format", NULL, val);
ef416fc2 1345 else
fa73b229 1346 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1347 "document-format", NULL, "application/octet-stream");
ef416fc2 1348
fa73b229 1349 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1350 "requesting-user-name", NULL, cupsUser());
ef416fc2 1351
bd7854cb 1352 /*
1353 * Add the original document filename...
1354 */
1355
1356 if ((base = strrchr(files[i], '/')) != NULL)
1357 base ++;
1358 else
1359 base = files[i];
1360
1361 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "document-name",
1362 NULL, base);
1363
ef416fc2 1364 /*
1365 * Is this the last document?
1366 */
1367
1368 if (i == (num_files - 1))
1369 ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
1370
1371 /*
1372 * Send the file...
1373 */
1374
1375 snprintf(uri, sizeof(uri), "/printers/%s", name);
1376
1377 if ((response = cupsDoFileRequest(http, request, uri,
1378 files[i])) != NULL)
1379 ippDelete(response);
1380 }
1381
1382 cupsLangFree(language);
1383
1384 return (jobid);
1385}
1386
1387
1388/*
1389 * 'cups_connect()' - Connect to the specified host...
1390 */
1391
1392static char * /* I - Printer name or NULL */
1393cups_connect(const char *name, /* I - Destination (printer[@host]) */
1394 char *printer, /* O - Printer name [HTTP_MAX_URI] */
1395 char *hostname) /* O - Hostname [HTTP_MAX_URI] */
1396{
1397 char hostbuf[HTTP_MAX_URI]; /* Name of host */
fa73b229 1398 _cups_globals_t *cg = _cupsGlobals();/* Pointer to library globals */
ef416fc2 1399
1400
1401 DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name, printer, hostname));
1402
1403 if (name == NULL)
1404 {
ecdc0628 1405 _cupsSetError(IPP_BAD_REQUEST, NULL);
ef416fc2 1406
1407 return (NULL);
1408 }
1409
1410 /*
1411 * All jobs are now queued to cupsServer() to avoid hostname
1412 * resolution problems and to ensure that the user sees all
1413 * locally queued jobs locally.
1414 */
1415
1416 strlcpy(hostbuf, cupsServer(), sizeof(hostbuf));
1417
1418 if (hostname != NULL)
1419 strlcpy(hostname, hostbuf, HTTP_MAX_URI);
1420 else
1421 hostname = hostbuf;
1422
1423 if (printer != NULL)
1424 strlcpy(printer, name, HTTP_MAX_URI);
1425 else
1426 printer = (char *)name;
1427
1428 if (cg->http != NULL)
1429 {
1430 if (!strcasecmp(cg->http->hostname, hostname))
1431 return (printer);
1432
1433 httpClose(cg->http);
1434 }
1435
1436 DEBUG_printf(("connecting to %s on port %d...\n", hostname, ippPort()));
1437
1438 if ((cg->http = httpConnectEncrypt(hostname, ippPort(),
fa73b229 1439 cupsEncryption())) == NULL)
ef416fc2 1440 {
1441 DEBUG_puts("Unable to connect to server!");
1442
ecdc0628 1443 _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno));
ef416fc2 1444
1445 return (NULL);
1446 }
1447 else
1448 return (printer);
1449}
1450
1451
fa73b229 1452/*
1453 * 'cups_get_printer_uri()' - Get the printer-uri-supported attribute for the first printer in a class.
1454 */
1455
1456static int /* O - 1 on success, 0 on failure */
1457cups_get_printer_uri(
1458 http_t *http, /* I - HTTP connection */
1459 const char *name, /* I - Name of printer or class */
1460 char *host, /* I - Hostname buffer */
1461 int hostsize, /* I - Size of hostname buffer */
1462 int *port, /* O - Port number */
1463 char *resource, /* I - Resource buffer */
1464 int resourcesize, /* I - Size of resource buffer */
1465 int depth) /* I - Depth of query */
1466{
1467 int i; /* Looping var */
1468 int http_port; /* Port number */
1469 http_t *http2; /* Alternate HTTP connection */
1470 ipp_t *request, /* IPP request */
1471 *response; /* IPP response */
1472 ipp_attribute_t *attr; /* Current attribute */
1473 char uri[HTTP_MAX_URI], /* printer-uri attribute */
1474 scheme[HTTP_MAX_URI], /* Scheme name */
1475 username[HTTP_MAX_URI], /* Username:password */
1476 classname[255]; /* Temporary class name */
1477 static const char * const requested_attrs[] =
1478 { /* Requested attributes */
1479 "printer-uri-supported",
1480 "printer-type",
1481 "member-uris"
1482 };
1483
1484
1485 DEBUG_printf(("cups_get_printer_uri(http=%p, name=\"%s\", host=%p, "
1486 "hostsize=%d, resource=%p, resourcesize=%d, depth=%d)\n",
1487 http, name ? name : "(null)", host, hostsize,
1488 resource, resourcesize, depth));
1489
1490 /*
1491 * Setup the printer URI...
1492 */
1493
a4d04587 1494 if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
1495 "localhost", 0, "/printers/%s", name) != HTTP_URI_OK)
fa73b229 1496 {
b423cd4c 1497 _cupsSetError(IPP_INTERNAL_ERROR, "Unable to create printer-uri!");
fa73b229 1498
1499 *host = '\0';
1500 *resource = '\0';
1501
1502 return (0);
1503 }
1504
1505 DEBUG_printf(("cups_get_printer_uri: printer-uri=\"%s\"\n", uri));
1506
1507 /*
1508 * Get the port number we are connected to...
1509 */
1510
1511#ifdef AF_INET6
1512 if (http->hostaddr->addr.sa_family == AF_INET6)
1513 http_port = ntohs(http->hostaddr->ipv6.sin6_port);
1514 else
1515#endif /* AF_INET6 */
1516 if (http->hostaddr->addr.sa_family == AF_INET)
1517 http_port = ntohs(http->hostaddr->ipv4.sin_port);
1518 else
1519 http_port = ippPort();
1520
1521 /*
1522 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
1523 * attributes:
1524 *
1525 * attributes-charset
1526 * attributes-natural-language
1527 * printer-uri
1528 * requested-attributes
1529 */
1530
1531 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
1532
1533 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1534 NULL, uri);
1535
1536 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1537 "requested-attributes",
1538 sizeof(requested_attrs) / sizeof(requested_attrs[0]),
1539 NULL, requested_attrs);
1540
1541 /*
1542 * Do the request and get back a response...
1543 */
1544
1545 if ((response = cupsDoRequest(http, request, "/")) != NULL)
1546 {
1547 if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL)
1548 {
1549 /*
1550 * Get the first actual printer name in the class...
1551 */
1552
1553 for (i = 0; i < attr->num_values; i ++)
1554 {
a4d04587 1555 httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text,
1556 scheme, sizeof(scheme), username, sizeof(username),
1557 host, hostsize, port, resource, resourcesize);
fa73b229 1558 if (!strncmp(resource, "/printers/", 10))
1559 {
1560 /*
1561 * Found a printer!
1562 */
1563
1564 ippDelete(response);
1565
1566 return (1);
1567 }
1568 }
1569
1570 /*
1571 * No printers in this class - try recursively looking for a printer,
1572 * but not more than 3 levels deep...
1573 */
1574
1575 if (depth < 3)
1576 {
1577 for (i = 0; i < attr->num_values; i ++)
1578 {
a4d04587 1579 httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text,
1580 scheme, sizeof(scheme), username, sizeof(username),
1581 host, hostsize, port, resource, resourcesize);
fa73b229 1582 if (!strncmp(resource, "/classes/", 9))
1583 {
1584 /*
1585 * Found a class! Connect to the right server...
1586 */
1587
1588 if (!strcasecmp(http->hostname, host) && *port == http_port)
1589 http2 = http;
1590 else if ((http2 = httpConnectEncrypt(host, *port,
1591 cupsEncryption())) == NULL)
1592 {
1593 DEBUG_puts("Unable to connect to server!");
1594
1595 continue;
1596 }
1597
1598 /*
1599 * Look up printers on that server...
1600 */
1601
1602 strlcpy(classname, resource + 9, sizeof(classname));
1603
1604 cups_get_printer_uri(http2, classname, host, hostsize, port,
1605 resource, resourcesize, depth + 1);
1606
1607 /*
1608 * Close the connection as needed...
1609 */
1610
1611 if (http2 != http)
1612 httpClose(http2);
1613
1614 if (*host)
1615 return (1);
1616 }
1617 }
1618 }
1619 }
1620 else if ((attr = ippFindAttribute(response, "printer-uri-supported",
1621 IPP_TAG_URI)) != NULL)
1622 {
a4d04587 1623 httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text,
1624 scheme, sizeof(scheme), username, sizeof(username),
1625 host, hostsize, port, resource, resourcesize);
fa73b229 1626 ippDelete(response);
1627
1628 return (1);
1629 }
1630
1631 ippDelete(response);
1632 }
1633
b423cd4c 1634 _cupsSetError(IPP_INTERNAL_ERROR, "No printer-uri found!");
1635
fa73b229 1636 *host = '\0';
1637 *resource = '\0';
1638
1639 return (0);
1640}
1641
1642
ef416fc2 1643/*
b423cd4c 1644 * End of "$Id: util.c 5165 2006-02-24 21:20:30Z mike $".
ef416fc2 1645 */