]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/dirsvc.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / dirsvc.c
1 /*
2 * "$Id: dirsvc.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * Directory services routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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 * Contents:
16 *
17 * cupsdDeregisterPrinter() - Stop sending broadcast information for a
18 * local printer and remove any pending
19 * references to remote printers.
20 * cupsdLoadRemoteCache() - Load the remote printer cache.
21 * cupsdRegisterPrinter() - Start sending broadcast information for a
22 * printer update the broadcast contents.
23 * cupsdSaveRemoteCache() - Save the remote printer cache.
24 * cupsdSendBrowseList() - Send new browsing information as necessary.
25 * cupsdStartBrowsing() - Start sending and receiving broadcast
26 * information.
27 * cupsdStartPolling() - Start polling servers as needed.
28 * cupsdStopBrowsing() - Stop sending and receiving broadcast
29 * information.
30 * cupsdStopPolling() - Stop polling servers as needed.
31 * cupsdUpdateDNSSDBrowse() - Handle DNS-SD queries.
32 * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
33 * cupsdUpdateSLPBrowse() - Get browsing information via SLP.
34 * dnssdBuildTxtRecord() - Build a TXT record from printer info.
35 * dnssdDeregisterPrinter() - Stop sending broadcast information for a
36 * printer.
37 * dnssdPackTxtRecord() - Pack an array of key/value pairs into the
38 * TXT record format.
39 * dnssdRegisterCallback() - DNSServiceRegister callback.
40 * dnssdRegisterPrinter() - Start sending broadcast information for a
41 * printer or update the broadcast contents.
42 * dequote() - Remote quotes from a string.
43 * process_browse_data() - Process new browse data.
44 * process_implicit_classes() - Create/update implicit classes as needed.
45 * send_cups_browse() - Send new browsing information using the
46 * CUPS protocol.
47 * send_ldap_browse() - Send LDAP printer registrations.
48 * send_slp_browse() - Register the specified printer with SLP.
49 * slp_attr_callback() - SLP attribute callback
50 * slp_dereg_printer() - SLPDereg() the specified printer
51 * slp_get_attr() - Get an attribute from an SLP registration.
52 * slp_reg_callback() - Empty SLPRegReport.
53 * slp_url_callback() - SLP service url callback
54 * update_cups_browse() - Update the browse lists using the CUPS
55 * protocol.
56 * update_polling() - Read status messages from the poll daemons.
57 */
58
59 /*
60 * Include necessary headers...
61 */
62
63 #include "cupsd.h"
64 #include <grp.h>
65
66 #ifdef HAVE_DNSSD
67 # include <dns_sd.h>
68 # include <nameser.h>
69 # include <nameser.h>
70 # ifdef HAVE_COREFOUNDATION
71 # include <CoreFoundation/CoreFoundation.h>
72 # endif /* HAVE_COREFOUNDATION */
73 # ifdef HAVE_SYSTEMCONFIGURATION
74 # include <SystemConfiguration/SystemConfiguration.h>
75 # endif /* HAVE_SYSTEMCONFIGURATION */
76 #endif /* HAVE_DNSSD */
77
78
79 /*
80 * Local functions...
81 */
82
83 static char *dequote(char *d, const char *s, int dlen);
84 static int is_local_queue(const char *uri, char *host, int hostlen,
85 char *resource, int resourcelen);
86 static void process_browse_data(const char *uri, const char *host,
87 const char *resource, cups_ptype_t type,
88 ipp_pstate_t state, const char *location,
89 const char *info, const char *make_model,
90 int num_attrs, cups_option_t *attrs);
91 static void process_implicit_classes(void);
92 static void send_cups_browse(cupsd_printer_t *p);
93 #ifdef HAVE_LDAP
94 static void send_ldap_browse(cupsd_printer_t *p);
95 #endif /* HAVE_LDAP */
96 #ifdef HAVE_LIBSLP
97 static void send_slp_browse(cupsd_printer_t *p);
98 #endif /* HAVE_LIBSLP */
99 static void update_cups_browse(void);
100 static void update_polling(void);
101
102
103 #ifdef HAVE_OPENLDAP
104 static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
105 {
106 "printerDescription",
107 "printerLocation",
108 "printerMakeAndModel",
109 "printerType",
110 "printerURI",
111 NULL
112 };
113 #endif /* HAVE_OPENLDAP */
114
115 #ifdef HAVE_LIBSLP
116 /*
117 * SLP definitions...
118 */
119
120 /*
121 * SLP service name for CUPS...
122 */
123
124 # define SLP_CUPS_SRVTYPE "service:printer"
125 # define SLP_CUPS_SRVLEN 15
126
127
128 /*
129 * Printer service URL structure
130 */
131
132 typedef struct _slpsrvurl_s /**** SLP URL list ****/
133 {
134 struct _slpsrvurl_s *next; /* Next URL in list */
135 char url[HTTP_MAX_URI];
136 /* URL */
137 } slpsrvurl_t;
138
139
140 /*
141 * Local functions...
142 */
143
144 static SLPBoolean slp_attr_callback(SLPHandle hslp, const char *attrlist,
145 SLPError errcode, void *cookie);
146 static void slp_dereg_printer(cupsd_printer_t *p);
147 static int slp_get_attr(const char *attrlist, const char *tag,
148 char **valbuf);
149 static void slp_reg_callback(SLPHandle hslp, SLPError errcode,
150 void *cookie);
151 static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl,
152 unsigned short lifetime,
153 SLPError errcode, void *cookie);
154 #endif /* HAVE_LIBSLP */
155
156 #ifdef HAVE_DNSSD
157 /*
158 * For IPP register using a subtype of 'cups' so that shared printer browsing
159 * only finds other CUPS servers (not all IPP based printers).
160 */
161 static char dnssdIPPRegType[] = "_ipp._tcp,_cups";
162 static char dnssdIPPFaxRegType[] = "_fax-ipp._tcp";
163
164 static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p);
165 static void dnssdDeregisterPrinter(cupsd_printer_t *p);
166 static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2],
167 int count);
168 static void dnssdRegisterCallback(DNSServiceRef sdRef,
169 DNSServiceFlags flags,
170 DNSServiceErrorType errorCode,
171 const char *name, const char *regtype,
172 const char *domain, void *context);
173 static void dnssdRegisterPrinter(cupsd_printer_t *p);
174 #endif /* HAVE_DNSSD */
175
176
177 /*
178 * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
179 * local printer and remove any pending
180 * references to remote printers.
181 */
182
183 void
184 cupsdDeregisterPrinter(
185 cupsd_printer_t *p, /* I - Printer to register */
186 int removeit) /* I - Printer being permanently removed */
187 {
188 /*
189 * Only deregister if browsing is enabled and it's a local printers...
190 */
191
192 if (!Browsing || !p->shared ||
193 (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
194 return;
195
196 /*
197 * Announce the deletion...
198 */
199
200 if ((BrowseLocalProtocols & BROWSE_CUPS))
201 {
202 cups_ptype_t savedtype = p->type; /* Saved printer type */
203
204 p->type |= CUPS_PRINTER_DELETE;
205
206 send_cups_browse(p);
207
208 p->type = savedtype;
209 }
210
211 #ifdef HAVE_LIBSLP
212 if (BrowseLocalProtocols & BROWSE_SLP)
213 slp_dereg_printer(p);
214 #endif /* HAVE_LIBSLP */
215
216 #ifdef HAVE_DNSSD
217 if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD))
218 dnssdDeregisterPrinter(p);
219 #endif /* HAVE_DNSSD */
220 }
221
222
223 /*
224 * 'cupsdLoadRemoteCache()' - Load the remote printer cache.
225 */
226
227 void
228 cupsdLoadRemoteCache(void)
229 {
230 cups_file_t *fp; /* remote.cache file */
231 int linenum; /* Current line number */
232 char line[1024], /* Line from file */
233 *value, /* Pointer to value */
234 *valueptr, /* Pointer into value */
235 scheme[32], /* Scheme portion of URI */
236 username[64], /* Username portion of URI */
237 host[HTTP_MAX_HOST],
238 /* Hostname portion of URI */
239 resource[HTTP_MAX_URI];
240 /* Resource portion of URI */
241 int port; /* Port number */
242 cupsd_printer_t *p; /* Current printer */
243 time_t now; /* Current time */
244
245
246 /*
247 * Don't load the cache if the CUPS remote protocol is disabled...
248 */
249
250 if (!Browsing || !(BrowseRemoteProtocols & BROWSE_CUPS))
251 {
252 cupsdLogMessage(CUPSD_LOG_DEBUG,
253 "cupsdLoadRemoteCache: Not loading remote cache.");
254 return;
255 }
256
257 /*
258 * Open the remote.cache file...
259 */
260
261 snprintf(line, sizeof(line), "%s/remote.cache", CacheDir);
262 if ((fp = cupsFileOpen(line, "r")) == NULL)
263 return;
264
265 /*
266 * Read printer configurations until we hit EOF...
267 */
268
269 linenum = 0;
270 p = NULL;
271 now = time(NULL);
272
273 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
274 {
275 /*
276 * Decode the directive...
277 */
278
279 if (!strcasecmp(line, "<Printer") ||
280 !strcasecmp(line, "<DefaultPrinter"))
281 {
282 /*
283 * <Printer name> or <DefaultPrinter name>
284 */
285
286 if (p == NULL && value)
287 {
288 /*
289 * Add the printer and a base file type...
290 */
291
292 cupsdLogMessage(CUPSD_LOG_DEBUG,
293 "cupsdLoadRemoteCache: Loading printer %s...", value);
294
295 if ((p = cupsdFindDest(value)) != NULL)
296 {
297 if (p->type & CUPS_PRINTER_CLASS)
298 {
299 cupsdLogMessage(CUPSD_LOG_WARN,
300 "Cached remote printer \"%s\" conflicts with "
301 "existing class!",
302 value);
303 p = NULL;
304 continue;
305 }
306 }
307 else
308 p = cupsdAddPrinter(value);
309
310 p->accepting = 1;
311 p->state = IPP_PRINTER_IDLE;
312 p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
313 p->browse_time = now;
314 p->browse_expire = now + BrowseTimeout;
315
316 /*
317 * Set the default printer as needed...
318 */
319
320 if (!strcasecmp(line, "<DefaultPrinter"))
321 DefaultPrinter = p;
322 }
323 else
324 {
325 cupsdLogMessage(CUPSD_LOG_ERROR,
326 "Syntax error on line %d of remote.cache.", linenum);
327 return;
328 }
329 }
330 else if (!strcasecmp(line, "<Class") ||
331 !strcasecmp(line, "<DefaultClass"))
332 {
333 /*
334 * <Class name> or <DefaultClass name>
335 */
336
337 if (p == NULL && value)
338 {
339 /*
340 * Add the printer and a base file type...
341 */
342
343 cupsdLogMessage(CUPSD_LOG_DEBUG,
344 "cupsdLoadRemoteCache: Loading class %s...", value);
345
346 if ((p = cupsdFindDest(value)) != NULL)
347 p->type = CUPS_PRINTER_CLASS;
348 else
349 p = cupsdAddClass(value);
350
351 p->accepting = 1;
352 p->state = IPP_PRINTER_IDLE;
353 p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
354 p->browse_time = now;
355 p->browse_expire = now + BrowseTimeout;
356
357 /*
358 * Set the default printer as needed...
359 */
360
361 if (!strcasecmp(line, "<DefaultClass"))
362 DefaultPrinter = p;
363 }
364 else
365 {
366 cupsdLogMessage(CUPSD_LOG_ERROR,
367 "Syntax error on line %d of remote.cache.", linenum);
368 return;
369 }
370 }
371 else if (!strcasecmp(line, "</Printer>") ||
372 !strcasecmp(line, "</Class>"))
373 {
374 if (p != NULL)
375 {
376 /*
377 * Close out the current printer...
378 */
379
380 cupsdSetPrinterAttrs(p);
381
382 p = NULL;
383 }
384 else
385 {
386 cupsdLogMessage(CUPSD_LOG_ERROR,
387 "Syntax error on line %d of remote.cache.", linenum);
388 return;
389 }
390 }
391 else if (!p)
392 {
393 cupsdLogMessage(CUPSD_LOG_ERROR,
394 "Syntax error on line %d of remote.cache.", linenum);
395 return;
396 }
397 else if (!strcasecmp(line, "Info"))
398 {
399 if (value)
400 cupsdSetString(&p->info, value);
401 }
402 else if (!strcasecmp(line, "MakeModel"))
403 {
404 if (value)
405 cupsdSetString(&p->make_model, value);
406 }
407 else if (!strcasecmp(line, "Location"))
408 {
409 if (value)
410 cupsdSetString(&p->location, value);
411 }
412 else if (!strcasecmp(line, "DeviceURI"))
413 {
414 if (value)
415 {
416 httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme),
417 username, sizeof(username), host, sizeof(host), &port,
418 resource, sizeof(resource));
419
420 cupsdSetString(&p->hostname, host);
421 cupsdSetString(&p->uri, value);
422 cupsdSetString(&p->device_uri, value);
423 }
424 else
425 {
426 cupsdLogMessage(CUPSD_LOG_ERROR,
427 "Syntax error on line %d of remote.cache.", linenum);
428 return;
429 }
430 }
431 else if (!strcasecmp(line, "Option") && value)
432 {
433 /*
434 * Option name value
435 */
436
437 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
438
439 if (!*valueptr)
440 cupsdLogMessage(CUPSD_LOG_ERROR,
441 "Syntax error on line %d of remote.cache.", linenum);
442 else
443 {
444 for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
445
446 p->num_options = cupsAddOption(value, valueptr, p->num_options,
447 &(p->options));
448 }
449 }
450 else if (!strcasecmp(line, "State"))
451 {
452 /*
453 * Set the initial queue state...
454 */
455
456 if (value && !strcasecmp(value, "idle"))
457 p->state = IPP_PRINTER_IDLE;
458 else if (value && !strcasecmp(value, "stopped"))
459 p->state = IPP_PRINTER_STOPPED;
460 else
461 {
462 cupsdLogMessage(CUPSD_LOG_ERROR,
463 "Syntax error on line %d of remote.cache.", linenum);
464 return;
465 }
466 }
467 else if (!strcasecmp(line, "StateMessage"))
468 {
469 /*
470 * Set the initial queue state message...
471 */
472
473 if (value)
474 strlcpy(p->state_message, value, sizeof(p->state_message));
475 }
476 else if (!strcasecmp(line, "Accepting"))
477 {
478 /*
479 * Set the initial accepting state...
480 */
481
482 if (value &&
483 (!strcasecmp(value, "yes") ||
484 !strcasecmp(value, "on") ||
485 !strcasecmp(value, "true")))
486 p->accepting = 1;
487 else if (value &&
488 (!strcasecmp(value, "no") ||
489 !strcasecmp(value, "off") ||
490 !strcasecmp(value, "false")))
491 p->accepting = 0;
492 else
493 {
494 cupsdLogMessage(CUPSD_LOG_ERROR,
495 "Syntax error on line %d of remote.cache.", linenum);
496 return;
497 }
498 }
499 else if (!strcasecmp(line, "Type"))
500 {
501 if (value)
502 p->type = atoi(value);
503 else
504 {
505 cupsdLogMessage(CUPSD_LOG_ERROR,
506 "Syntax error on line %d of remote.cache.", linenum);
507 return;
508 }
509 }
510 else if (!strcasecmp(line, "BrowseTime"))
511 {
512 if (value)
513 {
514 time_t t = atoi(value);
515
516 if (t > p->browse_expire)
517 p->browse_expire = t;
518 }
519 else
520 {
521 cupsdLogMessage(CUPSD_LOG_ERROR,
522 "Syntax error on line %d of remote.cache.", linenum);
523 return;
524 }
525 }
526 else if (!strcasecmp(line, "JobSheets"))
527 {
528 /*
529 * Set the initial job sheets...
530 */
531
532 if (value)
533 {
534 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
535
536 if (*valueptr)
537 *valueptr++ = '\0';
538
539 cupsdSetString(&p->job_sheets[0], value);
540
541 while (isspace(*valueptr & 255))
542 valueptr ++;
543
544 if (*valueptr)
545 {
546 for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
547
548 if (*valueptr)
549 *valueptr++ = '\0';
550
551 cupsdSetString(&p->job_sheets[1], value);
552 }
553 }
554 else
555 {
556 cupsdLogMessage(CUPSD_LOG_ERROR,
557 "Syntax error on line %d of remote.cache.", linenum);
558 return;
559 }
560 }
561 else if (!strcasecmp(line, "AllowUser"))
562 {
563 if (value)
564 {
565 p->deny_users = 0;
566 cupsdAddPrinterUser(p, value);
567 }
568 else
569 {
570 cupsdLogMessage(CUPSD_LOG_ERROR,
571 "Syntax error on line %d of remote.cache.", linenum);
572 return;
573 }
574 }
575 else if (!strcasecmp(line, "DenyUser"))
576 {
577 if (value)
578 {
579 p->deny_users = 1;
580 cupsdAddPrinterUser(p, value);
581 }
582 else
583 {
584 cupsdLogMessage(CUPSD_LOG_ERROR,
585 "Syntax error on line %d of remote.cache.", linenum);
586 return;
587 }
588 }
589 else
590 {
591 /*
592 * Something else we don't understand...
593 */
594
595 cupsdLogMessage(CUPSD_LOG_ERROR,
596 "Unknown configuration directive %s on line %d of remote.cache.",
597 line, linenum);
598 }
599 }
600
601 cupsFileClose(fp);
602
603 /*
604 * Do auto-classing if needed...
605 */
606
607 process_implicit_classes();
608 }
609
610
611 /*
612 * 'cupsdRegisterPrinter()' - Start sending broadcast information for a
613 * printer or update the broadcast contents.
614 */
615
616 void
617 cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
618 {
619 if (!Browsing || !BrowseLocalProtocols || !BrowseInterval || !NumBrowsers ||
620 (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
621 return;
622
623 #ifdef HAVE_LIBSLP
624 /* if (BrowseLocalProtocols & BROWSE_SLP)
625 slpRegisterPrinter(p); */
626 #endif /* HAVE_LIBSLP */
627
628 #ifdef HAVE_DNSSD
629 if (BrowseLocalProtocols & BROWSE_DNSSD)
630 dnssdRegisterPrinter(p);
631 #endif /* HAVE_DNSSD */
632 }
633
634
635 /*
636 * 'cupsdRestartPolling()' - Restart polling servers as needed.
637 */
638
639 void
640 cupsdRestartPolling(void)
641 {
642 int i; /* Looping var */
643 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
644
645
646 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
647 if (pollp->pid)
648 kill(pollp->pid, SIGHUP);
649 }
650
651
652 /*
653 * 'cupsdSaveRemoteCache()' - Save the remote printer cache.
654 */
655
656 void
657 cupsdSaveRemoteCache(void)
658 {
659 int i; /* Looping var */
660 cups_file_t *fp; /* printers.conf file */
661 char temp[1024]; /* Temporary string */
662 cupsd_printer_t *printer; /* Current printer class */
663 time_t curtime; /* Current time */
664 struct tm *curdate; /* Current date */
665 cups_option_t *option; /* Current option */
666
667
668 /*
669 * Create the remote.cache file...
670 */
671
672 snprintf(temp, sizeof(temp), "%s/remote.cache", CacheDir);
673
674 if ((fp = cupsFileOpen(temp, "w")) == NULL)
675 {
676 cupsdLogMessage(CUPSD_LOG_ERROR,
677 "Unable to save remote.cache - %s", strerror(errno));
678 return;
679 }
680 else
681 cupsdLogMessage(CUPSD_LOG_DEBUG, "Saving remote.cache...");
682
683 /*
684 * Restrict access to the file...
685 */
686
687 fchown(cupsFileNumber(fp), getuid(), Group);
688 fchmod(cupsFileNumber(fp), ConfigFilePerm);
689
690 /*
691 * Write a small header to the file...
692 */
693
694 curtime = time(NULL);
695 curdate = localtime(&curtime);
696 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
697
698 cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n");
699 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
700
701 /*
702 * Write each local printer known to the system...
703 */
704
705 for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
706 printer;
707 printer = (cupsd_printer_t *)cupsArrayNext(Printers))
708 {
709 /*
710 * Skip local destinations...
711 */
712
713 if (!(printer->type & CUPS_PRINTER_DISCOVERED))
714 continue;
715
716 /*
717 * Write printers as needed...
718 */
719
720 if (printer == DefaultPrinter)
721 cupsFilePuts(fp, "<Default");
722 else
723 cupsFilePutChar(fp, '<');
724
725 if (printer->type & CUPS_PRINTER_CLASS)
726 cupsFilePrintf(fp, "Class %s>\n", printer->name);
727 else
728 cupsFilePrintf(fp, "Printer %s>\n", printer->name);
729
730 cupsFilePrintf(fp, "Type %d\n", printer->type);
731
732 cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_expire);
733
734 if (printer->info)
735 cupsFilePrintf(fp, "Info %s\n", printer->info);
736
737 if (printer->make_model)
738 cupsFilePrintf(fp, "MakeModel %s\n", printer->make_model);
739
740 if (printer->location)
741 cupsFilePrintf(fp, "Location %s\n", printer->location);
742
743 if (printer->device_uri)
744 cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
745
746 if (printer->state == IPP_PRINTER_STOPPED)
747 {
748 cupsFilePuts(fp, "State Stopped\n");
749 cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message);
750 }
751 else
752 cupsFilePuts(fp, "State Idle\n");
753
754 if (printer->accepting)
755 cupsFilePuts(fp, "Accepting Yes\n");
756 else
757 cupsFilePuts(fp, "Accepting No\n");
758
759 cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
760 printer->job_sheets[1]);
761
762 for (i = 0; i < printer->num_users; i ++)
763 cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
764 printer->users[i]);
765
766 for (i = printer->num_options, option = printer->options;
767 i > 0;
768 i --, option ++)
769 cupsFilePrintf(fp, "Option %s %s\n", option->name, option->value);
770
771 if (printer->type & CUPS_PRINTER_CLASS)
772 cupsFilePuts(fp, "</Class>\n");
773 else
774 cupsFilePuts(fp, "</Printer>\n");
775 }
776
777 cupsFileClose(fp);
778 }
779
780
781 /*
782 * 'cupsdSendBrowseList()' - Send new browsing information as necessary.
783 */
784
785 void
786 cupsdSendBrowseList(void)
787 {
788 int count; /* Number of dests to update */
789 cupsd_printer_t *p; /* Current printer */
790 time_t ut, /* Minimum update time */
791 to; /* Timeout time */
792
793
794 if (!Browsing || !BrowseLocalProtocols || !Printers)
795 return;
796
797 /*
798 * Compute the update and timeout times...
799 */
800
801 to = time(NULL);
802 ut = to - BrowseInterval;
803
804 /*
805 * Figure out how many printers need an update...
806 */
807
808 if (BrowseInterval > 0)
809 {
810 int max_count; /* Maximum number to update */
811
812
813 /*
814 * Throttle the number of printers we'll be updating this time
815 * around based on the number of queues that need updating and
816 * the maximum number of queues to update each second...
817 */
818
819 max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1;
820
821 for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers);
822 count < max_count && p != NULL;
823 p = (cupsd_printer_t *)cupsArrayNext(Printers))
824 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
825 p->shared && p->browse_time < ut)
826 count ++;
827
828 /*
829 * Loop through all of the printers and send local updates as needed...
830 */
831
832 if (BrowseNext)
833 p = (cupsd_printer_t *)cupsArrayFind(Printers, BrowseNext);
834 else
835 p = (cupsd_printer_t *)cupsArrayFirst(Printers);
836
837 for (;
838 count > 0;
839 p = (cupsd_printer_t *)cupsArrayNext(Printers))
840 {
841 /*
842 * Check for wraparound...
843 */
844
845 if (!p)
846 p = (cupsd_printer_t *)cupsArrayFirst(Printers);
847
848 if (!p)
849 break;
850 else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) ||
851 !p->shared)
852 continue;
853 else if (p->browse_time < ut)
854 {
855 /*
856 * Need to send an update...
857 */
858
859 count --;
860
861 p->browse_time = time(NULL);
862
863 if (BrowseLocalProtocols & BROWSE_CUPS)
864 send_cups_browse(p);
865
866 #ifdef HAVE_LIBSLP
867 if (BrowseLocalProtocols & BROWSE_SLP)
868 send_slp_browse(p);
869 #endif /* HAVE_LIBSLP */
870
871 #ifdef HAVE_LDAP
872 if (BrowseLocalProtocols & BROWSE_LDAP)
873 send_ldap_browse(p);
874 #endif /* HAVE_LDAP */
875 }
876 }
877
878 /*
879 * Save where we left off so that all printers get updated...
880 */
881
882 BrowseNext = p;
883 }
884
885 /*
886 * Loop through all of the printers and send local updates as needed...
887 */
888
889 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
890 p;
891 p = (cupsd_printer_t *)cupsArrayNext(Printers))
892 {
893 /*
894 * If this is a remote queue, see if it needs to be timed out...
895 */
896
897 if (p->type & CUPS_PRINTER_DISCOVERED)
898 {
899 if (p->browse_expire < to)
900 {
901 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
902 "%s \'%s\' deleted by directory services (timeout).",
903 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
904 p->name);
905
906 cupsdLogMessage(CUPSD_LOG_DEBUG,
907 "Remote destination \"%s\" has timed out; "
908 "deleting it...",
909 p->name);
910
911 cupsArraySave(Printers);
912 cupsdDeletePrinter(p, 1);
913 cupsArrayRestore(Printers);
914 }
915 }
916 }
917 }
918
919
920 /*
921 * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
922 */
923
924 void
925 cupsdStartBrowsing(void)
926 {
927 int val; /* Socket option value */
928 struct sockaddr_in addr; /* Broadcast address */
929 cupsd_printer_t *p; /* Current printer */
930
931
932 BrowseNext = NULL;
933
934 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
935 return;
936
937 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
938 {
939 if (BrowseSocket < 0)
940 {
941 /*
942 * Create the broadcast socket...
943 */
944
945 if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
946 {
947 cupsdLogMessage(CUPSD_LOG_ERROR,
948 "Unable to create broadcast socket - %s.",
949 strerror(errno));
950 BrowseLocalProtocols &= ~BROWSE_CUPS;
951 BrowseRemoteProtocols &= ~BROWSE_CUPS;
952 return;
953 }
954
955 /*
956 * Bind the socket to browse port...
957 */
958
959 memset(&addr, 0, sizeof(addr));
960 addr.sin_addr.s_addr = htonl(INADDR_ANY);
961 addr.sin_family = AF_INET;
962 addr.sin_port = htons(BrowsePort);
963
964 if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
965 {
966 cupsdLogMessage(CUPSD_LOG_ERROR,
967 "Unable to bind broadcast socket - %s.",
968 strerror(errno));
969
970 #ifdef WIN32
971 closesocket(BrowseSocket);
972 #else
973 close(BrowseSocket);
974 #endif /* WIN32 */
975
976 BrowseSocket = -1;
977 BrowseLocalProtocols &= ~BROWSE_CUPS;
978 BrowseRemoteProtocols &= ~BROWSE_CUPS;
979 return;
980 }
981 }
982
983 /*
984 * Set the "broadcast" flag...
985 */
986
987 val = 1;
988 if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
989 {
990 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
991 strerror(errno));
992
993 #ifdef WIN32
994 closesocket(BrowseSocket);
995 #else
996 close(BrowseSocket);
997 #endif /* WIN32 */
998
999 BrowseSocket = -1;
1000 BrowseLocalProtocols &= ~BROWSE_CUPS;
1001 BrowseRemoteProtocols &= ~BROWSE_CUPS;
1002 return;
1003 }
1004
1005 /*
1006 * Close the socket on exec...
1007 */
1008
1009 fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
1010
1011 /*
1012 * Finally, add the socket to the input selection set as needed...
1013 */
1014
1015 if (BrowseRemoteProtocols & BROWSE_CUPS)
1016 {
1017 /*
1018 * We only listen if we want remote printers...
1019 */
1020
1021 cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
1022 NULL, NULL);
1023 }
1024 }
1025 else
1026 BrowseSocket = -1;
1027
1028 #ifdef HAVE_LIBSLP
1029 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
1030 {
1031 /*
1032 * Open SLP handle...
1033 */
1034
1035 if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
1036 {
1037 cupsdLogMessage(CUPSD_LOG_ERROR,
1038 "Unable to open an SLP handle; disabling SLP browsing!");
1039 BrowseLocalProtocols &= ~BROWSE_SLP;
1040 BrowseRemoteProtocols &= ~BROWSE_SLP;
1041 }
1042
1043 BrowseSLPRefresh = 0;
1044 }
1045 else
1046 BrowseSLPHandle = NULL;
1047 #endif /* HAVE_LIBSLP */
1048
1049 #ifdef HAVE_OPENLDAP
1050 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
1051 {
1052 if (!BrowseLDAPDN)
1053 {
1054 cupsdLogMessage(CUPSD_LOG_ERROR,
1055 "Need to set BrowseLDAPDN to use LDAP browsing!");
1056 BrowseLocalProtocols &= ~BROWSE_LDAP;
1057 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1058 }
1059 else
1060 {
1061 /*
1062 * Open LDAP handle...
1063 */
1064
1065 int rc; /* LDAP API status */
1066 int version = 3; /* LDAP version */
1067 struct berval bv = {0, ""}; /* SASL bind value */
1068
1069
1070 /*
1071 * Set the certificate file to use for encrypted LDAP sessions...
1072 */
1073
1074 if (BrowseLDAPCACertFile)
1075 {
1076 cupsdLogMessage(CUPSD_LOG_DEBUG,
1077 "cupsdStartBrowsing: Setting CA certificate file \"%s\"",
1078 BrowseLDAPCACertFile);
1079
1080 if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
1081 (void *)BrowseLDAPCACertFile))
1082 != LDAP_SUCCESS)
1083 cupsdLogMessage(CUPSD_LOG_ERROR,
1084 "Unable to set CA certificate file for LDAP "
1085 "connections: %d - %s", rc, ldap_err2string(rc));
1086 }
1087
1088 /*
1089 * LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
1090 */
1091
1092 if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
1093 rc = ldap_initialize(&BrowseLDAPHandle, "ldapi:///");
1094 else
1095 rc = ldap_initialize(&BrowseLDAPHandle, BrowseLDAPServer);
1096
1097 if (rc != LDAP_SUCCESS)
1098 {
1099 cupsdLogMessage(CUPSD_LOG_ERROR,
1100 "Unable to initialize LDAP; disabling LDAP browsing!");
1101 BrowseLocalProtocols &= ~BROWSE_LDAP;
1102 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1103 }
1104 else if (ldap_set_option(BrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
1105 (const void *)&version) != LDAP_SUCCESS)
1106 {
1107 ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
1108 BrowseLDAPHandle = NULL;
1109 cupsdLogMessage(CUPSD_LOG_ERROR,
1110 "Unable to set LDAP protocol version; "
1111 "disabling LDAP browsing!");
1112 BrowseLocalProtocols &= ~BROWSE_LDAP;
1113 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1114 }
1115 else
1116 {
1117 if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
1118 rc = ldap_sasl_bind_s(BrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
1119 NULL, NULL);
1120 else
1121 rc = ldap_bind_s(BrowseLDAPHandle, BrowseLDAPBindDN,
1122 BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
1123
1124 if (rc != LDAP_SUCCESS)
1125 {
1126 cupsdLogMessage(CUPSD_LOG_ERROR,
1127 "Unable to bind to LDAP server; "
1128 "disabling LDAP browsing!");
1129 ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
1130 BrowseLocalProtocols &= ~BROWSE_LDAP;
1131 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1132 }
1133 }
1134 }
1135
1136 BrowseLDAPRefresh = 0;
1137 }
1138 #endif /* HAVE_OPENLDAP */
1139
1140 /*
1141 * Register the individual printers
1142 */
1143
1144 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1145 p;
1146 p = (cupsd_printer_t *)cupsArrayNext(Printers))
1147 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
1148 cupsdRegisterPrinter(p);
1149 }
1150
1151
1152 /*
1153 * 'cupsdStartPolling()' - Start polling servers as needed.
1154 */
1155
1156 void
1157 cupsdStartPolling(void)
1158 {
1159 int i; /* Looping var */
1160 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1161 char polld[1024]; /* Poll daemon path */
1162 char sport[255]; /* Server port */
1163 char bport[255]; /* Browser port */
1164 char interval[255]; /* Poll interval */
1165 int statusfds[2]; /* Status pipe */
1166 char *argv[6]; /* Arguments */
1167 char *envp[100]; /* Environment */
1168
1169
1170 /*
1171 * Don't do anything if we aren't polling...
1172 */
1173
1174 if (NumPolled == 0 || BrowseSocket < 0)
1175 {
1176 PollPipe = -1;
1177 PollStatusBuffer = NULL;
1178 return;
1179 }
1180
1181 /*
1182 * Setup string arguments for polld, port and interval options.
1183 */
1184
1185 snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
1186
1187 sprintf(bport, "%d", BrowsePort);
1188
1189 if (BrowseInterval)
1190 sprintf(interval, "%d", BrowseInterval);
1191 else
1192 strcpy(interval, "30");
1193
1194 argv[0] = "cups-polld";
1195 argv[2] = sport;
1196 argv[3] = interval;
1197 argv[4] = bport;
1198 argv[5] = NULL;
1199
1200 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
1201
1202 /*
1203 * Create a pipe that receives the status messages from each
1204 * polling daemon...
1205 */
1206
1207 if (cupsdOpenPipe(statusfds))
1208 {
1209 cupsdLogMessage(CUPSD_LOG_ERROR,
1210 "Unable to create polling status pipes - %s.",
1211 strerror(errno));
1212 PollPipe = -1;
1213 PollStatusBuffer = NULL;
1214 return;
1215 }
1216
1217 PollPipe = statusfds[0];
1218 PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
1219
1220 /*
1221 * Run each polling daemon, redirecting stderr to the polling pipe...
1222 */
1223
1224 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1225 {
1226 sprintf(sport, "%d", pollp->port);
1227
1228 argv[1] = pollp->hostname;
1229
1230 if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
1231 0, &(pollp->pid)) < 0)
1232 {
1233 cupsdLogMessage(CUPSD_LOG_ERROR,
1234 "cupsdStartPolling: Unable to fork polling daemon - %s",
1235 strerror(errno));
1236 pollp->pid = 0;
1237 break;
1238 }
1239 else
1240 cupsdLogMessage(CUPSD_LOG_DEBUG,
1241 "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
1242 pollp->hostname, pollp->port, pollp->pid);
1243 }
1244
1245 close(statusfds[1]);
1246
1247 /*
1248 * Finally, add the pipe to the input selection set...
1249 */
1250
1251 cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
1252 }
1253
1254
1255 /*
1256 * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
1257 */
1258
1259 void
1260 cupsdStopBrowsing(void)
1261 {
1262 cupsd_printer_t *p; /* Current printer */
1263
1264
1265 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
1266 return;
1267
1268 /*
1269 * De-register the individual printers
1270 */
1271
1272 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1273 p;
1274 p = (cupsd_printer_t *)cupsArrayNext(Printers))
1275 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
1276 cupsdDeregisterPrinter(p, 1);
1277
1278 /*
1279 * Shut down browsing sockets...
1280 */
1281
1282 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
1283 BrowseSocket >= 0)
1284 {
1285 /*
1286 * Close the socket and remove it from the input selection set.
1287 */
1288
1289 #ifdef WIN32
1290 closesocket(BrowseSocket);
1291 #else
1292 close(BrowseSocket);
1293 #endif /* WIN32 */
1294
1295 cupsdRemoveSelect(BrowseSocket);
1296 BrowseSocket = -1;
1297 }
1298
1299 #ifdef HAVE_LIBSLP
1300 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
1301 BrowseSLPHandle)
1302 {
1303 /*
1304 * Close SLP handle...
1305 */
1306
1307 SLPClose(BrowseSLPHandle);
1308 BrowseSLPHandle = NULL;
1309 }
1310 #endif /* HAVE_LIBSLP */
1311
1312 #ifdef HAVE_OPENLDAP
1313 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
1314 BrowseLDAPHandle)
1315 {
1316 ldap_unbind(BrowseLDAPHandle);
1317 BrowseLDAPHandle = NULL;
1318 }
1319 #endif /* HAVE_OPENLDAP */
1320 }
1321
1322
1323 /*
1324 * 'cupsdStopPolling()' - Stop polling servers as needed.
1325 */
1326
1327 void
1328 cupsdStopPolling(void)
1329 {
1330 int i; /* Looping var */
1331 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1332
1333
1334 if (PollPipe >= 0)
1335 {
1336 cupsdStatBufDelete(PollStatusBuffer);
1337 close(PollPipe);
1338
1339 cupsdRemoveSelect(PollPipe);
1340
1341 PollPipe = -1;
1342 PollStatusBuffer = NULL;
1343 }
1344
1345 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1346 if (pollp->pid)
1347 cupsdEndProcess(pollp->pid, 0);
1348 }
1349
1350
1351 #ifdef HAVE_DNSSD
1352 /*
1353 * 'cupsdUpdateDNSSDBrowse()' - Handle DNS-SD queries.
1354 */
1355
1356 void
1357 cupsdUpdateDNSSDBrowse(
1358 cupsd_printer_t *p) /* I - Printer being queried */
1359 {
1360 DNSServiceErrorType sdErr; /* Service discovery error */
1361
1362
1363 if ((sdErr = DNSServiceProcessResult(p->dnssd_ipp_ref))
1364 != kDNSServiceErr_NoError)
1365 {
1366 cupsdLogMessage(CUPSD_LOG_ERROR,
1367 "DNS Service Discovery registration error %d for \"%s\"!",
1368 sdErr, p->name);
1369 cupsdRemoveSelect(p->dnssd_ipp_fd);
1370 DNSServiceRefDeallocate(p->dnssd_ipp_ref);
1371
1372 p->dnssd_ipp_ref = NULL;
1373 p->dnssd_ipp_fd = -1;
1374 }
1375 }
1376 #endif /* HAVE_DNSSD */
1377
1378
1379 #ifdef HAVE_OPENLDAP
1380 /*
1381 * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
1382 */
1383
1384 void
1385 cupsdUpdateLDAPBrowse(void)
1386 {
1387 char uri[HTTP_MAX_URI], /* Printer URI */
1388 host[HTTP_MAX_URI], /* Hostname */
1389 resource[HTTP_MAX_URI], /* Resource path */
1390 location[1024], /* Printer location */
1391 info[1024], /* Printer information */
1392 make_model[1024], /* Printer make and model */
1393 **value; /* Holds the returned data from LDAP */
1394 int type; /* Printer type */
1395 int rc; /* LDAP status */
1396 int limit; /* Size limit */
1397 LDAPMessage *res, /* LDAP search results */
1398 *e; /* Current entry from search */
1399
1400
1401 /*
1402 * Search for printers...
1403 */
1404
1405 cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
1406
1407 BrowseLDAPRefresh = time(NULL) + BrowseInterval;
1408
1409 rc = ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
1410 "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
1411 if (rc != LDAP_SUCCESS)
1412 {
1413 cupsdLogMessage(CUPSD_LOG_ERROR,
1414 "LDAP search returned error %d: %s", rc,
1415 ldap_err2string(rc));
1416 return;
1417 }
1418
1419 limit = ldap_count_entries(BrowseLDAPHandle, res);
1420 cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
1421 if (limit < 1)
1422 return;
1423
1424 /*
1425 * Loop through the available printers...
1426 */
1427
1428 for (e = ldap_first_entry(BrowseLDAPHandle, res);
1429 e;
1430 e = ldap_next_entry(BrowseLDAPHandle, e))
1431 {
1432 /*
1433 * Get the required values from this entry...
1434 */
1435
1436 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1437 "printerDescription")) == NULL)
1438 continue;
1439
1440 strlcpy(info, *value, sizeof(info));
1441 ldap_value_free(value);
1442
1443 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1444 "printerLocation")) == NULL)
1445 continue;
1446
1447 strlcpy(location, *value, sizeof(location));
1448 ldap_value_free(value);
1449
1450 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1451 "printerMakeAndModel")) == NULL)
1452 continue;
1453
1454 strlcpy(make_model, *value, sizeof(make_model));
1455 ldap_value_free(value);
1456
1457 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1458 "printerType")) == NULL)
1459 continue;
1460
1461 type = atoi(*value);
1462 ldap_value_free(value);
1463
1464 if ((value = ldap_get_values(BrowseLDAPHandle, e,
1465 "printerURI")) == NULL)
1466 continue;
1467
1468 strlcpy(uri, *value, sizeof(uri));
1469 ldap_value_free(value);
1470
1471 /*
1472 * Process the entry as browse data...
1473 */
1474
1475 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
1476 process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
1477 location, info, make_model, 0, NULL);
1478
1479 }
1480 }
1481 #endif /* HAVE_OPENLDAP */
1482
1483
1484 #ifdef HAVE_LIBSLP
1485 /*
1486 * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
1487 */
1488
1489 void
1490 cupsdUpdateSLPBrowse(void)
1491 {
1492 slpsrvurl_t *s, /* Temporary list of service URLs */
1493 *next; /* Next service in list */
1494 cupsd_printer_t p; /* Printer information */
1495 const char *uri; /* Pointer to printer URI */
1496 char host[HTTP_MAX_URI], /* Host portion of URI */
1497 resource[HTTP_MAX_URI]; /* Resource portion of URI */
1498
1499
1500 /*
1501 * Reset the refresh time...
1502 */
1503
1504 BrowseSLPRefresh = time(NULL) + BrowseInterval;
1505
1506 /*
1507 * Poll for remote printers using SLP...
1508 */
1509
1510 s = NULL;
1511
1512 SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
1513 slp_url_callback, &s);
1514
1515 /*
1516 * Loop through the list of available printers...
1517 */
1518
1519 for (; s; s = next)
1520 {
1521 /*
1522 * Save the "next" pointer...
1523 */
1524
1525 next = s->next;
1526
1527 /*
1528 * Load a cupsd_printer_t structure with the SLP service attributes...
1529 */
1530
1531 SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
1532
1533 /*
1534 * Process this printer entry...
1535 */
1536
1537 uri = s->url + SLP_CUPS_SRVLEN + 1;
1538
1539 if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
1540 {
1541 /*
1542 * Pull the URI apart to see if this is a local or remote printer...
1543 */
1544
1545 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
1546 process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE,
1547 p.location, p.info, p.make_model, 0, NULL);
1548 }
1549
1550 /*
1551 * Free this listing...
1552 */
1553
1554 cupsdClearString(&p.info);
1555 cupsdClearString(&p.location);
1556 cupsdClearString(&p.make_model);
1557
1558 free(s);
1559 }
1560 }
1561 #endif /* HAVE_LIBSLP */
1562
1563
1564 /*
1565 * 'dequote()' - Remote quotes from a string.
1566 */
1567
1568 static char * /* O - Dequoted string */
1569 dequote(char *d, /* I - Destination string */
1570 const char *s, /* I - Source string */
1571 int dlen) /* I - Destination length */
1572 {
1573 char *dptr; /* Pointer into destination */
1574
1575
1576 if (s)
1577 {
1578 for (dptr = d, dlen --; *s && dlen > 0; s ++)
1579 if (*s != '\"')
1580 {
1581 *dptr++ = *s;
1582 dlen --;
1583 }
1584
1585 *dptr = '\0';
1586 }
1587 else
1588 *d = '\0';
1589
1590 return (d);
1591 }
1592
1593
1594 /*
1595 * 'is_local_queue()' - Determine whether the URI points at a local queue.
1596 */
1597
1598 static int /* O - 1 = local, 0 = remote, -1 = bad URI */
1599 is_local_queue(const char *uri, /* I - Printer URI */
1600 char *host, /* O - Host string */
1601 int hostlen, /* I - Length of host buffer */
1602 char *resource, /* O - Resource string */
1603 int resourcelen) /* I - Length of resource buffer */
1604 {
1605 char scheme[32], /* Scheme portion of URI */
1606 username[HTTP_MAX_URI]; /* Username portion of URI */
1607 int port; /* Port portion of URI */
1608 cupsd_netif_t *iface; /* Network interface */
1609
1610
1611 /*
1612 * Pull the URI apart to see if this is a local or remote printer...
1613 */
1614
1615 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
1616 username, sizeof(username), host, hostlen, &port,
1617 resource, resourcelen) < HTTP_URI_OK)
1618 return (-1);
1619
1620 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
1621
1622 /*
1623 * Check for local server addresses...
1624 */
1625
1626 if (!strcasecmp(host, ServerName) && port == LocalPort)
1627 return (1);
1628
1629 cupsdNetIFUpdate();
1630
1631 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
1632 iface;
1633 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
1634 if (!strcasecmp(host, iface->hostname) && port == iface->port)
1635 return (1);
1636
1637 /*
1638 * If we get here, the printer is remote...
1639 */
1640
1641 return (0);
1642 }
1643
1644
1645 /*
1646 * 'process_browse_data()' - Process new browse data.
1647 */
1648
1649 static void
1650 process_browse_data(
1651 const char *uri, /* I - URI of printer/class */
1652 const char *host, /* I - Hostname */
1653 const char *resource, /* I - Resource path */
1654 cups_ptype_t type, /* I - Printer type */
1655 ipp_pstate_t state, /* I - Printer state */
1656 const char *location, /* I - Printer location */
1657 const char *info, /* I - Printer information */
1658 const char *make_model, /* I - Printer make and model */
1659 int num_attrs, /* I - Number of attributes */
1660 cups_option_t *attrs) /* I - Attributes */
1661 {
1662 int i; /* Looping var */
1663 int update; /* Update printer attributes? */
1664 char finaluri[HTTP_MAX_URI], /* Final URI for printer */
1665 name[IPP_MAX_NAME], /* Name of printer */
1666 newname[IPP_MAX_NAME], /* New name of printer */
1667 *hptr, /* Pointer into hostname */
1668 *sptr; /* Pointer into ServerName */
1669 char local_make_model[IPP_MAX_NAME];
1670 /* Local make and model */
1671 cupsd_printer_t *p; /* Printer information */
1672 const char *ipp_options, /* ipp-options value */
1673 *lease_duration; /* lease-duration value */
1674
1675
1676 /*
1677 * Determine if the URI contains any illegal characters in it...
1678 */
1679
1680 if (strncmp(uri, "ipp://", 6) || !host[0] ||
1681 (strncmp(resource, "/printers/", 10) &&
1682 strncmp(resource, "/classes/", 9)))
1683 {
1684 cupsdLogMessage(CUPSD_LOG_ERROR,
1685 "process_browse_data: Bad printer URI in browse data: %s",
1686 uri);
1687 return;
1688 }
1689
1690 if (strchr(resource, '?') ||
1691 (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
1692 (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
1693 {
1694 cupsdLogMessage(CUPSD_LOG_ERROR,
1695 "process_browse_data: Bad resource in browse data: %s",
1696 resource);
1697 return;
1698 }
1699
1700 /*
1701 * OK, this isn't a local printer; add any remote options...
1702 */
1703
1704 ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
1705
1706 if (BrowseRemoteOptions)
1707 {
1708 if (BrowseRemoteOptions[0] == '?')
1709 {
1710 /*
1711 * Override server-supplied options...
1712 */
1713
1714 snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
1715 }
1716 else if (ipp_options)
1717 {
1718 /*
1719 * Combine the server and local options...
1720 */
1721
1722 snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
1723 BrowseRemoteOptions);
1724 }
1725 else
1726 {
1727 /*
1728 * Just use the local options...
1729 */
1730
1731 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
1732 }
1733
1734 uri = finaluri;
1735 }
1736 else if (ipp_options)
1737 {
1738 /*
1739 * Just use the server-supplied options...
1740 */
1741
1742 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
1743 uri = finaluri;
1744 }
1745
1746 /*
1747 * See if we already have it listed in the Printers list, and add it if not...
1748 */
1749
1750 type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
1751 type &= ~CUPS_PRINTER_IMPLICIT;
1752 update = 0;
1753 hptr = strchr(host, '.');
1754 sptr = strchr(ServerName, '.');
1755
1756 if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
1757 {
1758 /*
1759 * Strip the common domain name components...
1760 */
1761
1762 while (hptr != NULL)
1763 {
1764 if (!strcasecmp(hptr, sptr))
1765 {
1766 *hptr = '\0';
1767 break;
1768 }
1769 else
1770 hptr = strchr(hptr + 1, '.');
1771 }
1772 }
1773
1774 if (type & CUPS_PRINTER_CLASS)
1775 {
1776 /*
1777 * Remote destination is a class...
1778 */
1779
1780 if (!strncmp(resource, "/classes/", 9))
1781 snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
1782 else
1783 return;
1784
1785 if (hptr && !*hptr)
1786 *hptr = '.'; /* Resource FQDN */
1787
1788 if ((p = cupsdFindClass(name)) == NULL && BrowseShortNames)
1789 {
1790 if ((p = cupsdFindClass(resource + 9)) != NULL)
1791 {
1792 if (p->hostname && strcasecmp(p->hostname, host))
1793 {
1794 /*
1795 * Nope, this isn't the same host; if the hostname isn't the local host,
1796 * add it to the other class and then find a class using the full host
1797 * name...
1798 */
1799
1800 if (p->type & CUPS_PRINTER_REMOTE)
1801 {
1802 cupsdLogMessage(CUPSD_LOG_DEBUG,
1803 "Renamed remote class \"%s\" to \"%s@%s\"...",
1804 p->name, p->name, p->hostname);
1805 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
1806 "Class \'%s\' deleted by directory services.",
1807 p->name);
1808
1809 snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
1810 cupsdRenamePrinter(p, newname);
1811
1812 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
1813 "Class \'%s\' added by directory services.",
1814 p->name);
1815 }
1816
1817 p = NULL;
1818 }
1819 else if (!p->hostname)
1820 {
1821 /*
1822 * Hostname not set, so this must be a cached remote printer
1823 * that was created for a pending print job...
1824 */
1825
1826 cupsdSetString(&p->hostname, host);
1827 cupsdSetString(&p->uri, uri);
1828 cupsdSetString(&p->device_uri, uri);
1829 update = 1;
1830 }
1831 }
1832 else
1833 {
1834 /*
1835 * Use the short name for this shared class.
1836 */
1837
1838 strlcpy(name, resource + 9, sizeof(name));
1839 }
1840 }
1841 else if (p && !p->hostname)
1842 {
1843 /*
1844 * Hostname not set, so this must be a cached remote printer
1845 * that was created for a pending print job...
1846 */
1847
1848 cupsdSetString(&p->hostname, host);
1849 cupsdSetString(&p->uri, uri);
1850 cupsdSetString(&p->device_uri, uri);
1851 update = 1;
1852 }
1853
1854 if (!p)
1855 {
1856 /*
1857 * Class doesn't exist; add it...
1858 */
1859
1860 p = cupsdAddClass(name);
1861
1862 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote class \"%s\"...", name);
1863
1864 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
1865 "Class \'%s\' added by directory services.", name);
1866
1867 /*
1868 * Force the URI to point to the real server...
1869 */
1870
1871 p->type = type & ~CUPS_PRINTER_REJECTING;
1872 p->accepting = 1;
1873 cupsdSetString(&p->uri, uri);
1874 cupsdSetString(&p->device_uri, uri);
1875 cupsdSetString(&p->hostname, host);
1876
1877 update = 1;
1878 }
1879 }
1880 else
1881 {
1882 /*
1883 * Remote destination is a printer...
1884 */
1885
1886 if (!strncmp(resource, "/printers/", 10))
1887 snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
1888 else
1889 return;
1890
1891 if (hptr && !*hptr)
1892 *hptr = '.'; /* Resource FQDN */
1893
1894 if ((p = cupsdFindPrinter(name)) == NULL && BrowseShortNames)
1895 {
1896 if ((p = cupsdFindPrinter(resource + 10)) != NULL)
1897 {
1898 if (p->hostname && strcasecmp(p->hostname, host))
1899 {
1900 /*
1901 * Nope, this isn't the same host; if the hostname isn't the local host,
1902 * add it to the other printer and then find a printer using the full host
1903 * name...
1904 */
1905
1906 if (p->type & CUPS_PRINTER_REMOTE)
1907 {
1908 cupsdLogMessage(CUPSD_LOG_DEBUG,
1909 "Renamed remote printer \"%s\" to \"%s@%s\"...",
1910 p->name, p->name, p->hostname);
1911 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
1912 "Printer \'%s\' deleted by directory services.",
1913 p->name);
1914
1915 snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
1916 cupsdRenamePrinter(p, newname);
1917
1918 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
1919 "Printer \'%s\' added by directory services.",
1920 p->name);
1921 }
1922
1923 p = NULL;
1924 }
1925 else if (!p->hostname)
1926 {
1927 /*
1928 * Hostname not set, so this must be a cached remote printer
1929 * that was created for a pending print job...
1930 */
1931
1932 cupsdSetString(&p->hostname, host);
1933 cupsdSetString(&p->uri, uri);
1934 cupsdSetString(&p->device_uri, uri);
1935 update = 1;
1936 }
1937 }
1938 else
1939 {
1940 /*
1941 * Use the short name for this shared printer.
1942 */
1943
1944 strlcpy(name, resource + 10, sizeof(name));
1945 }
1946 }
1947 else if (p && !p->hostname)
1948 {
1949 /*
1950 * Hostname not set, so this must be a cached remote printer
1951 * that was created for a pending print job...
1952 */
1953
1954 cupsdSetString(&p->hostname, host);
1955 cupsdSetString(&p->uri, uri);
1956 cupsdSetString(&p->device_uri, uri);
1957 update = 1;
1958 }
1959
1960 if (!p)
1961 {
1962 /*
1963 * Printer doesn't exist; add it...
1964 */
1965
1966 p = cupsdAddPrinter(name);
1967
1968 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
1969 "Printer \'%s\' added by directory services.", name);
1970
1971 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote printer \"%s\"...", name);
1972
1973 /*
1974 * Force the URI to point to the real server...
1975 */
1976
1977 p->type = type & ~CUPS_PRINTER_REJECTING;
1978 p->accepting = 1;
1979 cupsdSetString(&p->hostname, host);
1980 cupsdSetString(&p->uri, uri);
1981 cupsdSetString(&p->device_uri, uri);
1982
1983 update = 1;
1984 }
1985 }
1986
1987 /*
1988 * Update the state...
1989 */
1990
1991 p->state = state;
1992 p->browse_time = time(NULL);
1993
1994 if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
1995 attrs)) != NULL)
1996 {
1997 /*
1998 * Grab the lease-duration for the browse data; anything less then 1
1999 * second or more than 1 week gets the default BrowseTimeout...
2000 */
2001
2002 i = atoi(lease_duration);
2003 if (i < 1 || i > 604800)
2004 i = BrowseTimeout;
2005
2006 p->browse_expire = p->browse_time + i;
2007 }
2008 else
2009 p->browse_expire = p->browse_time + BrowseTimeout;
2010
2011 if (type & CUPS_PRINTER_REJECTING)
2012 {
2013 type &= ~CUPS_PRINTER_REJECTING;
2014
2015 if (p->accepting)
2016 {
2017 update = 1;
2018 p->accepting = 0;
2019 }
2020 }
2021 else if (!p->accepting)
2022 {
2023 update = 1;
2024 p->accepting = 1;
2025 }
2026
2027 if (p->type != type)
2028 {
2029 p->type = type;
2030 update = 1;
2031 }
2032
2033 if (location && (!p->location || strcmp(p->location, location)))
2034 {
2035 cupsdSetString(&p->location, location);
2036 update = 1;
2037 }
2038
2039 if (info && (!p->info || strcmp(p->info, info)))
2040 {
2041 cupsdSetString(&p->info, info);
2042 update = 1;
2043 }
2044
2045 if (!make_model || !make_model[0])
2046 {
2047 if (type & CUPS_PRINTER_CLASS)
2048 snprintf(local_make_model, sizeof(local_make_model),
2049 "Remote Class on %s", host);
2050 else
2051 snprintf(local_make_model, sizeof(local_make_model),
2052 "Remote Printer on %s", host);
2053 }
2054 else
2055 snprintf(local_make_model, sizeof(local_make_model),
2056 "%s on %s", make_model, host);
2057
2058 if (!p->make_model || strcmp(p->make_model, local_make_model))
2059 {
2060 cupsdSetString(&p->make_model, local_make_model);
2061 update = 1;
2062 }
2063
2064 if (p->num_options)
2065 {
2066 if (!update && !(type & CUPS_PRINTER_DELETE))
2067 {
2068 /*
2069 * See if we need to update the attributes...
2070 */
2071
2072 if (p->num_options != num_attrs)
2073 update = 1;
2074 else
2075 {
2076 for (i = 0; i < num_attrs; i ++)
2077 if (strcmp(attrs[i].name, p->options[i].name) ||
2078 (!attrs[i].value != !p->options[i].value) ||
2079 (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
2080 {
2081 update = 1;
2082 break;
2083 }
2084 }
2085 }
2086
2087 /*
2088 * Free the old options...
2089 */
2090
2091 cupsFreeOptions(p->num_options, p->options);
2092 }
2093
2094 p->num_options = num_attrs;
2095 p->options = attrs;
2096
2097 if (type & CUPS_PRINTER_DELETE)
2098 {
2099 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
2100 "%s \'%s\' deleted by directory services.",
2101 (type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", p->name);
2102
2103 cupsdExpireSubscriptions(p, NULL);
2104
2105 cupsdDeletePrinter(p, 1);
2106 cupsdUpdateImplicitClasses();
2107 }
2108 else if (update)
2109 {
2110 cupsdSetPrinterAttrs(p);
2111 cupsdUpdateImplicitClasses();
2112 }
2113
2114 /*
2115 * See if we have a default printer... If not, make the first network
2116 * default printer the default.
2117 */
2118
2119 if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
2120 {
2121 /*
2122 * Find the first network default printer and use it...
2123 */
2124
2125 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2126 p;
2127 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2128 if (p->type & CUPS_PRINTER_DEFAULT)
2129 {
2130 DefaultPrinter = p;
2131 break;
2132 }
2133 }
2134
2135 /*
2136 * Do auto-classing if needed...
2137 */
2138
2139 process_implicit_classes();
2140
2141 /*
2142 * Update the printcap file...
2143 */
2144
2145 cupsdWritePrintcap();
2146 }
2147
2148
2149 #ifdef HAVE_DNSSD
2150 /*
2151 * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
2152 */
2153
2154 static char * /* O - TXT record */
2155 dnssdBuildTxtRecord(
2156 int *txt_len, /* O - TXT record length */
2157 cupsd_printer_t *p) /* I - Printer information */
2158 {
2159 int i, j; /* Looping vars */
2160 char type_str[32], /* Type to string buffer */
2161 state_str[32], /* State to string buffer */
2162 rp_str[1024], /* Queue name string buffer */
2163 air_str[1024], /* auth-info-required string buffer */
2164 *keyvalue[32][2]; /* Table of key/value pairs */
2165
2166
2167 /*
2168 * Load up the key value pairs...
2169 */
2170
2171 i = 0;
2172
2173 keyvalue[i ][0] = "txtvers";
2174 keyvalue[i++][1] = "1";
2175
2176 keyvalue[i ][0] = "qtotal";
2177 keyvalue[i++][1] = "1";
2178
2179 keyvalue[i ][0] = "rp";
2180 keyvalue[i++][1] = rp_str;
2181 snprintf(rp_str, sizeof(rp_str), "%s/%s",
2182 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
2183
2184 keyvalue[i ][0] = "ty";
2185 keyvalue[i++][1] = p->make_model;
2186
2187 if (p->location && *p->location != '\0')
2188 {
2189 keyvalue[i ][0] = "note";
2190 keyvalue[i++][1] = p->location;
2191 }
2192
2193 keyvalue[i ][0] = "product";
2194 keyvalue[i++][1] = p->product ? p->product : "Unknown";
2195
2196 snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
2197 snprintf(state_str, sizeof(state_str), "%d", p->state);
2198
2199 keyvalue[i ][0] = "printer-state";
2200 keyvalue[i++][1] = state_str;
2201
2202 keyvalue[i ][0] = "printer-type";
2203 keyvalue[i++][1] = type_str;
2204
2205 keyvalue[i ][0] = "Transparent";
2206 keyvalue[i++][1] = "T";
2207
2208 keyvalue[i ][0] = "Binary";
2209 keyvalue[i++][1] = "T";
2210
2211 if ((p->type & CUPS_PRINTER_FAX))
2212 {
2213 keyvalue[i ][0] = "Fax";
2214 keyvalue[i++][1] = "T";
2215 }
2216
2217 if ((p->type & CUPS_PRINTER_COLOR))
2218 {
2219 keyvalue[i ][0] = "Color";
2220 keyvalue[i++][1] = "T";
2221 }
2222
2223 if ((p->type & CUPS_PRINTER_DUPLEX))
2224 {
2225 keyvalue[i ][0] = "Duplex";
2226 keyvalue[i++][1] = "T";
2227 }
2228
2229 if ((p->type & CUPS_PRINTER_STAPLE))
2230 {
2231 keyvalue[i ][0] = "Staple";
2232 keyvalue[i++][1] = "T";
2233 }
2234
2235 if ((p->type & CUPS_PRINTER_COPIES))
2236 {
2237 keyvalue[i ][0] = "Copies";
2238 keyvalue[i++][1] = "T";
2239 }
2240
2241 if ((p->type & CUPS_PRINTER_COLLATE))
2242 {
2243 keyvalue[i ][0] = "Collate";
2244 keyvalue[i++][1] = "T";
2245 }
2246
2247 if ((p->type & CUPS_PRINTER_PUNCH))
2248 {
2249 keyvalue[i ][0] = "Punch";
2250 keyvalue[i++][1] = "T";
2251 }
2252
2253 if ((p->type & CUPS_PRINTER_BIND))
2254 {
2255 keyvalue[i ][0] = "Bind";
2256 keyvalue[i++][1] = "T";
2257 }
2258
2259 if ((p->type & CUPS_PRINTER_SORT))
2260 {
2261 keyvalue[i ][0] = "Sort";
2262 keyvalue[i++][1] = "T";
2263 }
2264
2265 keyvalue[i ][0] = "pdl";
2266 keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
2267
2268 if (p->num_auth_info_required)
2269 {
2270 char *air = air_str; /* Pointer into string */
2271
2272
2273 for (j = 0; j < p->num_auth_info_required; j ++)
2274 {
2275 if (air >= (air_str + sizeof(air_str) - 2))
2276 break;
2277
2278 if (j)
2279 *air++ = ',';
2280
2281 strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str));
2282 air += strlen(air);
2283 }
2284
2285 keyvalue[i ][0] = "air";
2286 keyvalue[i++][1] = air;
2287 }
2288
2289 /*
2290 * Then pack them into a proper txt record...
2291 */
2292
2293 return (dnssdPackTxtRecord(txt_len, keyvalue, i));
2294 }
2295
2296
2297 /*
2298 * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
2299 * printer.
2300 */
2301
2302 static void
2303 dnssdDeregisterPrinter(
2304 cupsd_printer_t *p) /* I - Printer */
2305 {
2306 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
2307
2308 /*
2309 * Closing the socket deregisters the service
2310 */
2311
2312 if (p->dnssd_ipp_ref)
2313 {
2314 cupsdRemoveSelect(p->dnssd_ipp_fd);
2315 DNSServiceRefDeallocate(p->dnssd_ipp_ref);
2316 p->dnssd_ipp_ref = NULL;
2317 p->dnssd_ipp_fd = -1;
2318 }
2319
2320 cupsdClearString(&p->reg_name);
2321
2322 if (p->txt_record)
2323 {
2324 /*
2325 * p->txt_record is malloc'd, not _cupsStrAlloc'd...
2326 */
2327
2328 free(p->txt_record);
2329 p->txt_record = NULL;
2330 }
2331 }
2332
2333
2334 /*
2335 * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
2336 * TXT record format.
2337 */
2338
2339 static char * /* O - TXT record */
2340 dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
2341 char *keyvalue[][2], /* I - Table of key value pairs */
2342 int count) /* I - Items in table */
2343 {
2344 int i; /* Looping var */
2345 int length; /* Length of TXT record */
2346 int length2; /* Length of value */
2347 char *txtRecord; /* TXT record buffer */
2348 char *cursor; /* Looping pointer */
2349
2350
2351 /*
2352 * Calculate the buffer size
2353 */
2354
2355 for (length = i = 0; i < count; i++)
2356 length += 1 + strlen(keyvalue[i][0]) +
2357 (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
2358
2359 /*
2360 * Allocate and fill it
2361 */
2362
2363 txtRecord = malloc(length);
2364 if (txtRecord)
2365 {
2366 *txt_len = length;
2367
2368 for (cursor = txtRecord, i = 0; i < count; i++)
2369 {
2370 /*
2371 * Drop in the p-string style length byte followed by the data
2372 */
2373
2374 length = strlen(keyvalue[i][0]);
2375 length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
2376
2377 *cursor++ = (unsigned char)(length + length2);
2378
2379 memcpy(cursor, keyvalue[i][0], length);
2380 cursor += length;
2381
2382 if (length2)
2383 {
2384 length2 --;
2385 *cursor++ = '=';
2386 memcpy(cursor, keyvalue[i][1], length2);
2387 cursor += length2;
2388 }
2389 }
2390 }
2391
2392 return (txtRecord);
2393 }
2394
2395
2396 /*
2397 * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
2398 */
2399
2400 static void
2401 dnssdRegisterCallback(
2402 DNSServiceRef sdRef, /* I - DNS Service reference */
2403 DNSServiceFlags flags, /* I - Reserved for future use */
2404 DNSServiceErrorType errorCode, /* I - Error code */
2405 const char *name, /* I - Service name */
2406 const char *regtype, /* I - Service type */
2407 const char *domain, /* I - Domain. ".local" for now */
2408 void *context) /* I - User-defined context */
2409 {
2410 (void)context;
2411
2412 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2413 "dnssdRegisterCallback(%s, %s)", name, regtype);
2414
2415 if (errorCode)
2416 {
2417 cupsdLogMessage(CUPSD_LOG_ERROR,
2418 "DNSServiceRegister failed with error %d", (int)errorCode);
2419 return;
2420 }
2421 }
2422
2423
2424 /*
2425 * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
2426 * or update the broadcast contents.
2427 */
2428
2429 static void
2430 dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
2431 {
2432 DNSServiceErrorType se; /* dnssd errors */
2433 cupsd_listener_t *lis; /* Current listening socket */
2434 char *txt_record, /* TXT record buffer */
2435 *name; /* Service name */
2436 int txt_len, /* TXT record length */
2437 port; /* IPP port number */
2438 char str_buffer[1024];
2439 /* C-string buffer */
2440 const char *computerName; /* Computer name c-string ptr */
2441 const char *regtype; /* Registration type */
2442 #ifdef HAVE_COREFOUNDATION_H
2443 CFStringRef computerNameRef;/* Computer name CFString */
2444 CFStringEncoding nameEncoding; /* Computer name encoding */
2445 CFMutableStringRef shortNameRef; /* Mutable name string */
2446 CFIndex nameLength; /* Name string length */
2447 #else
2448 int nameLength; /* Name string length */
2449 #endif /* HAVE_COREFOUNDATION_H */
2450
2451
2452 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2453 !p->dnssd_ipp_ref ? "new" : "update");
2454
2455 /*
2456 * If per-printer sharing was just disabled make sure we're not
2457 * registered before returning.
2458 */
2459
2460 if (!p->shared)
2461 {
2462 dnssdDeregisterPrinter(p);
2463 return;
2464 }
2465
2466 /*
2467 * Get the computer name as a c-string...
2468 */
2469
2470 #ifdef HAVE_COREFOUNDATION_H
2471 computerName = NULL;
2472 if ((computerNameRef = SCDynamicStoreCopyComputerName(NULL, &nameEncoding)))
2473 if ((computerName = CFStringGetCStringPtr(computerNameRef,
2474 kCFStringEncodingUTF8)) == NULL)
2475 if (CFStringGetCString(computerNameRef, str_buffer, sizeof(str_buffer),
2476 kCFStringEncodingUTF8))
2477 computerName = str_buffer;
2478 #else
2479 computerName = ServerName;
2480 #endif /* HAVE_COREFOUNDATION_H */
2481
2482 /*
2483 * The registered name takes the form of "<printer-info> @ <computer name>"...
2484 */
2485
2486 name = NULL;
2487 if (computerName)
2488 cupsdSetStringf(&name, "%s @ %s",
2489 (p->info && strlen(p->info)) ? p->info : p->name,
2490 computerName);
2491 else
2492 cupsdSetString(&name, (p->info && strlen(p->info)) ? p->info : p->name);
2493
2494 #ifdef HAVE_COREFOUNDATION_H
2495 if (computerNameRef)
2496 CFRelease(computerNameRef);
2497 #endif /* HAVE_COREFOUNDATION_H */
2498
2499 /*
2500 * If an existing printer was renamed, unregister it and start over...
2501 */
2502
2503 if (p->reg_name && strcmp(p->reg_name, name))
2504 dnssdDeregisterPrinter(p);
2505
2506 txt_len = 0; /* anti-compiler-warning-code */
2507 txt_record = dnssdBuildTxtRecord(&txt_len, p);
2508
2509 if (!p->dnssd_ipp_ref)
2510 {
2511 /*
2512 * Initial registration...
2513 */
2514
2515 cupsdSetString(&p->reg_name, name);
2516
2517 port = ippPort();
2518
2519 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
2520 lis;
2521 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
2522 {
2523 if (lis->address.addr.sa_family == AF_INET)
2524 {
2525 port = ntohs(lis->address.ipv4.sin_port);
2526 break;
2527 }
2528 else if (lis->address.addr.sa_family == AF_INET6)
2529 {
2530 port = ntohs(lis->address.ipv6.sin6_port);
2531 break;
2532 }
2533 }
2534
2535 /*
2536 * Use the _fax subtype for fax queues...
2537 */
2538
2539 regtype = (p->type & CUPS_PRINTER_FAX) ? dnssdIPPFaxRegType :
2540 dnssdIPPRegType;
2541
2542 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) type is \"%s\"",
2543 p->name, regtype);
2544
2545 se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, name, regtype,
2546 NULL, NULL, htons(port), txt_len, txt_record,
2547 dnssdRegisterCallback, p);
2548
2549 /*
2550 * In case the name is too long, try shortening the string one character
2551 * at a time...
2552 */
2553
2554 if (se == kDNSServiceErr_BadParam)
2555 {
2556 #ifdef HAVE_COREFOUNDATION_H
2557 if ((shortNameRef = CFStringCreateMutable(NULL, 0)) != NULL)
2558 {
2559 CFStringAppendCString(shortNameRef, name, kCFStringEncodingUTF8);
2560 nameLength = CFStringGetLength(shortNameRef);
2561
2562 while (se == kDNSServiceErr_BadParam && nameLength > 1)
2563 {
2564 CFStringDelete(shortNameRef, CFRangeMake(--nameLength, 1));
2565 if (CFStringGetCString(shortNameRef, str_buffer, sizeof(str_buffer),
2566 kCFStringEncodingUTF8))
2567 {
2568 se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer,
2569 regtype, NULL, NULL, htons(port),
2570 txt_len, txt_record,
2571 dnssdRegisterCallback, p);
2572 }
2573 }
2574
2575 CFRelease(shortNameRef);
2576 }
2577 #else
2578 nameLength = strlen(name);
2579 while (se == kDNSServiceErr_BadParam && nameLength > 1)
2580 {
2581 name[--nameLength] = '\0';
2582 se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer, regtype,
2583 NULL, NULL, htons(port), txt_len, txt_record,
2584 dnssdRegisterCallback, p);
2585 }
2586 #endif /* HAVE_COREFOUNDATION_H */
2587 }
2588
2589 if (se == kDNSServiceErr_NoError)
2590 {
2591 p->dnssd_ipp_fd = DNSServiceRefSockFD(p->dnssd_ipp_ref);
2592 p->txt_record = txt_record;
2593 p->txt_len = txt_len;
2594 txt_record = NULL;
2595
2596 cupsdAddSelect(p->dnssd_ipp_fd, (cupsd_selfunc_t)cupsdUpdateDNSSDBrowse,
2597 NULL, (void *)p);
2598 }
2599 else
2600 cupsdLogMessage(CUPSD_LOG_WARN,
2601 "DNS-SD registration of \"%s\" failed with %d",
2602 p->name, se);
2603 }
2604 else if (txt_len != p->txt_len || memcmp(txt_record, p->txt_record, txt_len))
2605 {
2606 /*
2607 * Update the existing registration...
2608 */
2609
2610 /* A TTL of 0 means use record's original value (Radar 3176248) */
2611 se = DNSServiceUpdateRecord(p->dnssd_ipp_ref, NULL, 0,
2612 txt_len, txt_record, 0);
2613
2614 if (p->txt_record)
2615 free(p->txt_record);
2616
2617 p->txt_record = txt_record;
2618 p->txt_len = txt_len;
2619 txt_record = NULL;
2620 }
2621
2622 if (txt_record)
2623 free(txt_record);
2624
2625 cupsdClearString(&name);
2626 }
2627 #endif /* HAVE_DNSSD */
2628
2629
2630 /*
2631 * 'process_implicit_classes()' - Create/update implicit classes as needed.
2632 */
2633
2634 static void
2635 process_implicit_classes(void)
2636 {
2637 int i; /* Looping var */
2638 int update; /* Update printer attributes? */
2639 char name[IPP_MAX_NAME], /* Name of printer */
2640 *hptr; /* Pointer into hostname */
2641 cupsd_printer_t *p, /* Printer information */
2642 *pclass, /* Printer class */
2643 *first; /* First printer in class */
2644 int offset, /* Offset of name */
2645 len; /* Length of name */
2646
2647
2648 if (!ImplicitClasses || !Printers)
2649 return;
2650
2651 /*
2652 * Loop through all available printers and create classes as needed...
2653 */
2654
2655 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
2656 update = 0, pclass = NULL, first = NULL;
2657 p != NULL;
2658 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2659 {
2660 /*
2661 * Skip implicit classes...
2662 */
2663
2664 if (p->type & CUPS_PRINTER_IMPLICIT)
2665 {
2666 len = 0;
2667 continue;
2668 }
2669
2670 /*
2671 * If len == 0, get the length of this printer name up to the "@"
2672 * sign (if any).
2673 */
2674
2675 cupsArraySave(Printers);
2676
2677 if (len > 0 &&
2678 !strncasecmp(p->name, name + offset, len) &&
2679 (p->name[len] == '\0' || p->name[len] == '@'))
2680 {
2681 /*
2682 * We have more than one printer with the same name; see if
2683 * we have a class, and if this printer is a member...
2684 */
2685
2686 if (pclass && strcasecmp(pclass->name, name))
2687 {
2688 if (update)
2689 cupsdSetPrinterAttrs(pclass);
2690
2691 update = 0;
2692 pclass = NULL;
2693 }
2694
2695 if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
2696 {
2697 /*
2698 * Need to add the class...
2699 */
2700
2701 pclass = cupsdAddPrinter(name);
2702 cupsArrayAdd(ImplicitPrinters, pclass);
2703
2704 pclass->type |= CUPS_PRINTER_IMPLICIT;
2705 pclass->accepting = 1;
2706 pclass->state = IPP_PRINTER_IDLE;
2707
2708 cupsdSetString(&pclass->location, p->location);
2709 cupsdSetString(&pclass->info, p->info);
2710
2711 cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
2712 cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
2713
2714 update = 1;
2715
2716 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
2717 name);
2718 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
2719 "Implicit class \'%s\' added by directory services.",
2720 name);
2721 }
2722
2723 if (first != NULL)
2724 {
2725 for (i = 0; i < pclass->num_printers; i ++)
2726 if (pclass->printers[i] == first)
2727 break;
2728
2729 if (i >= pclass->num_printers)
2730 {
2731 first->in_implicit_class = 1;
2732 cupsdAddPrinterToClass(pclass, first);
2733 }
2734
2735 first = NULL;
2736 }
2737
2738 for (i = 0; i < pclass->num_printers; i ++)
2739 if (pclass->printers[i] == p)
2740 break;
2741
2742 if (i >= pclass->num_printers)
2743 {
2744 p->in_implicit_class = 1;
2745 cupsdAddPrinterToClass(pclass, p);
2746 update = 1;
2747 }
2748 }
2749 else
2750 {
2751 /*
2752 * First time around; just get name length and mark it as first
2753 * in the list...
2754 */
2755
2756 if ((hptr = strchr(p->name, '@')) != NULL)
2757 len = hptr - p->name;
2758 else
2759 len = strlen(p->name);
2760
2761 strncpy(name, p->name, len);
2762 name[len] = '\0';
2763 offset = 0;
2764
2765 if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
2766 !(first->type & CUPS_PRINTER_IMPLICIT))
2767 {
2768 /*
2769 * Can't use same name as a local printer; add "Any" to the
2770 * front of the name, unless we have explicitly disabled
2771 * the "ImplicitAnyClasses"...
2772 */
2773
2774 if (ImplicitAnyClasses && len < (sizeof(name) - 4))
2775 {
2776 /*
2777 * Add "Any" to the class name...
2778 */
2779
2780 strcpy(name, "Any");
2781 strncpy(name + 3, p->name, len);
2782 name[len + 3] = '\0';
2783 offset = 3;
2784 }
2785 else
2786 {
2787 /*
2788 * Don't create an implicit class if we have a local printer
2789 * with the same name...
2790 */
2791
2792 len = 0;
2793 cupsArrayRestore(Printers);
2794 continue;
2795 }
2796 }
2797
2798 first = p;
2799 }
2800
2801 cupsArrayRestore(Printers);
2802 }
2803
2804 /*
2805 * Update the last printer class as needed...
2806 */
2807
2808 if (pclass && update)
2809 cupsdSetPrinterAttrs(pclass);
2810 }
2811
2812
2813 /*
2814 * 'send_cups_browse()' - Send new browsing information using the CUPS
2815 * protocol.
2816 */
2817
2818 static void
2819 send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */
2820 {
2821 int i; /* Looping var */
2822 cups_ptype_t type; /* Printer type */
2823 cupsd_dirsvc_addr_t *b; /* Browse address */
2824 int bytes; /* Length of packet */
2825 char packet[1453], /* Browse data packet */
2826 uri[1024], /* Printer URI */
2827 location[1024], /* printer-location */
2828 info[1024], /* printer-info */
2829 make_model[1024];
2830 /* printer-make-and-model */
2831 cupsd_netif_t *iface; /* Network interface */
2832
2833
2834 /*
2835 * Figure out the printer type value...
2836 */
2837
2838 type = p->type | CUPS_PRINTER_REMOTE;
2839
2840 if (!p->accepting)
2841 type |= CUPS_PRINTER_REJECTING;
2842
2843 if (p == DefaultPrinter)
2844 type |= CUPS_PRINTER_DEFAULT;
2845
2846 /*
2847 * Remove quotes from printer-info, printer-location, and
2848 * printer-make-and-model attributes...
2849 */
2850
2851 dequote(location, p->location, sizeof(location));
2852 dequote(info, p->info, sizeof(info));
2853
2854 if (p->make_model)
2855 dequote(make_model, p->make_model, sizeof(make_model));
2856 else if (p->type & CUPS_PRINTER_CLASS)
2857 {
2858 if (p->num_printers > 0 && p->printers[0]->make_model)
2859 strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model));
2860 else
2861 strlcpy(make_model, "Local Printer Class", sizeof(make_model));
2862 }
2863 else if (p->raw)
2864 strlcpy(make_model, "Local Raw Printer", sizeof(make_model));
2865 else
2866 strlcpy(make_model, "Local System V Printer", sizeof(make_model));
2867
2868 /*
2869 * Send a packet to each browse address...
2870 */
2871
2872 for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
2873 if (b->iface[0])
2874 {
2875 /*
2876 * Send the browse packet to one or more interfaces...
2877 */
2878
2879 if (!strcmp(b->iface, "*"))
2880 {
2881 /*
2882 * Send to all local interfaces...
2883 */
2884
2885 cupsdNetIFUpdate();
2886
2887 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
2888 iface;
2889 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
2890 {
2891 /*
2892 * Only send to local, IPv4 interfaces...
2893 */
2894
2895 if (!iface->is_local || !iface->port ||
2896 iface->address.addr.sa_family != AF_INET)
2897 continue;
2898
2899 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2900 iface->hostname, iface->port,
2901 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
2902 "/printers/%s",
2903 p->name);
2904 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
2905 type, p->state, uri, location, info, make_model,
2906 p->browse_attrs ? p->browse_attrs : "");
2907
2908 bytes = strlen(packet);
2909
2910 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2911 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
2912 iface->name, packet);
2913
2914 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
2915
2916 sendto(BrowseSocket, packet, bytes, 0,
2917 (struct sockaddr *)&(iface->broadcast),
2918 httpAddrLength(&(iface->broadcast)));
2919 }
2920 }
2921 else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
2922 {
2923 /*
2924 * Send to the named interface using the IPv4 address...
2925 */
2926
2927 while (iface)
2928 if (strcmp(b->iface, iface->name))
2929 {
2930 iface = NULL;
2931 break;
2932 }
2933 else if (iface->address.addr.sa_family == AF_INET && iface->port)
2934 break;
2935 else
2936 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
2937
2938 if (iface)
2939 {
2940 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
2941 iface->hostname, iface->port,
2942 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
2943 "/printers/%s",
2944 p->name);
2945 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
2946 type, p->state, uri, location, info, make_model,
2947 p->browse_attrs ? p->browse_attrs : "");
2948
2949 bytes = strlen(packet);
2950
2951 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2952 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
2953 iface->name, packet);
2954
2955 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
2956
2957 sendto(BrowseSocket, packet, bytes, 0,
2958 (struct sockaddr *)&(iface->broadcast),
2959 httpAddrLength(&(iface->broadcast)));
2960 }
2961 }
2962 }
2963 else
2964 {
2965 /*
2966 * Send the browse packet to the indicated address using
2967 * the default server name...
2968 */
2969
2970 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
2971 type, p->state, p->uri, location, info, make_model,
2972 p->browse_attrs ? p->browse_attrs : "");
2973
2974 bytes = strlen(packet);
2975 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2976 "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
2977
2978 if (sendto(BrowseSocket, packet, bytes, 0,
2979 (struct sockaddr *)&(b->to),
2980 httpAddrLength(&(b->to))) <= 0)
2981 {
2982 /*
2983 * Unable to send browse packet, so remove this address from the
2984 * list...
2985 */
2986
2987 cupsdLogMessage(CUPSD_LOG_ERROR,
2988 "cupsdSendBrowseList: sendto failed for browser "
2989 "%d - %s.",
2990 (int)(b - Browsers + 1), strerror(errno));
2991
2992 if (i > 1)
2993 memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
2994
2995 b --;
2996 NumBrowsers --;
2997 }
2998 }
2999 }
3000
3001
3002 #ifdef HAVE_OPENLDAP
3003 /*
3004 * 'send_ldap_browse()' - Send LDAP printer registrations.
3005 */
3006
3007 static void
3008 send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */
3009 {
3010 int i; /* Looping var... */
3011 LDAPMod mods[7]; /* The 7 attributes we will be adding */
3012 LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
3013 LDAPMessage *res; /* Search result token */
3014 char *cn_value[2], /* Change records */
3015 *uri[2],
3016 *info[2],
3017 *location[2],
3018 *make_model[2],
3019 *type[2],
3020 typestring[255], /* String to hold printer-type */
3021 filter[256], /* Search filter for possible UPDATEs */
3022 dn[1024]; /* DN of the printer we are adding */
3023 int rc; /* LDAP status */
3024 static const char * const objectClass_values[] =
3025 { /* The 3 objectClass's we use in */
3026 "top", /* our LDAP entries */
3027 "device",
3028 "cupsPrinter",
3029 NULL
3030 };
3031
3032 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s\n", p->name);
3033
3034 /*
3035 * Everything in ldap is ** so we fudge around it...
3036 */
3037
3038 sprintf(typestring, "%u", p->type);
3039
3040 cn_value[0] = p->name;
3041 cn_value[1] = NULL;
3042 info[0] = p->info ? p->info : "Unknown";
3043 info[1] = NULL;
3044 location[0] = p->location ? p->location : "Unknown";
3045 location[1] = NULL;
3046 make_model[0] = p->make_model ? p->make_model : "Unknown";
3047 make_model[1] = NULL;
3048 type[0] = typestring;
3049 type[1] = NULL;
3050 uri[0] = p->uri;
3051 uri[1] = NULL;
3052
3053 snprintf(filter, sizeof(filter),
3054 "(&(objectclass=cupsPrinter)(printerURI=%s))", p->uri);
3055
3056 ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
3057 filter, (char **)ldap_attrs, 0, &res);
3058 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: Searching \"%s\"",
3059 filter);
3060
3061 mods[0].mod_type = "cn";
3062 mods[0].mod_values = cn_value;
3063 mods[1].mod_type = "printerDescription";
3064 mods[1].mod_values = info;
3065 mods[2].mod_type = "printerURI";
3066 mods[2].mod_values = uri;
3067 mods[3].mod_type = "printerLocation";
3068 mods[3].mod_values = location;
3069 mods[4].mod_type = "printerMakeAndModel";
3070 mods[4].mod_values = make_model;
3071 mods[5].mod_type = "printerType";
3072 mods[5].mod_values = type;
3073 mods[6].mod_type = "objectClass";
3074 mods[6].mod_values = (char **)objectClass_values;
3075
3076 snprintf(dn, sizeof(dn), "cn=%s,ou=printers,%s", p->name, BrowseLDAPDN);
3077 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
3078
3079 if (ldap_count_entries(BrowseLDAPHandle, res) > 0)
3080 {
3081 /*
3082 * Printer has already been registered, modify the current
3083 * registration...
3084 */
3085
3086 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3087 "send_ldap_browse: Replacing entry...");
3088
3089 for (i = 0; i < 7; i ++)
3090 {
3091 pmods[i] = mods + i;
3092 pmods[i]->mod_op = LDAP_MOD_REPLACE;
3093 }
3094 pmods[i] = NULL;
3095
3096 if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
3097 cupsdLogMessage(CUPSD_LOG_ERROR,
3098 "LDAP modify for %s failed with status %d: %s",
3099 p->name, rc, ldap_err2string(rc));
3100 }
3101 else
3102 {
3103 /*
3104 * Printer has never been registered, add the current
3105 * registration...
3106 */
3107
3108 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3109 "send_ldap_browse: Adding entry...");
3110
3111 for (i = 0; i < 7; i ++)
3112 {
3113 pmods[i] = mods + i;
3114 pmods[i]->mod_op = LDAP_MOD_ADD;
3115 }
3116 pmods[i] = NULL;
3117
3118 if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
3119 cupsdLogMessage(CUPSD_LOG_ERROR,
3120 "LDAP add for %s failed with status %d: %s",
3121 p->name, rc, ldap_err2string(rc));
3122 }
3123 }
3124 #endif /* HAVE_OPENLDAP */
3125
3126
3127 #ifdef HAVE_LIBSLP
3128 /*
3129 * 'send_slp_browse()' - Register the specified printer with SLP.
3130 */
3131
3132 static void
3133 send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */
3134 {
3135 char srvurl[HTTP_MAX_URI], /* Printer service URI */
3136 attrs[8192], /* Printer attributes */
3137 finishings[1024], /* Finishings to support */
3138 make_model[IPP_MAX_NAME * 2],
3139 /* Make and model, quoted */
3140 location[IPP_MAX_NAME * 2],
3141 /* Location, quoted */
3142 info[IPP_MAX_NAME * 2], /* Info, quoted */
3143 *src, /* Pointer to original string */
3144 *dst; /* Pointer to destination string */
3145 ipp_attribute_t *authentication; /* uri-authentication-supported value */
3146 SLPError error; /* SLP error, if any */
3147
3148
3149 cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
3150 p->name);
3151
3152 /*
3153 * Make the SLP service URL that conforms to the IANA
3154 * 'printer:' template.
3155 */
3156
3157 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
3158
3159 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
3160
3161 /*
3162 * Figure out the finishings string...
3163 */
3164
3165 if (p->type & CUPS_PRINTER_STAPLE)
3166 strcpy(finishings, "staple");
3167 else
3168 finishings[0] = '\0';
3169
3170 if (p->type & CUPS_PRINTER_BIND)
3171 {
3172 if (finishings[0])
3173 strlcat(finishings, ",bind", sizeof(finishings));
3174 else
3175 strcpy(finishings, "bind");
3176 }
3177
3178 if (p->type & CUPS_PRINTER_PUNCH)
3179 {
3180 if (finishings[0])
3181 strlcat(finishings, ",punch", sizeof(finishings));
3182 else
3183 strcpy(finishings, "punch");
3184 }
3185
3186 if (p->type & CUPS_PRINTER_COVER)
3187 {
3188 if (finishings[0])
3189 strlcat(finishings, ",cover", sizeof(finishings));
3190 else
3191 strcpy(finishings, "cover");
3192 }
3193
3194 if (p->type & CUPS_PRINTER_SORT)
3195 {
3196 if (finishings[0])
3197 strlcat(finishings, ",sort", sizeof(finishings));
3198 else
3199 strcpy(finishings, "sort");
3200 }
3201
3202 if (!finishings[0])
3203 strcpy(finishings, "none");
3204
3205 /*
3206 * Quote any commas in the make and model, location, and info strings...
3207 */
3208
3209 for (src = p->make_model, dst = make_model;
3210 src && *src && dst < (make_model + sizeof(make_model) - 2);)
3211 {
3212 if (*src == ',' || *src == '\\' || *src == ')')
3213 *dst++ = '\\';
3214
3215 *dst++ = *src++;
3216 }
3217
3218 *dst = '\0';
3219
3220 if (!make_model[0])
3221 strcpy(make_model, "Unknown");
3222
3223 for (src = p->location, dst = location;
3224 src && *src && dst < (location + sizeof(location) - 2);)
3225 {
3226 if (*src == ',' || *src == '\\' || *src == ')')
3227 *dst++ = '\\';
3228
3229 *dst++ = *src++;
3230 }
3231
3232 *dst = '\0';
3233
3234 if (!location[0])
3235 strcpy(location, "Unknown");
3236
3237 for (src = p->info, dst = info;
3238 src && *src && dst < (info + sizeof(info) - 2);)
3239 {
3240 if (*src == ',' || *src == '\\' || *src == ')')
3241 *dst++ = '\\';
3242
3243 *dst++ = *src++;
3244 }
3245
3246 *dst = '\0';
3247
3248 if (!info[0])
3249 strcpy(info, "Unknown");
3250
3251 /*
3252 * Get the authentication value...
3253 */
3254
3255 authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
3256 IPP_TAG_KEYWORD);
3257
3258 /*
3259 * Make the SLP attribute string list that conforms to
3260 * the IANA 'printer:' template.
3261 */
3262
3263 snprintf(attrs, sizeof(attrs),
3264 "(printer-uri-supported=%s),"
3265 "(uri-authentication-supported=%s>),"
3266 #ifdef HAVE_SSL
3267 "(uri-security-supported=tls>),"
3268 #else
3269 "(uri-security-supported=none>),"
3270 #endif /* HAVE_SSL */
3271 "(printer-name=%s),"
3272 "(printer-location=%s),"
3273 "(printer-info=%s),"
3274 "(printer-more-info=%s),"
3275 "(printer-make-and-model=%s),"
3276 "(printer-type=%d),"
3277 "(charset-supported=utf-8),"
3278 "(natural-language-configured=%s),"
3279 "(natural-language-supported=de,en,es,fr,it),"
3280 "(color-supported=%s),"
3281 "(finishings-supported=%s),"
3282 "(sides-supported=one-sided%s),"
3283 "(multiple-document-jobs-supported=true)"
3284 "(ipp-versions-supported=1.0,1.1)",
3285 p->uri, authentication->values[0].string.text, p->name, location,
3286 info, p->uri, make_model, p->type, DefaultLanguage,
3287 p->type & CUPS_PRINTER_COLOR ? "true" : "false",
3288 finishings,
3289 p->type & CUPS_PRINTER_DUPLEX ?
3290 ",two-sided-long-edge,two-sided-short-edge" : "");
3291
3292 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
3293
3294 /*
3295 * Register the printer with the SLP server...
3296 */
3297
3298 error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
3299 SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
3300
3301 if (error != SLP_OK)
3302 cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
3303 error);
3304 }
3305
3306
3307 /*
3308 * 'slp_attr_callback()' - SLP attribute callback
3309 */
3310
3311 static SLPBoolean /* O - SLP_TRUE for success */
3312 slp_attr_callback(
3313 SLPHandle hslp, /* I - SLP handle */
3314 const char *attrlist, /* I - Attribute list */
3315 SLPError errcode, /* I - Parsing status for this attr */
3316 void *cookie) /* I - Current printer */
3317 {
3318 char *tmp = 0; /* Temporary string */
3319 cupsd_printer_t *p = (cupsd_printer_t*)cookie;
3320 /* Current printer */
3321
3322
3323 (void)hslp; /* anti-compiler-warning-code */
3324
3325 /*
3326 * Bail if there was an error
3327 */
3328
3329 if (errcode != SLP_OK)
3330 return (SLP_TRUE);
3331
3332 /*
3333 * Parse the attrlist to obtain things needed to build CUPS browse packet
3334 */
3335
3336 memset(p, 0, sizeof(cupsd_printer_t));
3337
3338 if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
3339 return (SLP_FALSE);
3340 if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
3341 return (SLP_FALSE);
3342 if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
3343 return (SLP_FALSE);
3344 if (!slp_get_attr(attrlist, "(printer-type=", &tmp))
3345 p->type = atoi(tmp);
3346 else
3347 p->type = CUPS_PRINTER_REMOTE;
3348
3349 cupsdClearString(&tmp);
3350
3351 return (SLP_TRUE);
3352 }
3353
3354
3355 /*
3356 * 'slp_dereg_printer()' - SLPDereg() the specified printer
3357 */
3358
3359 static void
3360 slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
3361 {
3362 char srvurl[HTTP_MAX_URI]; /* Printer service URI */
3363
3364
3365 cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
3366
3367 if (!(p->type & CUPS_PRINTER_REMOTE))
3368 {
3369 /*
3370 * Make the SLP service URL that conforms to the IANA
3371 * 'printer:' template.
3372 */
3373
3374 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
3375
3376 /*
3377 * Deregister the printer...
3378 */
3379
3380 SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
3381 }
3382 }
3383
3384
3385 /*
3386 * 'slp_get_attr()' - Get an attribute from an SLP registration.
3387 */
3388
3389 static int /* O - 0 on success */
3390 slp_get_attr(const char *attrlist, /* I - Attribute list string */
3391 const char *tag, /* I - Name of attribute */
3392 char **valbuf) /* O - Value */
3393 {
3394 char *ptr1, /* Pointer into string */
3395 *ptr2; /* ... */
3396
3397
3398 cupsdClearString(valbuf);
3399
3400 if ((ptr1 = strstr(attrlist, tag)) != NULL)
3401 {
3402 ptr1 += strlen(tag);
3403
3404 if ((ptr2 = strchr(ptr1,')')) != NULL)
3405 {
3406 /*
3407 * Copy the value...
3408 */
3409
3410 *valbuf = calloc(ptr2 - ptr1 + 1, 1);
3411 strncpy(*valbuf, ptr1, ptr2 - ptr1);
3412
3413 /*
3414 * Dequote the value...
3415 */
3416
3417 for (ptr1 = *valbuf; *ptr1; ptr1 ++)
3418 if (*ptr1 == '\\' && ptr1[1])
3419 _cups_strcpy(ptr1, ptr1 + 1);
3420
3421 return (0);
3422 }
3423 }
3424
3425 return (-1);
3426 }
3427
3428
3429 /*
3430 * 'slp_reg_callback()' - Empty SLPRegReport.
3431 */
3432
3433 static void
3434 slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
3435 SLPError errcode, /* I - Error code, if any */
3436 void *cookie) /* I - App data */
3437 {
3438 (void)hslp;
3439 (void)errcode;
3440 (void)cookie;
3441
3442 return;
3443 }
3444
3445
3446 /*
3447 * 'slp_url_callback()' - SLP service url callback
3448 */
3449
3450 static SLPBoolean /* O - TRUE = OK, FALSE = error */
3451 slp_url_callback(
3452 SLPHandle hslp, /* I - SLP handle */
3453 const char *srvurl, /* I - URL of service */
3454 unsigned short lifetime, /* I - Life of service */
3455 SLPError errcode, /* I - Existing error code */
3456 void *cookie) /* I - Pointer to service list */
3457 {
3458 slpsrvurl_t *s, /* New service entry */
3459 **head; /* Pointer to head of entry */
3460
3461
3462 /*
3463 * Let the compiler know we won't be using these vars...
3464 */
3465
3466 (void)hslp;
3467 (void)lifetime;
3468
3469 /*
3470 * Bail if there was an error
3471 */
3472
3473 if (errcode != SLP_OK)
3474 return (SLP_TRUE);
3475
3476 /*
3477 * Grab the head of the list...
3478 */
3479
3480 head = (slpsrvurl_t**)cookie;
3481
3482 /*
3483 * Allocate a *temporary* slpsrvurl_t to hold this entry.
3484 */
3485
3486 if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
3487 return (SLP_FALSE);
3488
3489 /*
3490 * Copy the SLP service URL...
3491 */
3492
3493 strlcpy(s->url, srvurl, sizeof(s->url));
3494
3495 /*
3496 * Link the SLP service URL into the head of the list
3497 */
3498
3499 if (*head)
3500 s->next = *head;
3501
3502 *head = s;
3503
3504 return (SLP_TRUE);
3505 }
3506 #endif /* HAVE_LIBSLP */
3507
3508
3509 /*
3510 * 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
3511 */
3512
3513 static void
3514 update_cups_browse(void)
3515 {
3516 int i; /* Looping var */
3517 int auth; /* Authorization status */
3518 int len; /* Length of name string */
3519 int bytes; /* Number of bytes left */
3520 char packet[1541], /* Broadcast packet */
3521 *pptr; /* Pointer into packet */
3522 socklen_t srclen; /* Length of source address */
3523 http_addr_t srcaddr; /* Source address */
3524 char srcname[1024]; /* Source hostname */
3525 unsigned address[4]; /* Source address */
3526 unsigned type; /* Printer type */
3527 unsigned state; /* Printer state */
3528 char uri[HTTP_MAX_URI], /* Printer URI */
3529 host[HTTP_MAX_URI], /* Host portion of URI */
3530 resource[HTTP_MAX_URI], /* Resource portion of URI */
3531 info[IPP_MAX_NAME], /* Information string */
3532 location[IPP_MAX_NAME], /* Location string */
3533 make_model[IPP_MAX_NAME];/* Make and model string */
3534 int num_attrs; /* Number of attributes */
3535 cups_option_t *attrs; /* Attributes */
3536
3537
3538 /*
3539 * Read a packet from the browse socket...
3540 */
3541
3542 srclen = sizeof(srcaddr);
3543 if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
3544 (struct sockaddr *)&srcaddr, &srclen)) < 0)
3545 {
3546 /*
3547 * "Connection refused" is returned under Linux if the destination port
3548 * or address is unreachable from a previous sendto(); check for the
3549 * error here and ignore it for now...
3550 */
3551
3552 if (errno != ECONNREFUSED && errno != EAGAIN)
3553 {
3554 cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
3555 strerror(errno));
3556 cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
3557
3558 cupsdStopBrowsing();
3559 Browsing = 0;
3560 }
3561
3562 return;
3563 }
3564
3565 packet[bytes] = '\0';
3566
3567 /*
3568 * If we're about to sleep, ignore incoming browse packets.
3569 */
3570
3571 if (Sleeping)
3572 return;
3573
3574 /*
3575 * Figure out where it came from...
3576 */
3577
3578 #ifdef AF_INET6
3579 if (srcaddr.addr.sa_family == AF_INET6)
3580 {
3581 address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
3582 address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
3583 address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
3584 address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
3585 }
3586 else
3587 #endif /* AF_INET6 */
3588 {
3589 address[0] = 0;
3590 address[1] = 0;
3591 address[2] = 0;
3592 address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
3593 }
3594
3595 if (HostNameLookups)
3596 httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
3597 else
3598 httpAddrString(&srcaddr, srcname, sizeof(srcname));
3599
3600 len = strlen(srcname);
3601
3602 /*
3603 * Do ACL stuff...
3604 */
3605
3606 if (BrowseACL)
3607 {
3608 if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
3609 {
3610 /*
3611 * Access from localhost (127.0.0.1) is always allowed...
3612 */
3613
3614 auth = AUTH_ALLOW;
3615 }
3616 else
3617 {
3618 /*
3619 * Do authorization checks on the domain/address...
3620 */
3621
3622 switch (BrowseACL->order_type)
3623 {
3624 default :
3625 auth = AUTH_DENY; /* anti-compiler-warning-code */
3626 break;
3627
3628 case AUTH_ALLOW : /* Order Deny,Allow */
3629 auth = AUTH_ALLOW;
3630
3631 if (cupsdCheckAuth(address, srcname, len,
3632 BrowseACL->num_deny, BrowseACL->deny))
3633 auth = AUTH_DENY;
3634
3635 if (cupsdCheckAuth(address, srcname, len,
3636 BrowseACL->num_allow, BrowseACL->allow))
3637 auth = AUTH_ALLOW;
3638 break;
3639
3640 case AUTH_DENY : /* Order Allow,Deny */
3641 auth = AUTH_DENY;
3642
3643 if (cupsdCheckAuth(address, srcname, len,
3644 BrowseACL->num_allow, BrowseACL->allow))
3645 auth = AUTH_ALLOW;
3646
3647 if (cupsdCheckAuth(address, srcname, len,
3648 BrowseACL->num_deny, BrowseACL->deny))
3649 auth = AUTH_DENY;
3650 break;
3651 }
3652 }
3653 }
3654 else
3655 auth = AUTH_ALLOW;
3656
3657 if (auth == AUTH_DENY)
3658 {
3659 cupsdLogMessage(CUPSD_LOG_DEBUG,
3660 "update_cups_browse: Refused %d bytes from %s", bytes,
3661 srcname);
3662 return;
3663 }
3664
3665 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3666 "update_cups_browse: (%d bytes from %s) %s", bytes,
3667 srcname, packet);
3668
3669 /*
3670 * Parse packet...
3671 */
3672
3673 if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
3674 {
3675 cupsdLogMessage(CUPSD_LOG_WARN,
3676 "update_cups_browse: Garbled browse packet - %s", packet);
3677 return;
3678 }
3679
3680 strcpy(location, "Location Unknown");
3681 strcpy(info, "No Information Available");
3682 make_model[0] = '\0';
3683 num_attrs = 0;
3684 attrs = NULL;
3685
3686 if ((pptr = strchr(packet, '\"')) != NULL)
3687 {
3688 /*
3689 * Have extended information; can't use sscanf for it because not all
3690 * sscanf's allow empty strings with %[^\"]...
3691 */
3692
3693 for (i = 0, pptr ++;
3694 i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
3695 i ++, pptr ++)
3696 location[i] = *pptr;
3697
3698 if (i)
3699 location[i] = '\0';
3700
3701 if (*pptr == '\"')
3702 pptr ++;
3703
3704 while (*pptr && isspace(*pptr & 255))
3705 pptr ++;
3706
3707 if (*pptr == '\"')
3708 {
3709 for (i = 0, pptr ++;
3710 i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
3711 i ++, pptr ++)
3712 info[i] = *pptr;
3713
3714 info[i] = '\0';
3715
3716 if (*pptr == '\"')
3717 pptr ++;
3718
3719 while (*pptr && isspace(*pptr & 255))
3720 pptr ++;
3721
3722 if (*pptr == '\"')
3723 {
3724 for (i = 0, pptr ++;
3725 i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
3726 i ++, pptr ++)
3727 make_model[i] = *pptr;
3728
3729 if (*pptr == '\"')
3730 pptr ++;
3731
3732 make_model[i] = '\0';
3733
3734 if (*pptr)
3735 num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
3736 }
3737 }
3738 }
3739
3740 DEBUG_puts(packet);
3741 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
3742 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
3743 type, state, uri, location, info, make_model));
3744
3745 /*
3746 * Pull the URI apart to see if this is a local or remote printer...
3747 */
3748
3749 if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
3750 {
3751 cupsFreeOptions(num_attrs, attrs);
3752 return;
3753 }
3754
3755 /*
3756 * Do relaying...
3757 */
3758
3759 for (i = 0; i < NumRelays; i ++)
3760 if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
3761 if (sendto(BrowseSocket, packet, bytes, 0,
3762 (struct sockaddr *)&(Relays[i].to),
3763 httpAddrLength(&(Relays[i].to))) <= 0)
3764 {
3765 cupsdLogMessage(CUPSD_LOG_ERROR,
3766 "update_cups_browse: sendto failed for relay %d - %s.",
3767 i + 1, strerror(errno));
3768 cupsFreeOptions(num_attrs, attrs);
3769 return;
3770 }
3771
3772 /*
3773 * Process the browse data...
3774 */
3775
3776 process_browse_data(uri, host, resource, (cups_ptype_t)type,
3777 (ipp_pstate_t)state, location, info, make_model,
3778 num_attrs, attrs);
3779 }
3780
3781
3782 /*
3783 * 'update_polling()' - Read status messages from the poll daemons.
3784 */
3785
3786 static void
3787 update_polling(void)
3788 {
3789 char *ptr, /* Pointer to end of line in buffer */
3790 message[1024]; /* Pointer to message text */
3791 int loglevel; /* Log level for message */
3792
3793
3794 while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
3795 message, sizeof(message))) != NULL)
3796 if (!strchr(PollStatusBuffer->buffer, '\n'))
3797 break;
3798
3799 if (ptr == NULL && !PollStatusBuffer->bufused)
3800 {
3801 /*
3802 * All polling processes have died; stop polling...
3803 */
3804
3805 cupsdLogMessage(CUPSD_LOG_ERROR,
3806 "update_polling: all polling processes have exited!");
3807 cupsdStopPolling();
3808 }
3809 }
3810
3811
3812 /*
3813 * End of "$Id: dirsvc.c 6649 2007-07-11 21:46:42Z mike $".
3814 */