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