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