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