1 /***
2 This file is part of cups-filters.
3
4 This file is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12 Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with avahi; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
17 USA.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <cups/cups.h>
27 #include <cups/backend.h>
28 #include <cupsfilters/ipp.h>
29 #include <cupsfilters/ppdgenerator.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <signal.h>
33 #include <sys/wait.h>
34 #include <sys/types.h>
35
36 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
37 #define HAVE_CUPS_1_6 1
38 #endif
39
40 enum resolve_uri_converter_type /**** Resolving DNS-SD based URI ****/
41 {
42 CUPS_BACKEND_URI_CONVERTER = -1,
43 IPPFIND_BASED_CONVERTER_FOR_PRINT_URI = 0,
44 IPPFIND_BASED_CONVERTER_FOR_FAX_URI = 1
45 };
46
47 char get_printer_attributes_log[LOGSIZE];
48
49 static int
convert_to_port(char * a)50 convert_to_port(char *a)
51 {
52 int port = 0;
53 for (int i = 0; i<strlen(a); i++)
54 port = port*10 + (a[i] - '0');
55
56 return (port);
57 }
58
59 void
log_printf(char * log,const char * format,...)60 log_printf(char *log,
61 const char *format, ...)
62 {
63 va_list arglist;
64 va_start(arglist, format);
65 vsnprintf(log + strlen(log),
66 LOGSIZE - strlen(log) - 1,
67 format, arglist);
68 log[LOGSIZE - 1] = '\0';
69 va_end(arglist);
70 }
71
72 char *
resolve_uri(const char * raw_uri)73 resolve_uri(const char *raw_uri)
74 {
75 char *pseudo_argv[2];
76 const char *uri;
77 int fd1, fd2;
78 char *save_device_uri_var;
79
80 /* Eliminate any output to stderr, to get rid of the CUPS-backend-specific
81 output of the cupsBackendDeviceURI() function */
82 fd1 = dup(2);
83 fd2 = open("/dev/null", O_WRONLY);
84 dup2(fd2, 2);
85 close(fd2);
86
87 /* If set, save the DEVICE_URI environment and then unset it, so that
88 if we are running under CUPS (as filter or backend) our raw_uri gets
89 resolved and not whatever URI is set in DEVICE_URI */
90 if ((save_device_uri_var = getenv("DEVICE_URI")) != NULL)
91 {
92 save_device_uri_var = strdup(save_device_uri_var);
93 unsetenv("DEVICE_URI");
94 }
95
96 /* Use the URI resolver of libcups to support DNS-SD-service-name-based
97 URIs. The function returns the corresponding host-name-based URI */
98 pseudo_argv[0] = (char *)raw_uri;
99 pseudo_argv[1] = NULL;
100 uri = cupsBackendDeviceURI(pseudo_argv);
101
102 /* Restore DEVICE_URI envidonment variable if we had unset it */
103 if (save_device_uri_var)
104 {
105 setenv("DEVICE_URI", save_device_uri_var, 1);
106 free(save_device_uri_var);
107 }
108
109 /* Re-activate stderr output */
110 dup2(fd1, 2);
111 close(fd1);
112
113 return (uri ? strdup(uri) : NULL);
114 }
115
116 #ifdef HAVE_CUPS_1_6
117 /* Check how the driverless support is provided */
118 int
check_driverless_support(const char * uri)119 check_driverless_support(const char* uri)
120 {
121 int support_status = DRVLESS_CHECKERR;
122 ipp_t *response = NULL;
123
124 response = get_printer_attributes3(NULL, uri, NULL, 0, NULL, 0, 1,
125 &support_status);
126 if (response != NULL)
127 ippDelete(response);
128
129 return support_status;
130 }
131
132 /* Get attributes of a printer specified only by URI */
133 ipp_t *
get_printer_attributes(const char * raw_uri,const char * const pattrs[],int pattrs_size,const char * const req_attrs[],int req_attrs_size,int debug)134 get_printer_attributes(const char* raw_uri,
135 const char* const pattrs[],
136 int pattrs_size,
137 const char* const req_attrs[],
138 int req_attrs_size,
139 int debug)
140 {
141 return get_printer_attributes2(NULL, raw_uri, pattrs, pattrs_size,
142 req_attrs, req_attrs_size, debug);
143 }
144
145 /* Get attributes of a printer specified by URI and under a given HTTP
146 connection, for example via a domain socket */
147 ipp_t *
get_printer_attributes2(http_t * http_printer,const char * raw_uri,const char * const pattrs[],int pattrs_size,const char * const req_attrs[],int req_attrs_size,int debug)148 get_printer_attributes2(http_t *http_printer,
149 const char* raw_uri,
150 const char* const pattrs[],
151 int pattrs_size,
152 const char* const req_attrs[],
153 int req_attrs_size,
154 int debug)
155 {
156 return get_printer_attributes3(http_printer, raw_uri, pattrs, pattrs_size,
157 req_attrs, req_attrs_size, debug, NULL);
158 }
159
160 /* Get attributes of a printer specified by URI and under a given HTTP
161 connection, for example via a domain socket, and give info about used
162 fallbacks */
163 ipp_t *
get_printer_attributes3(http_t * http_printer,const char * raw_uri,const char * const pattrs[],int pattrs_size,const char * const req_attrs[],int req_attrs_size,int debug,int * driverless_info)164 get_printer_attributes3(http_t *http_printer,
165 const char* raw_uri,
166 const char* const pattrs[],
167 int pattrs_size,
168 const char* const req_attrs[],
169 int req_attrs_size,
170 int debug,
171 int* driverless_info)
172 {
173 return get_printer_attributes5(http_printer, raw_uri, pattrs, pattrs_size,
174 req_attrs, req_attrs_size, debug,
175 driverless_info, CUPS_BACKEND_URI_CONVERTER);
176 }
177
178 /* Get attributes of a printer specified only by URI and given info about fax-support*/
get_printer_attributes4(const char * raw_uri,const char * const pattrs[],int pattrs_size,const char * const req_attrs[],int req_attrs_size,int debug,int is_fax)179 ipp_t *get_printer_attributes4(const char* raw_uri,
180 const char* const pattrs[],
181 int pattrs_size,
182 const char* const req_attrs[],
183 int req_attrs_size,
184 int debug,
185 int is_fax)
186 {
187 if(is_fax)
188 return get_printer_attributes5(NULL, raw_uri, pattrs, pattrs_size,
189 req_attrs, req_attrs_size, debug, NULL,
190 IPPFIND_BASED_CONVERTER_FOR_FAX_URI);
191 else
192 return get_printer_attributes5(NULL, raw_uri, pattrs, pattrs_size,
193 req_attrs, req_attrs_size, debug, NULL,
194 IPPFIND_BASED_CONVERTER_FOR_PRINT_URI);
195 }
196
197 /* Get attributes of a printer specified by URI and under a given HTTP
198 connection, for example via a domain socket, and give info about used
199 fallbacks */
200 ipp_t *
get_printer_attributes5(http_t * http_printer,const char * raw_uri,const char * const pattrs[],int pattrs_size,const char * const req_attrs[],int req_attrs_size,int debug,int * driverless_info,int resolve_uri_type)201 get_printer_attributes5(http_t *http_printer,
202 const char* raw_uri,
203 const char* const pattrs[],
204 int pattrs_size,
205 const char* const req_attrs[],
206 int req_attrs_size,
207 int debug,
208 int* driverless_info,
209 int resolve_uri_type )
210 {
211 char *uri;
212 int have_http, uri_status, host_port, i = 0, total_attrs = 0, fallback,
213 cap = 0;
214 char scheme[10], userpass[1024], host_name[1024], resource[1024];
215 http_encryption_t encryption;
216 ipp_t *request, *response = NULL;
217 ipp_attribute_t *attr;
218 char valuebuffer[65536];
219 const char *kw;
220 ipp_status_t ipp_status;
221 /* Default attributes for get-printer-attributes requests to
222 obtain complete capability lists of a printer */
223 const char * const pattrs_cap_standard[] = {
224 "all",
225 "media-col-database",
226 };
227 const char * const pattrs_cap_fallback[] = {
228 "all",
229 };
230 /* Attributes required in the IPP response of a complete printer
231 capability list */
232 const char * const req_attrs_cap[] = {
233 "attributes-charset",
234 "attributes-natural-language",
235 "charset-configured",
236 "charset-supported",
237 "compression-supported",
238 "document-format-default",
239 "document-format-supported",
240 "generated-natural-language-supported",
241 "ipp-versions-supported",
242 "natural-language-configured",
243 "operations-supported",
244 "printer-is-accepting-jobs",
245 "printer-name",
246 "printer-state",
247 "printer-state-reasons",
248 "printer-up-time",
249 "printer-uri-supported",
250 "uri-authentication-supported",
251 "uri-security-supported"
252 };
253
254 /* Expect a device capable of standard IPP Everywhere */
255 if (driverless_info != NULL)
256 *driverless_info = FULL_DRVLESS;
257
258 /* Request printer properties via IPP, for example to
259 - generate a PPD file for the printer
260 (mainly driverless-capable printers)
261 - generally find capabilities, options, and default settinngs,
262 - printers status: Accepting jobs? Busy? With how many jobs? */
263
264 get_printer_attributes_log[0] = '\0';
265
266 /* Convert DNS-SD-service-name-based URIs to host-name-based URIs */
267 if(resolve_uri_type == CUPS_BACKEND_URI_CONVERTER)
268 uri = resolve_uri(raw_uri);
269 else
270 uri = ippfind_based_uri_converter(raw_uri, resolve_uri_type);
271
272 if (uri == NULL)
273 {
274 log_printf(get_printer_attributes_log,
275 "get-printer-attibutes: Cannot resolve URI: %s\n", raw_uri);
276 return NULL;
277 }
278
279 /* Extract URI componants needed for the IPP request */
280 uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, uri,
281 scheme, sizeof(scheme),
282 userpass, sizeof(userpass),
283 host_name, sizeof(host_name),
284 &(host_port),
285 resource, sizeof(resource));
286 if (uri_status != HTTP_URI_OK) {
287 /* Invalid URI */
288 log_printf(get_printer_attributes_log,
289 "get-printer-attributes: Cannot parse the printer URI: %s\n",
290 uri);
291 if (uri) free(uri);
292 return NULL;
293 }
294
295 if (!strcmp(scheme, "ipps"))
296 encryption = HTTP_ENCRYPTION_ALWAYS;
297 else
298 encryption = HTTP_ENCRYPTION_IF_REQUESTED;
299
300 /* Connect to the server if not already done */
301 if (http_printer == NULL) {
302 have_http = 0;
303 if ((http_printer =
304 httpConnect2 (host_name, host_port, NULL, AF_UNSPEC,
305 encryption, 1, 3000, NULL)) == NULL) {
306 log_printf(get_printer_attributes_log,
307 "get-printer-attributes: Cannot connect to printer with URI %s.\n",
308 uri);
309 if (uri) free(uri);
310 return NULL;
311 }
312 } else
313 have_http = 1;
314
315 /* If we got called without attribute list, use the attributes for polling
316 a complete list of capabilities of the printer.
317 If also no list of required attributes in the response is supplied, use
318 the default list */
319 if (pattrs == NULL || pattrs_size == 0) {
320 cap = 1;
321 pattrs = pattrs_cap_standard;
322 pattrs_size = sizeof(pattrs_cap_standard) / sizeof(pattrs_cap_standard[0]);
323 if (req_attrs == NULL || req_attrs_size == 0) {
324 req_attrs = req_attrs_cap;
325 req_attrs_size = sizeof(req_attrs_cap) / sizeof(req_attrs_cap[0]);
326 }
327 }
328
329 /* Loop through all fallbacks until getting a successful result */
330 for (fallback = 0; fallback < 2 + cap; fallback ++) {
331 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
332 if (fallback == 1)
333 /* Fallback 1: Try IPP 1.1 instead of 2.0 */
334 ippSetVersion(request, 1, 1);
335 if (fallback == 2 && cap) {
336 /* Fallback 2: (Only for full capability list) Try only "all",
337 without "media-col-database */
338 pattrs = pattrs_cap_fallback;
339 pattrs_size = sizeof(pattrs_cap_fallback) /
340 sizeof(pattrs_cap_fallback[0]);
341 }
342 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
343 uri);
344 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
345 "requested-attributes", pattrs_size,
346 NULL, pattrs);
347
348 response = cupsDoRequest(http_printer, request, resource);
349 ipp_status = cupsLastError();
350
351 if (response) {
352 log_printf(get_printer_attributes_log,
353 "Requested IPP attributes (get-printer-attributes) for printer with URI %s\n",
354 uri);
355 /* Log all printer attributes for debugging and count them */
356 if (debug)
357 log_printf(get_printer_attributes_log,
358 "Full list of all IPP attributes:\n");
359 attr = ippFirstAttribute(response);
360 while (attr) {
361 total_attrs ++;
362 if (debug) {
363 ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
364 log_printf(get_printer_attributes_log,
365 " Attr: %s\n",ippGetName(attr));
366 log_printf(get_printer_attributes_log,
367 " Value: %s\n", valuebuffer);
368 for (i = 0; i < ippGetCount(attr); i ++) {
369 if ((kw = ippGetString(attr, i, NULL)) != NULL) {
370 log_printf(get_printer_attributes_log, " Keyword: %s\n", kw);
371 }
372 }
373 }
374 attr = ippNextAttribute(response);
375 }
376
377 /* Check whether the IPP response contains the required attributes
378 and is not incomplete */
379 if (req_attrs)
380 for (i = req_attrs_size; i > 0; i --)
381 if (ippFindAttribute(response, req_attrs[i - 1], IPP_TAG_ZERO) ==
382 NULL)
383 break;
384 if (ipp_status == IPP_STATUS_ERROR_BAD_REQUEST ||
385 ipp_status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED ||
386 (req_attrs && i > 0) || (cap && total_attrs < 20)) {
387 log_printf(get_printer_attributes_log,
388 "get-printer-attributes IPP request failed:\n");
389 if (ipp_status == IPP_STATUS_ERROR_BAD_REQUEST)
390 log_printf(get_printer_attributes_log,
391 " - ipp_status == IPP_STATUS_ERROR_BAD_REQUEST\n");
392 else if (ipp_status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
393 log_printf(get_printer_attributes_log,
394 " - ipp_status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED\n");
395 if (req_attrs && i > 0)
396 log_printf(get_printer_attributes_log,
397 " - Required IPP attribute %s not found\n",
398 req_attrs[i - 1]);
399 if (cap && total_attrs < 20)
400 log_printf(get_printer_attributes_log,
401 " - Too few IPP attributes: %d (30 or more expected)\n",
402 total_attrs);
403 ippDelete(response);
404 } else {
405 /* Suitable response, we are done */
406 // if we did not succeed to obtain the "media-col-database" attribute
407 // try to get it separately
408 if (cap &&
409 ippFindAttribute(response, "media-col-database", IPP_TAG_ZERO) ==
410 NULL)
411 {
412 ipp_t *response2 = NULL;
413
414 log_printf(get_printer_attributes_log,
415 "Polling \"media-col-database\" attribute separately.\n");
416 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
417 ippSetVersion(request, 2, 0);
418 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
419 "printer-uri", NULL, uri);
420 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
421 "requested-attributes", NULL, "media-col-database");
422 response2 = cupsDoRequest(http_printer, request, resource);
423 ipp_status = cupsLastError();
424 if (response2)
425 {
426 if ((attr = ippFindAttribute(response2, "media-col-database",
427 IPP_TAG_ZERO)) != NULL)
428 {
429 // Copy "media-col-database" attribute into the original
430 // IPP response
431 log_printf(get_printer_attributes_log,
432 "\"media-col-database\" attribute found.\n");
433 ippCopyAttribute(response, attr, 0);
434 }
435 ippDelete(response2);
436 }
437 }
438 if (have_http == 0) httpClose(http_printer);
439 if (uri) free(uri);
440 return response;
441 }
442 } else {
443 log_printf(get_printer_attributes_log,
444 "Request for IPP attributes (get-printer-attributes) for printer with URI %s failed: %s\n",
445 uri, cupsLastErrorString());
446 log_printf(get_printer_attributes_log, "get-printer-attributes IPP request failed:\n");
447 log_printf(get_printer_attributes_log, " - No response\n");
448 }
449 if (fallback == 1 + cap) {
450 log_printf(get_printer_attributes_log,
451 "No further fallback available, giving up\n");
452 if (driverless_info != NULL)
453 *driverless_info = DRVLESS_CHECKERR;
454 } else if (cap && fallback == 1) {
455 log_printf(get_printer_attributes_log,
456 "The server doesn't support the standard IPP request, trying request without media-col\n");
457 if (driverless_info != NULL)
458 *driverless_info = DRVLESS_INCOMPLETEIPP;
459 } else if (fallback == 0) {
460 log_printf(get_printer_attributes_log,
461 "The server doesn't support IPP2.0 request, trying IPP1.1 request\n");
462 if (driverless_info != NULL)
463 *driverless_info = DRVLESS_IPP11;
464 }
465 }
466
467 if (have_http == 0) httpClose(http_printer);
468 if (uri) free(uri);
469 return NULL;
470 }
471
472 char*
ippfind_based_uri_converter(const char * uri,int is_fax)473 ippfind_based_uri_converter (const char *uri, int is_fax)
474 {
475 int ippfind_pid = 0, /* Process ID of ippfind for IPP */
476 post_proc_pipe[2], /* Pipe to post-processing for IPP */
477 wait_children, /* Number of child processes left */
478 wait_pid, /* Process ID from wait() */
479 wait_status, /* Status from child */
480 exit_status = 0, /* Exit status */
481 bytes,
482 port,
483 i,
484 output_of_fax_uri = 0,
485 is_local;
486 char *ippfind_argv[100], /* Arguments for ippfind */
487 *ptr_to_port = NULL,
488 *reg_type,
489 *resolved_uri = NULL, /* Buffer for resolved URI */
490 *resource_field = NULL,
491 *service_hostname = NULL,
492 /* URI components... */
493 scheme[32],
494 userpass[256],
495 hostname[1024],
496 resource[1024],
497 *buffer = NULL, /* Copy buffer */
498 *ptr; /* Pointer into string */;
499 cups_file_t *fp; /* Post-processing input file */
500 int status; /* Status of GET request */
501
502 status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
503 userpass, sizeof(userpass),
504 hostname, sizeof(hostname), &port, resource,
505 sizeof(resource));
506 if (status < HTTP_URI_OK) {
507 /* Invalid URI */
508 fprintf(stderr, "ERROR: Could not parse URI: %s\n", uri);
509 goto error;
510 }
511
512 /* URI is not DNS-SD-based, so do not resolve */
513 if ((reg_type = strstr(hostname, "._tcp")) == NULL) {
514 return strdup(uri);
515 }
516
517 resolved_uri = (char *)malloc(MAX_URI_LEN * (sizeof(char)));
518 if (resolved_uri == NULL) {
519 fprintf(stderr, "resolved_uri malloc: Out of memory\n");
520 goto error;
521 }
522 memset(resolved_uri, 0, MAX_URI_LEN);
523
524 reg_type --;
525 while (reg_type >= hostname && *reg_type != '.')
526 reg_type --;
527 if (reg_type < hostname) {
528 fprintf(stderr, "ERROR: Invalid DNS-SD service name: %s\n", hostname);
529 goto error;
530 }
531 *reg_type++ = '\0';
532
533 i = 0;
534 ippfind_argv[i++] = "ippfind";
535 ippfind_argv[i++] = reg_type; /* list IPP(S) entries */
536 ippfind_argv[i++] = "-T"; /* DNS-SD poll timeout */
537 ippfind_argv[i++] = "0"; /* Minimum time required */
538 if (is_fax) {
539 ippfind_argv[i++] = "--txt";
540 ippfind_argv[i++] = "rfo";
541 }
542 ippfind_argv[i++] = "-N";
543 ippfind_argv[i++] = hostname;
544 ippfind_argv[i++] = "-x";
545 ippfind_argv[i++] = "echo"; /* Output the needed data fields */
546 ippfind_argv[i++] = "-en"; /* separated by tab characters */
547 if(is_fax)
548 ippfind_argv[i++] = "\n{service_hostname}\t{txt_rfo}\t{service_port}\t";
549 else
550 ippfind_argv[i++] = "\n{service_hostname}\t{txt_rp}\t{service_port}\t";
551 ippfind_argv[i++] = ";";
552 ippfind_argv[i++] = "--local"; /* Rest only if local service */
553 ippfind_argv[i++] = "-x";
554 ippfind_argv[i++] = "echo"; /* Output an 'L' at the end of the */
555 ippfind_argv[i++] = "-en"; /* line */
556 ippfind_argv[i++] = "L";
557 ippfind_argv[i++] = ";";
558 ippfind_argv[i++] = NULL;
559
560 /*
561 * Create a pipe for passing the ippfind output to post-processing
562 */
563
564 if (pipe(post_proc_pipe)) {
565 perror("ERROR: Unable to create pipe to post-processing");
566 goto error;
567 }
568
569 if ((ippfind_pid = fork()) == 0) {
570 /*
571 * Child comes here...
572 */
573
574 dup2(post_proc_pipe[1], 1);
575 close(post_proc_pipe[0]);
576 close(post_proc_pipe[1]);
577
578 execvp(CUPS_IPPFIND, ippfind_argv);
579 perror("ERROR: Unable to execute ippfind utility");
580
581 exit(1);
582 }
583 else if (ippfind_pid < 0) {
584 /*
585 * Unable to fork!
586 */
587
588 perror("ERROR: Unable to execute ippfind utility");
589 goto error;
590 }
591
592 close(post_proc_pipe[1]);
593
594 fp = cupsFileOpenFd(post_proc_pipe[0], "r");
595
596 buffer = (char*)malloc(MAX_OUTPUT_LEN * sizeof(char));
597 if (buffer == NULL) {
598 fprintf(stderr, "buffer malloc: Out of memory.\n");
599 goto error;
600 }
601 memset(buffer, 0, MAX_OUTPUT_LEN);
602
603 while ((bytes = cupsFileGetLine(fp, buffer, MAX_OUTPUT_LEN)) > 0) {
604 /* Mark all the fields of the output of ippfind */
605 ptr = buffer;
606
607 /* ignore new lines */
608 if (bytes < 3)
609 goto read_error;
610
611 /* First, build the DNS-SD-service-name-based URI ... */
612 while (ptr && !isalnum(*ptr & 255)) ptr ++;
613
614 service_hostname = ptr;
615 ptr = memchr(ptr, '\t', MAX_OUTPUT_LEN - (ptr - buffer));
616 if (!ptr) goto read_error;
617 *ptr = '\0';
618 ptr ++;
619
620 resource_field = ptr;
621 ptr = memchr(ptr, '\t', MAX_OUTPUT_LEN - (ptr - buffer));
622 if (!ptr) goto read_error;
623 *ptr = '\0';
624 ptr ++;
625
626 ptr_to_port = ptr;
627 ptr = memchr(ptr, '\t', MAX_OUTPUT_LEN - (ptr - buffer));
628 if (!ptr) goto read_error;
629 *ptr = '\0';
630 ptr ++;
631
632 /* Do we have a local service so that we have to set the host name to
633 "localhost"? */
634 is_local = (*ptr == 'L');
635
636 ptr = strchr(reg_type, '.');
637 if (!ptr) goto read_error;
638 *ptr = '\0';
639
640 port = convert_to_port(ptr_to_port);
641
642 httpAssembleURIf(HTTP_URI_CODING_ALL, resolved_uri,
643 2047, reg_type + 1, NULL,
644 (is_local ? "localhost" : service_hostname), port, "/%s",
645 resource_field);
646
647 if (is_fax)
648 output_of_fax_uri = 1; /* fax-uri requested from fax-capable device */
649
650 read_error:
651 memset(buffer, 0, MAX_OUTPUT_LEN);
652 }
653
654 cupsFileClose(fp);
655
656 if (buffer != NULL)
657 free(buffer);
658
659 /*
660 * Wait for the child processes to exit...
661 */
662
663 wait_children = 1;
664
665 while (wait_children > 0) {
666 /*
667 * Wait until we get a valid process ID or the job is canceled...
668 */
669
670 while ((wait_pid = wait(&wait_status)) < 0 && errno == EINTR) {
671 }
672
673 if (wait_pid < 0)
674 break;
675
676 wait_children --;
677
678 /*
679 * Report child status...
680 */
681
682 if (wait_status) {
683 if (WIFEXITED(wait_status)) {
684 exit_status = WEXITSTATUS(wait_status);
685 if (wait_pid == ippfind_pid && exit_status <= 2)
686 exit_status = 0;
687 } else if (WTERMSIG(wait_status) == SIGTERM) {
688 } else {
689 exit_status = WTERMSIG(wait_status);
690 }
691 }
692 }
693 if (is_fax && !output_of_fax_uri) {
694 fprintf(stderr, "fax URI requested from not fax-capable device\n");
695 goto error;
696 }
697
698 return (resolved_uri);
699
700 /*
701 * Exit...
702 */
703
704 error:
705 if (resolved_uri != NULL)
706 free(resolved_uri);
707 return (NULL);
708 }
709
710
711 #endif /* HAVE_CUPS_1_6 */
712