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