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