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