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