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