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