]> 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/*
7594b224 2 * "$Id: dirsvc.c 6354 2007-03-19 06:16:32Z 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{
7594b224 2451 int i, j; /* Looping vars */
f7deaa1a 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 */
7594b224 2455 air_str[1024], /* auth-info-required string buffer */
f7deaa1a 2456 *keyvalue[32][2]; /* Table of key/value pairs */
2457
2458
2459 /*
2460 * Load up the key value pairs...
2461 */
2462
2463 i = 0;
2464
2465 keyvalue[i ][0] = "txtvers";
2466 keyvalue[i++][1] = "1";
2467
2468 keyvalue[i ][0] = "qtotal";
2469 keyvalue[i++][1] = "1";
2470
2471 keyvalue[i ][0] = "rp";
2472 keyvalue[i++][1] = rp_str;
2473 snprintf(rp_str, sizeof(rp_str), "%s/%s",
2474 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
2475
2476 keyvalue[i ][0] = "ty";
2477 keyvalue[i++][1] = p->make_model;
2478
2479 if (p->location && *p->location != '\0')
2480 {
2481 keyvalue[i ][0] = "note";
2482 keyvalue[i++][1] = p->location;
2483 }
2484
2485 keyvalue[i ][0] = "product";
2486 keyvalue[i++][1] = p->product ? p->product : "Unknown";
2487
2488 snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
2489 snprintf(state_str, sizeof(state_str), "%d", p->state);
2490
2491 keyvalue[i ][0] = "printer-state";
2492 keyvalue[i++][1] = state_str;
2493
2494 keyvalue[i ][0] = "printer-type";
2495 keyvalue[i++][1] = type_str;
2496
2497 keyvalue[i ][0] = "Transparent";
2498 keyvalue[i++][1] = "T";
2499
2500 keyvalue[i ][0] = "Binary";
2501 keyvalue[i++][1] = "T";
2502
2503 if ((p->type & CUPS_PRINTER_FAX))
2504 {
2505 keyvalue[i ][0] = "Fax";
2506 keyvalue[i++][1] = "T";
2507 }
2508
2509 if ((p->type & CUPS_PRINTER_COLOR))
2510 {
2511 keyvalue[i ][0] = "Color";
2512 keyvalue[i++][1] = "T";
2513 }
2514
2515 if ((p->type & CUPS_PRINTER_DUPLEX))
2516 {
2517 keyvalue[i ][0] = "Duplex";
2518 keyvalue[i++][1] = "T";
2519 }
2520
2521 if ((p->type & CUPS_PRINTER_STAPLE))
2522 {
2523 keyvalue[i ][0] = "Staple";
2524 keyvalue[i++][1] = "T";
2525 }
2526
2527 if ((p->type & CUPS_PRINTER_COPIES))
2528 {
2529 keyvalue[i ][0] = "Copies";
2530 keyvalue[i++][1] = "T";
2531 }
2532
2533 if ((p->type & CUPS_PRINTER_COLLATE))
2534 {
2535 keyvalue[i ][0] = "Collate";
2536 keyvalue[i++][1] = "T";
2537 }
2538
2539 if ((p->type & CUPS_PRINTER_PUNCH))
2540 {
2541 keyvalue[i ][0] = "Punch";
2542 keyvalue[i++][1] = "T";
2543 }
2544
2545 if ((p->type & CUPS_PRINTER_BIND))
2546 {
2547 keyvalue[i ][0] = "Bind";
2548 keyvalue[i++][1] = "T";
2549 }
2550
2551 if ((p->type & CUPS_PRINTER_SORT))
2552 {
2553 keyvalue[i ][0] = "Sort";
2554 keyvalue[i++][1] = "T";
2555 }
2556
2557 keyvalue[i ][0] = "pdl";
2558 keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
2559
7594b224 2560 if (p->num_auth_info_required)
2561 {
2562 char *air = air_str; /* Pointer into string */
2563
2564
2565 for (j = 0; j < p->num_auth_info_required; j ++)
2566 {
2567 if (air >= (air_str + sizeof(air_str) - 2))
2568 break;
2569
2570 if (j)
2571 *air++ = ',';
2572
2573 strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str));
2574 air += strlen(air);
2575 }
2576
2577 keyvalue[i ][0] = "air";
2578 keyvalue[i++][1] = air;
2579 }
2580
f7deaa1a 2581 /*
2582 * Then pack them into a proper txt record...
2583 */
2584
2585 return (dnssdPackTxtRecord(txt_len, keyvalue, i));
2586}
2587
2588
2589/*
2590 * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
2591 * printer.
2592 */
2593
2594static void
2595dnssdDeregisterPrinter(
2596 cupsd_printer_t *p) /* I - Printer */
2597{
2598 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
2599
2600 /*
2601 * Closing the socket deregisters the service
2602 */
2603
2604 if (p->dnssd_ipp_ref)
2605 {
2606 cupsdRemoveSelect(p->dnssd_ipp_fd);
2607 DNSServiceRefDeallocate(p->dnssd_ipp_ref);
2608 p->dnssd_ipp_ref = NULL;
2609 p->dnssd_ipp_fd = -1;
2610 }
2611
2612 cupsdClearString(&p->reg_name);
2613
2614 if (p->txt_record)
2615 {
2616 /*
2617 * p->txt_record is malloc'd, not _cupsStrAlloc'd...
2618 */
2619
2620 free(p->txt_record);
2621 p->txt_record = NULL;
2622 }
2623}
2624
2625
2626/*
2627 * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
2628 * TXT record format.
2629 */
2630
2631static char * /* O - TXT record */
2632dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
2633 char *keyvalue[][2], /* I - Table of key value pairs */
2634 int count) /* I - Items in table */
2635{
2636 int i; /* Looping var */
2637 int length; /* Length of TXT record */
2638 int length2; /* Length of value */
2639 char *txtRecord; /* TXT record buffer */
2640 char *cursor; /* Looping pointer */
2641
2642
2643 /*
2644 * Calculate the buffer size
2645 */
2646
2647 for (length = i = 0; i < count; i++)
2648 length += 1 + strlen(keyvalue[i][0]) +
2649 (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
2650
2651 /*
2652 * Allocate and fill it
2653 */
2654
2655 txtRecord = malloc(length);
2656 if (txtRecord)
2657 {
2658 *txt_len = length;
2659
2660 for (cursor = txtRecord, i = 0; i < count; i++)
2661 {
2662 /*
2663 * Drop in the p-string style length byte followed by the data
2664 */
2665
2666 length = strlen(keyvalue[i][0]);
2667 length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
2668
2669 *cursor++ = (unsigned char)(length + length2);
2670
2671 memcpy(cursor, keyvalue[i][0], length);
2672 cursor += length;
2673
2674 if (length2)
2675 {
2676 length2 --;
2677 *cursor++ = '=';
2678 memcpy(cursor, keyvalue[i][1], length2);
2679 cursor += length2;
2680 }
2681 }
2682 }
2683
2684 return (txtRecord);
2685}
2686
2687
2688/*
2689 * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
2690 */
2691
2692static void
2693dnssdRegisterCallback(
2694 DNSServiceRef sdRef, /* I - DNS Service reference */
2695 DNSServiceFlags flags, /* I - Reserved for future use */
2696 DNSServiceErrorType errorCode, /* I - Error code */
2697 const char *name, /* I - Service name */
2698 const char *regtype, /* I - Service type */
2699 const char *domain, /* I - Domain. ".local" for now */
2700 void *context) /* I - User-defined context */
2701{
2702 (void)context;
2703
2704 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2705 "dnssdRegisterCallback(%s, %s)", name, regtype);
2706
2707 if (errorCode)
2708 {
2709 cupsdLogMessage(CUPSD_LOG_ERROR,
2710 "DNSServiceRegister failed with error %d", (int)errorCode);
2711 return;
2712 }
2713}
2714
2715
2716/*
2717 * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
2718 * or update the broadcast contents.
2719 */
2720
2721static void
2722dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
2723{
2724 DNSServiceErrorType se; /* dnssd errors */
2725 cupsd_listener_t *lis; /* Current listening socket */
2726 char *txt_record, /* TXT record buffer */
2727 *name; /* Service name */
2728 int txt_len, /* TXT record length */
2729 port; /* IPP port number */
2730 char str_buffer[1024];
2731 /* C-string buffer */
2732 const char *computerName; /* Computer name c-string ptr */
2733 const char *regtype; /* Registration type */
2734#ifdef HAVE_COREFOUNDATION_H
2735 CFStringRef computerNameRef;/* Computer name CFString */
2736 CFStringEncoding nameEncoding; /* Computer name encoding */
2737 CFMutableStringRef shortNameRef; /* Mutable name string */
2738 CFIndex nameLength; /* Name string length */
2739#else
2740 int nameLength; /* Name string length */
2741#endif /* HAVE_COREFOUNDATION_H */
2742
2743
2744 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2745 !p->dnssd_ipp_ref ? "new" : "update");
2746
2747 /*
2748 * If per-printer sharing was just disabled make sure we're not
2749 * registered before returning.
2750 */
2751
2752 if (!p->shared)
2753 {
2754 dnssdDeregisterPrinter(p);
2755 return;
2756 }
2757
2758 /*
2759 * Get the computer name as a c-string...
2760 */
2761
2762#ifdef HAVE_COREFOUNDATION_H
2763 computerName = NULL;
2764 if ((computerNameRef = SCDynamicStoreCopyComputerName(NULL, &nameEncoding)))
2765 if ((computerName = CFStringGetCStringPtr(computerNameRef,
2766 kCFStringEncodingUTF8)) == NULL)
2767 if (CFStringGetCString(computerNameRef, str_buffer, sizeof(str_buffer),
2768 kCFStringEncodingUTF8))
2769 computerName = str_buffer;
2770#else
2771 computerName = ServerName;
2772#endif /* HAVE_COREFOUNDATION_H */
2773
2774 /*
2775 * The registered name takes the form of "<printer-info> @ <computer name>"...
2776 */
2777
2778 name = NULL;
2779 if (computerName)
2780 cupsdSetStringf(&name, "%s @ %s",
2781 (p->info && strlen(p->info)) ? p->info : p->name,
2782 computerName);
2783 else
2784 cupsdSetString(&name, (p->info && strlen(p->info)) ? p->info : p->name);
2785
2786#ifdef HAVE_COREFOUNDATION_H
2787 if (computerNameRef)
2788 CFRelease(computerNameRef);
2789#endif /* HAVE_COREFOUNDATION_H */
2790
2791 /*
2792 * If an existing printer was renamed, unregister it and start over...
2793 */
2794
2795 if (p->reg_name && strcmp(p->reg_name, name))
2796 dnssdDeregisterPrinter(p);
2797
2798 txt_len = 0; /* anti-compiler-warning-code */
2799 txt_record = dnssdBuildTxtRecord(&txt_len, p);
2800
2801 if (!p->dnssd_ipp_ref)
2802 {
2803 /*
2804 * Initial registration...
2805 */
2806
2807 cupsdSetString(&p->reg_name, name);
2808
2809 port = ippPort();
2810
2811 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
2812 lis;
2813 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
2814 {
2815 if (lis->address.addr.sa_family == AF_INET)
2816 {
2817 port = ntohs(lis->address.ipv4.sin_port);
2818 break;
2819 }
2820 else if (lis->address.addr.sa_family == AF_INET6)
2821 {
2822 port = ntohs(lis->address.ipv6.sin6_port);
2823 break;
2824 }
2825 }
2826
2827 /*
2828 * Use the _fax subtype for fax queues...
2829 */
2830
2831 regtype = (p->type & CUPS_PRINTER_FAX) ? dnssdIPPFaxRegType :
2832 dnssdIPPRegType;
2833
2834 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) type is \"%s\"",
2835 p->name, regtype);
2836
2837 se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, name, regtype,
2838 NULL, NULL, htons(port), txt_len, txt_record,
2839 dnssdRegisterCallback, p);
2840
2841 /*
2842 * In case the name is too long, try shortening the string one character
2843 * at a time...
2844 */
2845
2846 if (se == kDNSServiceErr_BadParam)
2847 {
2848#ifdef HAVE_COREFOUNDATION_H
2849 if ((shortNameRef = CFStringCreateMutable(NULL, 0)) != NULL)
2850 {
2851 CFStringAppendCString(shortNameRef, name, kCFStringEncodingUTF8);
2852 nameLength = CFStringGetLength(shortNameRef);
2853
2854 while (se == kDNSServiceErr_BadParam && nameLength > 1)
2855 {
2856 CFStringDelete(shortNameRef, CFRangeMake(--nameLength, 1));
2857 if (CFStringGetCString(shortNameRef, str_buffer, sizeof(str_buffer),
2858 kCFStringEncodingUTF8))
2859 {
2860 se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer,
2861 regtype, NULL, NULL, htons(port),
2862 txt_len, txt_record,
2863 dnssdRegisterCallback, p);
2864 }
2865 }
2866
2867 CFRelease(shortNameRef);
2868 }
2869#else
2870 nameLength = strlen(name);
2871 while (se == kDNSServiceErr_BadParam && nameLength > 1)
2872 {
2873 name[--nameLength] = '\0';
2874 se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer, regtype,
2875 NULL, NULL, htons(port), txt_len, txt_record,
2876 dnssdRegisterCallback, p);
2877 }
2878#endif /* HAVE_COREFOUNDATION_H */
2879 }
2880
2881 if (se == kDNSServiceErr_NoError)
2882 {
2883 p->dnssd_ipp_fd = DNSServiceRefSockFD(p->dnssd_ipp_ref);
2884 p->txt_record = txt_record;
2885 p->txt_len = txt_len;
2886 txt_record = NULL;
2887
2888 cupsdAddSelect(p->dnssd_ipp_fd, (cupsd_selfunc_t)cupsdUpdateDNSSDBrowse,
2889 NULL, (void *)p);
2890 }
2891 else
2892 cupsdLogMessage(CUPSD_LOG_WARN,
2893 "DNS-SD registration of \"%s\" failed with %d",
2894 p->name, se);
2895 }
2896 else if (txt_len != p->txt_len || memcmp(txt_record, p->txt_record, txt_len))
2897 {
2898 /*
2899 * Update the existing registration...
2900 */
2901
2902 /* A TTL of 0 means use record's original value (Radar 3176248) */
2903 se = DNSServiceUpdateRecord(p->dnssd_ipp_ref, NULL, 0,
2904 txt_len, txt_record, 0);
2905
2906 if (p->txt_record)
2907 free(p->txt_record);
2908
2909 p->txt_record = txt_record;
2910 p->txt_len = txt_len;
2911 txt_record = NULL;
2912 }
2913
2914 if (txt_record)
2915 free(txt_record);
2916
2917 cupsdClearString(&name);
2918}
2919#endif /* HAVE_DNSSD */
2920
2921
ef416fc2 2922/*
e00b005a 2923 * 'process_implicit_classes()' - Create/update implicit classes as needed.
ef416fc2 2924 */
2925
e00b005a 2926static void
2927process_implicit_classes(void)
ef416fc2 2928{
e00b005a 2929 int i; /* Looping var */
2930 int update; /* Update printer attributes? */
2931 char name[IPP_MAX_NAME], /* Name of printer */
2932 *hptr; /* Pointer into hostname */
2933 cupsd_printer_t *p, /* Printer information */
2934 *pclass, /* Printer class */
2935 *first; /* First printer in class */
2936 int offset, /* Offset of name */
2937 len; /* Length of name */
ef416fc2 2938
2939
e00b005a 2940 if (!ImplicitClasses || !Printers)
2941 return;
ef416fc2 2942
e00b005a 2943 /*
2944 * Loop through all available printers and create classes as needed...
2945 */
2946
2947 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
2948 update = 0, pclass = NULL, first = NULL;
2949 p != NULL;
2950 p = (cupsd_printer_t *)cupsArrayNext(Printers))
ef416fc2 2951 {
2952 /*
e00b005a 2953 * Skip implicit classes...
ef416fc2 2954 */
2955
e00b005a 2956 if (p->type & CUPS_PRINTER_IMPLICIT)
2957 {
2958 len = 0;
2959 continue;
2960 }
ef416fc2 2961
e00b005a 2962 /*
2963 * If len == 0, get the length of this printer name up to the "@"
2964 * sign (if any).
2965 */
ef416fc2 2966
e00b005a 2967 cupsArraySave(Printers);
ef416fc2 2968
e00b005a 2969 if (len > 0 &&
2970 !strncasecmp(p->name, name + offset, len) &&
2971 (p->name[len] == '\0' || p->name[len] == '@'))
2972 {
2973 /*
2974 * We have more than one printer with the same name; see if
2975 * we have a class, and if this printer is a member...
2976 */
ef416fc2 2977
e00b005a 2978 if (pclass && strcasecmp(pclass->name, name))
2979 {
2980 if (update)
2981 cupsdSetPrinterAttrs(pclass);
ef416fc2 2982
e00b005a 2983 update = 0;
2984 pclass = NULL;
2985 }
ef416fc2 2986
e00b005a 2987 if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
2988 {
2989 /*
2990 * Need to add the class...
2991 */
ef416fc2 2992
e00b005a 2993 pclass = cupsdAddPrinter(name);
2994 cupsArrayAdd(ImplicitPrinters, pclass);
ef416fc2 2995
e00b005a 2996 pclass->type |= CUPS_PRINTER_IMPLICIT;
2997 pclass->accepting = 1;
2998 pclass->state = IPP_PRINTER_IDLE;
ef416fc2 2999
e00b005a 3000 cupsdSetString(&pclass->location, p->location);
3001 cupsdSetString(&pclass->info, p->info);
ef416fc2 3002
7594b224 3003 cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
3004 cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
3005
e00b005a 3006 update = 1;
ef416fc2 3007
89d46774 3008 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
e00b005a 3009 name);
b423cd4c 3010 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3011 "Implicit class \'%s\' added by directory services.",
3012 name);
e00b005a 3013 }
ef416fc2 3014
e00b005a 3015 if (first != NULL)
3016 {
3017 for (i = 0; i < pclass->num_printers; i ++)
3018 if (pclass->printers[i] == first)
3019 break;
ef416fc2 3020
e00b005a 3021 if (i >= pclass->num_printers)
3022 {
3023 first->in_implicit_class = 1;
3024 cupsdAddPrinterToClass(pclass, first);
3025 }
ef416fc2 3026
e00b005a 3027 first = NULL;
3028 }
ef416fc2 3029
e00b005a 3030 for (i = 0; i < pclass->num_printers; i ++)
3031 if (pclass->printers[i] == p)
3032 break;
ef416fc2 3033
e00b005a 3034 if (i >= pclass->num_printers)
3035 {
3036 p->in_implicit_class = 1;
3037 cupsdAddPrinterToClass(pclass, p);
3038 update = 1;
3039 }
3040 }
3041 else
ef416fc2 3042 {
3043 /*
e00b005a 3044 * First time around; just get name length and mark it as first
3045 * in the list...
ef416fc2 3046 */
3047
e00b005a 3048 if ((hptr = strchr(p->name, '@')) != NULL)
3049 len = hptr - p->name;
3050 else
3051 len = strlen(p->name);
ef416fc2 3052
e00b005a 3053 strncpy(name, p->name, len);
3054 name[len] = '\0';
3055 offset = 0;
ef416fc2 3056
e00b005a 3057 if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
3058 !(first->type & CUPS_PRINTER_IMPLICIT))
3059 {
3060 /*
3061 * Can't use same name as a local printer; add "Any" to the
3062 * front of the name, unless we have explicitly disabled
3063 * the "ImplicitAnyClasses"...
3064 */
ef416fc2 3065
e00b005a 3066 if (ImplicitAnyClasses && len < (sizeof(name) - 4))
3067 {
3068 /*
3069 * Add "Any" to the class name...
3070 */
3071
3072 strcpy(name, "Any");
3073 strncpy(name + 3, p->name, len);
3074 name[len + 3] = '\0';
3075 offset = 3;
3076 }
3077 else
3078 {
3079 /*
3080 * Don't create an implicit class if we have a local printer
3081 * with the same name...
3082 */
3083
3084 len = 0;
3085 cupsArrayRestore(Printers);
3086 continue;
3087 }
3088 }
3089
3090 first = p;
ef416fc2 3091 }
3092
e00b005a 3093 cupsArrayRestore(Printers);
3094 }
ef416fc2 3095
e00b005a 3096 /*
3097 * Update the last printer class as needed...
3098 */
ef416fc2 3099
e00b005a 3100 if (pclass && update)
3101 cupsdSetPrinterAttrs(pclass);
ef416fc2 3102}
3103
3104
e1d6a774 3105/*
3106 * 'send_cups_browse()' - Send new browsing information using the CUPS
7594b224 3107 * protocol.
e1d6a774 3108 */
3109
3110static void
3111send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */
3112{
3113 int i; /* Looping var */
3114 cups_ptype_t type; /* Printer type */
3115 cupsd_dirsvc_addr_t *b; /* Browse address */
3116 int bytes; /* Length of packet */
3117 char packet[1453], /* Browse data packet */
3118 uri[1024], /* Printer URI */
3119 location[1024], /* printer-location */
3120 info[1024], /* printer-info */
3121 make_model[1024];
3122 /* printer-make-and-model */
3123 cupsd_netif_t *iface; /* Network interface */
3124
3125
3126 /*
3127 * Figure out the printer type value...
3128 */
3129
3130 type = p->type | CUPS_PRINTER_REMOTE;
3131
3132 if (!p->accepting)
3133 type |= CUPS_PRINTER_REJECTING;
3134
3135 if (p == DefaultPrinter)
3136 type |= CUPS_PRINTER_DEFAULT;
3137
3138 /*
3139 * Remove quotes from printer-info, printer-location, and
3140 * printer-make-and-model attributes...
3141 */
3142
3143 dequote(location, p->location, sizeof(location));
3144 dequote(info, p->info, sizeof(info));
d6ae789d 3145
3146 if (p->make_model)
3147 dequote(make_model, p->make_model, sizeof(make_model));
3148 else if (p->type & CUPS_PRINTER_CLASS)
3149 {
3150 if (p->num_printers > 0 && p->printers[0]->make_model)
3151 strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model));
3152 else
3153 strlcpy(make_model, "Local Printer Class", sizeof(make_model));
3154 }
3155 else if (p->raw)
3156 strlcpy(make_model, "Local Raw Printer", sizeof(make_model));
3157 else
3158 strlcpy(make_model, "Local System V Printer", sizeof(make_model));
e1d6a774 3159
3160 /*
3161 * Send a packet to each browse address...
3162 */
3163
3164 for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
3165 if (b->iface[0])
3166 {
3167 /*
3168 * Send the browse packet to one or more interfaces...
3169 */
3170
3171 if (!strcmp(b->iface, "*"))
3172 {
3173 /*
3174 * Send to all local interfaces...
3175 */
3176
3177 cupsdNetIFUpdate();
3178
3179 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
3180 iface;
3181 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
3182 {
3183 /*
3184 * Only send to local, IPv4 interfaces...
3185 */
3186
3187 if (!iface->is_local || !iface->port ||
3188 iface->address.addr.sa_family != AF_INET)
3189 continue;
3190
3191 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3192 iface->hostname, iface->port,
ed486911 3193 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
e1d6a774 3194 "/printers/%s",
3195 p->name);
3196 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3197 type, p->state, uri, location, info, make_model,
3198 p->browse_attrs ? p->browse_attrs : "");
3199
3200 bytes = strlen(packet);
3201
3202 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3203 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
3204 iface->name, packet);
3205
3206 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
3207
3208 sendto(BrowseSocket, packet, bytes, 0,
3209 (struct sockaddr *)&(iface->broadcast),
d09495fa 3210 httpAddrLength(&(iface->broadcast)));
e1d6a774 3211 }
3212 }
3213 else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
3214 {
3215 /*
3216 * Send to the named interface using the IPv4 address...
3217 */
3218
3219 while (iface)
3220 if (strcmp(b->iface, iface->name))
3221 {
3222 iface = NULL;
3223 break;
3224 }
3225 else if (iface->address.addr.sa_family == AF_INET && iface->port)
3226 break;
3227 else
3228 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
3229
3230 if (iface)
3231 {
3232 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3233 iface->hostname, iface->port,
3234 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" :
3235 "/printers/%s",
3236 p->name);
3237 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3238 type, p->state, uri, location, info, make_model,
3239 p->browse_attrs ? p->browse_attrs : "");
3240
3241 bytes = strlen(packet);
3242
3243 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3244 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
3245 iface->name, packet);
3246
3247 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
3248
3249 sendto(BrowseSocket, packet, bytes, 0,
3250 (struct sockaddr *)&(iface->broadcast),
d09495fa 3251 httpAddrLength(&(iface->broadcast)));
e1d6a774 3252 }
3253 }
3254 }
3255 else
3256 {
3257 /*
3258 * Send the browse packet to the indicated address using
3259 * the default server name...
3260 */
3261
3262 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3263 type, p->state, p->uri, location, info, make_model,
3264 p->browse_attrs ? p->browse_attrs : "");
3265
3266 bytes = strlen(packet);
3267 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3268 "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
3269
3270 if (sendto(BrowseSocket, packet, bytes, 0,
3271 (struct sockaddr *)&(b->to),
d09495fa 3272 httpAddrLength(&(b->to))) <= 0)
e1d6a774 3273 {
3274 /*
3275 * Unable to send browse packet, so remove this address from the
3276 * list...
3277 */
3278
3279 cupsdLogMessage(CUPSD_LOG_ERROR,
3280 "cupsdSendBrowseList: sendto failed for browser "
3281 "%d - %s.",
3282 (int)(b - Browsers + 1), strerror(errno));
3283
3284 if (i > 1)
3285 memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
3286
3287 b --;
3288 NumBrowsers --;
3289 }
3290 }
3291}
3292
3293
3294#ifdef HAVE_OPENLDAP
3295/*
3296 * 'send_ldap_browse()' - Send LDAP printer registrations.
3297 */
3298
3299static void
3300send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */
3301{
3302 int i; /* Looping var... */
3303 LDAPMod mods[7]; /* The 7 attributes we will be adding */
3304 LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
3305 LDAPMessage *res; /* Search result token */
3306 char *cn_value[2], /* Change records */
3307 *uri[2],
3308 *info[2],
3309 *location[2],
3310 *make_model[2],
3311 *type[2],
3312 typestring[255], /* String to hold printer-type */
3313 filter[256], /* Search filter for possible UPDATEs */
3314 dn[1024]; /* DN of the printer we are adding */
3315 int rc; /* LDAP status */
3316 static const char * const objectClass_values[] =
3317 { /* The 3 objectClass's we use in */
3318 "top", /* our LDAP entries */
3319 "device",
3320 "cupsPrinter",
3321 NULL
3322 };
3323
3324 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s\n", p->name);
3325
3326 /*
3327 * Everything in ldap is ** so we fudge around it...
3328 */
3329
3330 sprintf(typestring, "%u", p->type);
3331
ed486911 3332 cn_value[0] = p->name;
e1d6a774 3333 cn_value[1] = NULL;
ed486911 3334 info[0] = p->info ? p->info : "Unknown";
e1d6a774 3335 info[1] = NULL;
ed486911 3336 location[0] = p->location ? p->location : "Unknown";
e1d6a774 3337 location[1] = NULL;
ed486911 3338 make_model[0] = p->make_model ? p->make_model : "Unknown";
e1d6a774 3339 make_model[1] = NULL;
3340 type[0] = typestring;
3341 type[1] = NULL;
3342 uri[0] = p->uri;
3343 uri[1] = NULL;
3344
3345 snprintf(filter, sizeof(filter),
ed486911 3346 "(&(objectclass=cupsPrinter)(printerURI=%s))", p->uri);
e1d6a774 3347
3348 ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
3349 filter, (char **)ldap_attrs, 0, &res);
3350 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: Searching \"%s\"",
3351 filter);
3352
3353 mods[0].mod_type = "cn";
3354 mods[0].mod_values = cn_value;
3355 mods[1].mod_type = "printerDescription";
3356 mods[1].mod_values = info;
3357 mods[2].mod_type = "printerURI";
3358 mods[2].mod_values = uri;
3359 mods[3].mod_type = "printerLocation";
3360 mods[3].mod_values = location;
3361 mods[4].mod_type = "printerMakeAndModel";
3362 mods[4].mod_values = make_model;
3363 mods[5].mod_type = "printerType";
3364 mods[5].mod_values = type;
3365 mods[6].mod_type = "objectClass";
3366 mods[6].mod_values = (char **)objectClass_values;
3367
ed486911 3368 snprintf(dn, sizeof(dn), "cn=%s,ou=printers,%s", p->name, BrowseLDAPDN);
e1d6a774 3369 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
3370
3371 if (ldap_count_entries(BrowseLDAPHandle, res) > 0)
3372 {
3373 /*
3374 * Printer has already been registered, modify the current
3375 * registration...
3376 */
3377
3378 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3379 "send_ldap_browse: Replacing entry...");
3380
3381 for (i = 0; i < 7; i ++)
3382 {
3383 pmods[i] = mods + i;
3384 pmods[i]->mod_op = LDAP_MOD_REPLACE;
3385 }
3386 pmods[i] = NULL;
3387
3388 if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
3389 cupsdLogMessage(CUPSD_LOG_ERROR,
3390 "LDAP modify for %s failed with status %d: %s",
3391 p->name, rc, ldap_err2string(rc));
3392 }
3393 else
3394 {
3395 /*
ed486911 3396 * Printer has never been registered, add the current
e1d6a774 3397 * registration...
3398 */
3399
3400 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3401 "send_ldap_browse: Adding entry...");
3402
3403 for (i = 0; i < 7; i ++)
3404 {
3405 pmods[i] = mods + i;
ed486911 3406 pmods[i]->mod_op = LDAP_MOD_ADD;
e1d6a774 3407 }
3408 pmods[i] = NULL;
3409
ed486911 3410 if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
e1d6a774 3411 cupsdLogMessage(CUPSD_LOG_ERROR,
3412 "LDAP add for %s failed with status %d: %s",
3413 p->name, rc, ldap_err2string(rc));
3414 }
3415}
3416#endif /* HAVE_OPENLDAP */
3417
3418
3419#ifdef HAVE_LIBSLP
3420/*
3421 * 'send_slp_browse()' - Register the specified printer with SLP.
3422 */
3423
3424static void
3425send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */
3426{
3427 char srvurl[HTTP_MAX_URI], /* Printer service URI */
3428 attrs[8192], /* Printer attributes */
3429 finishings[1024], /* Finishings to support */
3430 make_model[IPP_MAX_NAME * 2],
3431 /* Make and model, quoted */
3432 location[IPP_MAX_NAME * 2],
3433 /* Location, quoted */
3434 info[IPP_MAX_NAME * 2], /* Info, quoted */
3435 *src, /* Pointer to original string */
3436 *dst; /* Pointer to destination string */
3437 ipp_attribute_t *authentication; /* uri-authentication-supported value */
3438 SLPError error; /* SLP error, if any */
3439
3440
3441 cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
3442 p->name);
3443
3444 /*
3445 * Make the SLP service URL that conforms to the IANA
3446 * 'printer:' template.
3447 */
3448
3449 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
3450
3451 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
3452
3453 /*
3454 * Figure out the finishings string...
3455 */
3456
3457 if (p->type & CUPS_PRINTER_STAPLE)
3458 strcpy(finishings, "staple");
3459 else
3460 finishings[0] = '\0';
3461
3462 if (p->type & CUPS_PRINTER_BIND)
3463 {
3464 if (finishings[0])
3465 strlcat(finishings, ",bind", sizeof(finishings));
3466 else
3467 strcpy(finishings, "bind");
3468 }
3469
3470 if (p->type & CUPS_PRINTER_PUNCH)
3471 {
3472 if (finishings[0])
3473 strlcat(finishings, ",punch", sizeof(finishings));
3474 else
3475 strcpy(finishings, "punch");
3476 }
3477
3478 if (p->type & CUPS_PRINTER_COVER)
3479 {
3480 if (finishings[0])
3481 strlcat(finishings, ",cover", sizeof(finishings));
3482 else
3483 strcpy(finishings, "cover");
3484 }
3485
3486 if (p->type & CUPS_PRINTER_SORT)
3487 {
3488 if (finishings[0])
3489 strlcat(finishings, ",sort", sizeof(finishings));
3490 else
3491 strcpy(finishings, "sort");
3492 }
3493
3494 if (!finishings[0])
3495 strcpy(finishings, "none");
3496
3497 /*
3498 * Quote any commas in the make and model, location, and info strings...
3499 */
3500
3501 for (src = p->make_model, dst = make_model;
3502 src && *src && dst < (make_model + sizeof(make_model) - 2);)
3503 {
3504 if (*src == ',' || *src == '\\' || *src == ')')
3505 *dst++ = '\\';
3506
3507 *dst++ = *src++;
3508 }
3509
3510 *dst = '\0';
3511
3512 if (!make_model[0])
3513 strcpy(make_model, "Unknown");
3514
3515 for (src = p->location, dst = location;
3516 src && *src && dst < (location + sizeof(location) - 2);)
3517 {
3518 if (*src == ',' || *src == '\\' || *src == ')')
3519 *dst++ = '\\';
3520
3521 *dst++ = *src++;
3522 }
3523
3524 *dst = '\0';
3525
3526 if (!location[0])
3527 strcpy(location, "Unknown");
3528
3529 for (src = p->info, dst = info;
3530 src && *src && dst < (info + sizeof(info) - 2);)
3531 {
3532 if (*src == ',' || *src == '\\' || *src == ')')
3533 *dst++ = '\\';
3534
3535 *dst++ = *src++;
3536 }
3537
3538 *dst = '\0';
3539
3540 if (!info[0])
3541 strcpy(info, "Unknown");
3542
3543 /*
3544 * Get the authentication value...
3545 */
3546
3547 authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
3548 IPP_TAG_KEYWORD);
3549
3550 /*
3551 * Make the SLP attribute string list that conforms to
3552 * the IANA 'printer:' template.
3553 */
3554
3555 snprintf(attrs, sizeof(attrs),
3556 "(printer-uri-supported=%s),"
3557 "(uri-authentication-supported=%s>),"
3558#ifdef HAVE_SSL
3559 "(uri-security-supported=tls>),"
3560#else
3561 "(uri-security-supported=none>),"
3562#endif /* HAVE_SSL */
3563 "(printer-name=%s),"
3564 "(printer-location=%s),"
3565 "(printer-info=%s),"
3566 "(printer-more-info=%s),"
3567 "(printer-make-and-model=%s),"
3568 "(printer-type=%d),"
3569 "(charset-supported=utf-8),"
3570 "(natural-language-configured=%s),"
3571 "(natural-language-supported=de,en,es,fr,it),"
3572 "(color-supported=%s),"
3573 "(finishings-supported=%s),"
3574 "(sides-supported=one-sided%s),"
3575 "(multiple-document-jobs-supported=true)"
3576 "(ipp-versions-supported=1.0,1.1)",
3577 p->uri, authentication->values[0].string.text, p->name, location,
3578 info, p->uri, make_model, p->type, DefaultLanguage,
3579 p->type & CUPS_PRINTER_COLOR ? "true" : "false",
3580 finishings,
3581 p->type & CUPS_PRINTER_DUPLEX ?
3582 ",two-sided-long-edge,two-sided-short-edge" : "");
3583
3584 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
3585
3586 /*
3587 * Register the printer with the SLP server...
3588 */
3589
3590 error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
3591 SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
3592
3593 if (error != SLP_OK)
3594 cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
3595 error);
3596}
3597
3598
ef416fc2 3599/*
3600 * 'slp_attr_callback()' - SLP attribute callback
3601 */
3602
3603static SLPBoolean /* O - SLP_TRUE for success */
3604slp_attr_callback(
3605 SLPHandle hslp, /* I - SLP handle */
3606 const char *attrlist, /* I - Attribute list */
3607 SLPError errcode, /* I - Parsing status for this attr */
3608 void *cookie) /* I - Current printer */
3609{
b423cd4c 3610 char *tmp = 0; /* Temporary string */
ef416fc2 3611 cupsd_printer_t *p = (cupsd_printer_t*)cookie;
b423cd4c 3612 /* Current printer */
ef416fc2 3613
3614
b423cd4c 3615 (void)hslp; /* anti-compiler-warning-code */
ef416fc2 3616
3617 /*
3618 * Bail if there was an error
3619 */
3620
3621 if (errcode != SLP_OK)
3622 return (SLP_TRUE);
3623
3624 /*
3625 * Parse the attrlist to obtain things needed to build CUPS browse packet
3626 */
3627
3628 memset(p, 0, sizeof(cupsd_printer_t));
3629
ef416fc2 3630 if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
3631 return (SLP_FALSE);
3632 if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
3633 return (SLP_FALSE);
3634 if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
3635 return (SLP_FALSE);
b423cd4c 3636 if (!slp_get_attr(attrlist, "(printer-type=", &tmp))
3637 p->type = atoi(tmp);
3638 else
3639 p->type = CUPS_PRINTER_REMOTE;
ef416fc2 3640
3641 cupsdClearString(&tmp);
3642
3643 return (SLP_TRUE);
3644}
3645
3646
3647/*
3648 * 'slp_dereg_printer()' - SLPDereg() the specified printer
3649 */
3650
3651static void
3652slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
3653{
3654 char srvurl[HTTP_MAX_URI]; /* Printer service URI */
3655
3656
3657 cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
3658
3659 if (!(p->type & CUPS_PRINTER_REMOTE))
3660 {
3661 /*
3662 * Make the SLP service URL that conforms to the IANA
3663 * 'printer:' template.
3664 */
3665
3666 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
3667
3668 /*
3669 * Deregister the printer...
3670 */
3671
3672 SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
3673 }
3674}
3675
3676
3677/*
3678 * 'slp_get_attr()' - Get an attribute from an SLP registration.
3679 */
3680
3681static int /* O - 0 on success */
3682slp_get_attr(const char *attrlist, /* I - Attribute list string */
3683 const char *tag, /* I - Name of attribute */
3684 char **valbuf) /* O - Value */
3685{
3686 char *ptr1, /* Pointer into string */
3687 *ptr2; /* ... */
3688
3689
3690 cupsdClearString(valbuf);
3691
3692 if ((ptr1 = strstr(attrlist, tag)) != NULL)
3693 {
3694 ptr1 += strlen(tag);
3695
3696 if ((ptr2 = strchr(ptr1,')')) != NULL)
3697 {
3698 /*
3699 * Copy the value...
3700 */
3701
3702 *valbuf = calloc(ptr2 - ptr1 + 1, 1);
3703 strncpy(*valbuf, ptr1, ptr2 - ptr1);
3704
3705 /*
3706 * Dequote the value...
3707 */
3708
3709 for (ptr1 = *valbuf; *ptr1; ptr1 ++)
3710 if (*ptr1 == '\\' && ptr1[1])
3711 _cups_strcpy(ptr1, ptr1 + 1);
3712
3713 return (0);
3714 }
3715 }
3716
3717 return (-1);
3718}
3719
3720
3721/*
3722 * 'slp_reg_callback()' - Empty SLPRegReport.
3723 */
3724
3725static void
3726slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
3727 SLPError errcode, /* I - Error code, if any */
3728 void *cookie) /* I - App data */
3729{
3730 (void)hslp;
3731 (void)errcode;
3732 (void)cookie;
3733
3734 return;
3735}
3736
3737
3738/*
3739 * 'slp_url_callback()' - SLP service url callback
3740 */
3741
3742static SLPBoolean /* O - TRUE = OK, FALSE = error */
3743slp_url_callback(
3744 SLPHandle hslp, /* I - SLP handle */
3745 const char *srvurl, /* I - URL of service */
3746 unsigned short lifetime, /* I - Life of service */
3747 SLPError errcode, /* I - Existing error code */
3748 void *cookie) /* I - Pointer to service list */
3749{
3750 slpsrvurl_t *s, /* New service entry */
3751 **head; /* Pointer to head of entry */
3752
3753
3754 /*
3755 * Let the compiler know we won't be using these vars...
3756 */
3757
3758 (void)hslp;
3759 (void)lifetime;
3760
3761 /*
3762 * Bail if there was an error
3763 */
3764
3765 if (errcode != SLP_OK)
3766 return (SLP_TRUE);
3767
3768 /*
3769 * Grab the head of the list...
3770 */
3771
3772 head = (slpsrvurl_t**)cookie;
3773
3774 /*
3775 * Allocate a *temporary* slpsrvurl_t to hold this entry.
3776 */
3777
3778 if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
3779 return (SLP_FALSE);
3780
3781 /*
3782 * Copy the SLP service URL...
3783 */
3784
3785 strlcpy(s->url, srvurl, sizeof(s->url));
3786
3787 /*
3788 * Link the SLP service URL into the head of the list
3789 */
3790
3791 if (*head)
3792 s->next = *head;
3793
3794 *head = s;
3795
3796 return (SLP_TRUE);
3797}
3798#endif /* HAVE_LIBSLP */
3799
3800
3801/*
7594b224 3802 * End of "$Id: dirsvc.c 6354 2007-03-19 06:16:32Z mike $".
ef416fc2 3803 */