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