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