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