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