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