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