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