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