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