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