]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/dirsvc.c
Cleanup.
[thirdparty/cups.git] / scheduler / dirsvc.c
CommitLineData
a129ddbd 1/*
b2e10895 2 * "$Id$"
a129ddbd 3 *
d6de4648 4 * Directory services routines for the Common UNIX Printing System (CUPS).
a129ddbd 5 *
c9d3f842 6 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
a129ddbd 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
8784b6a6 17 * 44141 Airport View Drive, Suite 204
8650fcf2 18 * Hollywood, Maryland 20636 USA
a129ddbd 19 *
edfd3c3d 20 * Voice: (301) 373-9600
a129ddbd 21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
589eb420 26 * cupsdProcessBrowseData() - Process new browse data.
27 * cupsdSendBrowseDelete() - Send a "browse delete" message for a printer.
28 * cupsdSendBrowseList() - Send new browsing information as necessary.
29 * cupsdSendCUPSBrowse() - Send new browsing information using the CUPS protocol.
30 * cupsdStartBrowsing() - Start sending and receiving broadcast information.
31 * cupsdStartPolling() - Start polling servers as needed.
32 * cupsdStopBrowsing() - Stop sending and receiving broadcast information.
33 * cupsdStopPolling() - Stop polling servers as needed.
34 * cupsdUpdateCUPSBrowse() - Update the browse lists using the CUPS protocol.
35 * cupsdUpdatePolling() - Read status messages from the poll daemons.
f3e786fc 36 * slp_reg_callback() - Empty SLPRegReport.
589eb420 37 * cupsdSendSLPBrowse() - Register the specified printer with SLP.
f3e786fc 38 * slp_dereg_printer() - SLPDereg() the specified printer
39 * slp_get_attr() - Get an attribute from an SLP registration.
40 * slp_attr_callback() - SLP attribute callback
41 * slp_url_callback() - SLP service url callback
589eb420 42 * cupsdUpdateSLPBrowse() - Get browsing information via SLP.
a129ddbd 43 */
44
45/*
46 * Include necessary headers...
47 */
48
fd8b1cf8 49#include "cupsd.h"
7a91f14b 50#include <grp.h>
fd8b1cf8 51
52
903511b4 53#ifdef HAVE_LIBSLP
f3e786fc 54static void slp_dereg_printer(cupsd_printer_t *p);
903511b4 55#endif /* HAVE_LIBSLP */
56
57
753453e4 58/*
589eb420 59 * 'cupsdProcessBrowseData()' - Process new browse data.
753453e4 60 */
61
62void
f3e786fc 63cupsdProcessBrowseData(
64 const char *uri, /* I - URI of printer/class */
65 cups_ptype_t type, /* I - Printer type */
66 ipp_pstate_t state, /* I - Printer state */
67 const char *location, /* I - Printer location */
68 const char *info, /* I - Printer information */
69 const char *make_model) /* I - Printer make and model */
753453e4 70{
71 int i; /* Looping var */
72 int update; /* Update printer attributes? */
7d6f99c0 73 char finaluri[HTTP_MAX_URI], /* Final URI for printer */
74 method[HTTP_MAX_URI], /* Method portion of URI */
753453e4 75 username[HTTP_MAX_URI], /* Username portion of URI */
76 host[HTTP_MAX_URI], /* Host portion of URI */
77 resource[HTTP_MAX_URI]; /* Resource portion of URI */
78 int port; /* Port portion of URI */
79 char name[IPP_MAX_NAME], /* Name of printer */
80 *hptr, /* Pointer into hostname */
81 *sptr; /* Pointer into ServerName */
82 char local_make_model[IPP_MAX_NAME];
83 /* Local make and model */
f3e786fc 84 cupsd_printer_t *p, /* Printer information */
753453e4 85 *pclass, /* Printer class */
90231631 86 *first; /* First printer in class */
753453e4 87 int offset, /* Offset of name */
88 len; /* Length of name */
89
90
91 /*
92 * Pull the URI apart to see if this is a local or remote printer...
93 */
94
95 httpSeparate(uri, method, username, host, &port, resource);
96
901b295d 97 /*
98 * Determine if the URI contains any illegal characters in it...
99 */
100
584ef899 101 if (strncmp(uri, "ipp://", 6) || !host[0] ||
102 (strncmp(resource, "/printers/", 10) &&
103 strncmp(resource, "/classes/", 9)))
901b295d 104 {
f3e786fc 105 cupsdLogMessage(CUPSD_LOG_ERROR,
106 "cupsdProcessBrowseData: Bad printer URI in browse data: %s",
107 uri);
901b295d 108 return;
109 }
110
584ef899 111 if (strchr(resource, '?') ||
112 (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
113 (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
901b295d 114 {
f3e786fc 115 cupsdLogMessage(CUPSD_LOG_ERROR,
116 "cupsdProcessBrowseData: Bad resource in browse data: %s",
117 resource);
901b295d 118 return;
119 }
7d6f99c0 120
753453e4 121 /*
7d6f99c0 122 * OK, this isn't a local printer; add any remote options...
123 */
124
125 if (BrowseRemoteOptions)
126 {
127 if (BrowseRemoteOptions[0] == '?')
128 {
129 /*
130 * Override server-supplied URI...
131 */
132
133 char tempuri[HTTP_MAX_URI]; /* Temporary URI */
134
135
136 if (strchr(uri, '?'))
137 {
138 /*
139 * Drop everything after ?...
140 */
141
142 strlcpy(tempuri, uri, sizeof(tempuri));
143 *strchr(tempuri, '?') = '\0';
144
145 uri = tempuri;
146 }
147
148 /*
149 * Combine stripped URI and remote options...
150 */
151
152 snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
153 }
154 else if (strchr(uri, '?'))
155 snprintf(finaluri, sizeof(finaluri), "%s+%s", uri, BrowseRemoteOptions);
156 else
157 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
158
159 /*
160 * Use the new URI instead of the old one...
161 */
162
163 uri = finaluri;
164 }
165
166 /*
167 * See if we already have it listed in the Printers list, and add it if not...
753453e4 168 */
169
f33b2b47 170 type |= CUPS_PRINTER_REMOTE;
903511b4 171 type &= ~CUPS_PRINTER_IMPLICIT;
753453e4 172 update = 0;
173 hptr = strchr(host, '.');
174 sptr = strchr(ServerName, '.');
175
176 if (sptr != NULL && hptr != NULL)
177 {
178 /*
179 * Strip the common domain name components...
180 */
181
182 while (hptr != NULL)
183 {
584ef899 184 if (!strcasecmp(hptr, sptr))
753453e4 185 {
186 *hptr = '\0';
187 break;
188 }
189 else
190 hptr = strchr(hptr + 1, '.');
191 }
192 }
193
194 if (type & CUPS_PRINTER_CLASS)
195 {
196 /*
197 * Remote destination is a class...
198 */
199
584ef899 200 if (!strncmp(resource, "/classes/", 9))
753453e4 201 snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
202 else
203 return;
204
589eb420 205 if ((p = cupsdFindClass(name)) == NULL && BrowseShortNames)
753453e4 206 {
589eb420 207 if ((p = cupsdFindClass(resource + 9)) != NULL)
753453e4 208 {
584ef899 209 if (p->hostname && strcasecmp(p->hostname, host))
753453e4 210 {
211 /*
212 * Nope, this isn't the same host; if the hostname isn't the local host,
213 * add it to the other class and then find a class using the full host
214 * name...
215 */
216
217 if (p->type & CUPS_PRINTER_REMOTE)
218 {
f3e786fc 219 cupsdLogMessage(CUPSD_LOG_INFO,
220 "Renamed remote class \"%s\" to \"%s@%s\"...",
221 p->name, p->name, p->hostname);
584ef899 222 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
223 "Class \'%s\' deleted by directory services.",
224 p->name);
225
90231631 226 cupsArrayRemove(Printers, p);
589eb420 227 cupsdSetStringf(&p->name, "%s@%s", p->name, p->hostname);
228 cupsdSetPrinterAttrs(p);
90231631 229 cupsArrayAdd(Printers, p);
584ef899 230
231 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
232 "Class \'%s\' added by directory services.",
233 p->name);
753453e4 234 }
235
236 p = NULL;
237 }
36992080 238 else if (!p->hostname)
753453e4 239 {
584ef899 240 /*
241 * Hostname not set, so this must be a cached remote printer
242 * that was created for a pending print job...
243 */
244
589eb420 245 cupsdSetString(&p->hostname, host);
246 cupsdSetString(&p->uri, uri);
247 cupsdSetString(&p->device_uri, uri);
753453e4 248 update = 1;
249 }
250 }
251 else
584ef899 252 {
253 /*
254 * Use the short name for this shared class.
255 */
256
def978d5 257 strlcpy(name, resource + 9, sizeof(name));
584ef899 258 }
753453e4 259 }
584ef899 260 else if (p && !p->hostname)
753453e4 261 {
584ef899 262 /*
263 * Hostname not set, so this must be a cached remote printer
264 * that was created for a pending print job...
265 */
266
589eb420 267 cupsdSetString(&p->hostname, host);
268 cupsdSetString(&p->uri, uri);
269 cupsdSetString(&p->device_uri, uri);
753453e4 270 update = 1;
271 }
272
584ef899 273 if (!p)
753453e4 274 {
275 /*
276 * Class doesn't exist; add it...
277 */
278
589eb420 279 p = cupsdAddClass(name);
753453e4 280
f3e786fc 281 cupsdLogMessage(CUPSD_LOG_INFO, "Added remote class \"%s\"...", name);
753453e4 282
403be522 283 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
42f94780 284 "Class \'%s\' added by directory services.", name);
285
753453e4 286 /*
287 * Force the URI to point to the real server...
288 */
289
648051ba 290 p->type = type & ~CUPS_PRINTER_REJECTING;
db628f45 291 p->accepting = 1;
589eb420 292 cupsdSetString(&p->uri, uri);
293 cupsdSetString(&p->device_uri, uri);
294 cupsdSetString(&p->hostname, host);
753453e4 295
296 update = 1;
297 }
298 }
299 else
300 {
301 /*
302 * Remote destination is a printer...
303 */
304
305 if (strncmp(resource, "/printers/", 10) == 0)
306 snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
307 else
308 return;
309
589eb420 310 if ((p = cupsdFindPrinter(name)) == NULL && BrowseShortNames)
753453e4 311 {
589eb420 312 if ((p = cupsdFindPrinter(resource + 10)) != NULL)
753453e4 313 {
584ef899 314 if (p->hostname && strcasecmp(p->hostname, host))
753453e4 315 {
316 /*
317 * Nope, this isn't the same host; if the hostname isn't the local host,
318 * add it to the other printer and then find a printer using the full host
319 * name...
320 */
321
322 if (p->type & CUPS_PRINTER_REMOTE)
323 {
f3e786fc 324 cupsdLogMessage(CUPSD_LOG_INFO,
325 "Renamed remote printer \"%s\" to \"%s@%s\"...",
326 p->name, p->name, p->hostname);
584ef899 327 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
328 "Printer \'%s\' deleted by directory services.",
329 p->name);
330
90231631 331 cupsArrayRemove(Printers, p);
589eb420 332 cupsdSetStringf(&p->name, "%s@%s", p->name, p->hostname);
333 cupsdSetPrinterAttrs(p);
90231631 334 cupsArrayAdd(Printers, p);
584ef899 335
336 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
337 "Printer \'%s\' added by directory services.",
338 p->name);
753453e4 339 }
340
341 p = NULL;
342 }
36992080 343 else if (!p->hostname)
753453e4 344 {
584ef899 345 /*
346 * Hostname not set, so this must be a cached remote printer
347 * that was created for a pending print job...
348 */
349
589eb420 350 cupsdSetString(&p->hostname, host);
351 cupsdSetString(&p->uri, uri);
352 cupsdSetString(&p->device_uri, uri);
753453e4 353 update = 1;
354 }
355 }
356 else
584ef899 357 {
358 /*
359 * Use the short name for this shared printer.
360 */
361
def978d5 362 strlcpy(name, resource + 10, sizeof(name));
584ef899 363 }
753453e4 364 }
584ef899 365 else if (p && !p->hostname)
753453e4 366 {
584ef899 367 /*
368 * Hostname not set, so this must be a cached remote printer
369 * that was created for a pending print job...
370 */
371
589eb420 372 cupsdSetString(&p->hostname, host);
373 cupsdSetString(&p->uri, uri);
374 cupsdSetString(&p->device_uri, uri);
753453e4 375 update = 1;
376 }
377
584ef899 378 if (!p)
753453e4 379 {
380 /*
381 * Printer doesn't exist; add it...
382 */
383
589eb420 384 p = cupsdAddPrinter(name);
753453e4 385
403be522 386 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
42f94780 387 "Printer \'%s\' added by directory services.", name);
388
f3e786fc 389 cupsdLogMessage(CUPSD_LOG_INFO, "Added remote printer \"%s\"...", name);
753453e4 390
391 /*
392 * Force the URI to point to the real server...
393 */
394
648051ba 395 p->type = type & ~CUPS_PRINTER_REJECTING;
db628f45 396 p->accepting = 1;
589eb420 397 cupsdSetString(&p->hostname, host);
398 cupsdSetString(&p->uri, uri);
399 cupsdSetString(&p->device_uri, uri);
753453e4 400
401 update = 1;
402 }
403 }
404
405 /*
406 * Update the state...
407 */
408
409 p->state = state;
753453e4 410 p->browse_time = time(NULL);
411
648051ba 412 if (type & CUPS_PRINTER_REJECTING)
413 {
414 type &= ~CUPS_PRINTER_REJECTING;
415
416 if (p->accepting)
417 {
418 update = 1;
419 p->accepting = 0;
420 }
421 }
422 else if (!p->accepting)
423 {
424 update = 1;
425 p->accepting = 1;
426 }
427
753453e4 428 if (p->type != type)
429 {
430 p->type = type;
431 update = 1;
432 }
433
d6d2f8e2 434 if (location && (!p->location || strcmp(p->location, location)))
753453e4 435 {
589eb420 436 cupsdSetString(&p->location, location);
753453e4 437 update = 1;
438 }
439
d6d2f8e2 440 if (info && (!p->info || strcmp(p->info, info)))
753453e4 441 {
589eb420 442 cupsdSetString(&p->info, info);
753453e4 443 update = 1;
444 }
445
d6d2f8e2 446 if (!make_model || !make_model[0])
753453e4 447 {
448 if (type & CUPS_PRINTER_CLASS)
449 snprintf(local_make_model, sizeof(local_make_model),
450 "Remote Class on %s", host);
451 else
452 snprintf(local_make_model, sizeof(local_make_model),
453 "Remote Printer on %s", host);
454 }
455 else
456 snprintf(local_make_model, sizeof(local_make_model),
457 "%s on %s", make_model, host);
458
36992080 459 if (!p->make_model || strcmp(p->make_model, local_make_model))
753453e4 460 {
589eb420 461 cupsdSetString(&p->make_model, local_make_model);
753453e4 462 update = 1;
463 }
464
903511b4 465 if (type & CUPS_PRINTER_DELETE)
466 {
42f94780 467 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
468 "%s \'%s\' deleted by directory services.",
469 (type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", p->name);
470
471 cupsdExpireSubscriptions(p, NULL);
472
589eb420 473 cupsdDeletePrinter(p, 1);
474 cupsdUpdateImplicitClasses();
903511b4 475 }
476 else if (update)
a4f3d51c 477 {
589eb420 478 cupsdSetPrinterAttrs(p);
479 cupsdUpdateImplicitClasses();
a4f3d51c 480 }
753453e4 481
482 /*
483 * See if we have a default printer... If not, make the first printer the
484 * default.
485 */
486
487 if (DefaultPrinter == NULL && Printers != NULL)
3a74d6bf 488 {
589eb420 489 DefaultPrinter = (cupsd_printer_t *)cupsArrayFirst(Printers);
753453e4 490
589eb420 491 cupsdWritePrintcap();
3a74d6bf 492 }
493
753453e4 494 /*
495 * Do auto-classing if needed...
496 */
497
90231631 498 if (ImplicitClasses && Printers)
753453e4 499 {
500 /*
501 * Loop through all available printers and create classes as needed...
502 */
503
f3e786fc 504 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
505 update = 0, pclass = NULL, first = NULL;
753453e4 506 p != NULL;
589eb420 507 p = (cupsd_printer_t *)cupsArrayNext(Printers))
753453e4 508 {
753453e4 509 /*
8bd0441f 510 * Skip implicit classes...
753453e4 511 */
512
8bd0441f 513 if (p->type & CUPS_PRINTER_IMPLICIT)
753453e4 514 {
515 len = 0;
516 continue;
517 }
518
519 /*
520 * If len == 0, get the length of this printer name up to the "@"
521 * sign (if any).
522 */
523
524 if (len > 0 &&
525 strncasecmp(p->name, name + offset, len) == 0 &&
526 (p->name[len] == '\0' || p->name[len] == '@'))
527 {
528 /*
529 * We have more than one printer with the same name; see if
530 * we have a class, and if this printer is a member...
531 */
532
584ef899 533 if (pclass && strcasecmp(pclass->name, name))
534 {
535 if (update)
589eb420 536 cupsdSetPrinterAttrs(pclass);
584ef899 537
538 update = 0;
539 pclass = NULL;
540 }
541
589eb420 542 if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
753453e4 543 {
544 /*
545 * Need to add the class...
546 */
547
589eb420 548 pclass = cupsdAddPrinter(name);
753453e4 549 pclass->type |= CUPS_PRINTER_IMPLICIT;
550 pclass->accepting = 1;
551 pclass->state = IPP_PRINTER_IDLE;
552
589eb420 553 cupsdSetString(&pclass->location, p->location);
554 cupsdSetString(&pclass->info, p->info);
8ce19460 555
584ef899 556 update = 1;
753453e4 557
f3e786fc 558 cupsdLogMessage(CUPSD_LOG_INFO, "Added implicit class \"%s\"...",
559 name);
753453e4 560 }
561
562 if (first != NULL)
563 {
564 for (i = 0; i < pclass->num_printers; i ++)
565 if (pclass->printers[i] == first)
566 break;
567
568 if (i >= pclass->num_printers)
589eb420 569 cupsdAddPrinterToClass(pclass, first);
753453e4 570
571 first = NULL;
572 }
573
574 for (i = 0; i < pclass->num_printers; i ++)
575 if (pclass->printers[i] == p)
576 break;
577
578 if (i >= pclass->num_printers)
584ef899 579 {
589eb420 580 cupsdAddPrinterToClass(pclass, p);
584ef899 581 update = 1;
582 }
753453e4 583 }
584 else
585 {
586 /*
587 * First time around; just get name length and mark it as first
588 * in the list...
589 */
590
591 if ((hptr = strchr(p->name, '@')) != NULL)
592 len = hptr - p->name;
593 else
594 len = strlen(p->name);
595
596 strncpy(name, p->name, len);
597 name[len] = '\0';
598 offset = 0;
599
589eb420 600 if ((first = cupsdFindDest(name)) != NULL &&
584ef899 601 !(first->type & CUPS_PRINTER_IMPLICIT))
753453e4 602 {
603 /*
604 * Can't use same name as a local printer; add "Any" to the
605 * front of the name, unless we have explicitly disabled
606 * the "ImplicitAnyClasses"...
607 */
608
8bd0441f 609 if (ImplicitAnyClasses && len < (sizeof(name) - 4))
753453e4 610 {
611 /*
612 * Add "Any" to the class name...
613 */
614
615 strcpy(name, "Any");
616 strncpy(name + 3, p->name, len);
617 name[len + 3] = '\0';
618 offset = 3;
619 }
620 else
621 {
622 /*
623 * Don't create an implicit class if we have a local printer
624 * with the same name...
625 */
626
627 len = 0;
628 continue;
629 }
630 }
631
632 first = p;
633 }
634 }
584ef899 635
636 /*
637 * Update the last printer class as needed...
638 */
639
640 if (pclass && update)
589eb420 641 cupsdSetPrinterAttrs(pclass);
753453e4 642 }
643}
644
645
903511b4 646/*
589eb420 647 * 'cupsdSendBrowseDelete()' - Send a "browse delete" message for a printer.
903511b4 648 */
649
650void
f3e786fc 651cupsdSendBrowseDelete(
652 cupsd_printer_t *p) /* I - Printer to delete */
903511b4 653{
654 /*
655 * Only announce if browsing is enabled...
656 */
657
25392f52 658 if (!Browsing || !p->shared)
903511b4 659 return;
660
661 /*
662 * First mark the printer for deletion...
663 */
664
665 p->type |= CUPS_PRINTER_DELETE;
666
667 /*
668 * Announce the deletion...
669 */
670
206d3f94 671 if (BrowseLocalProtocols & BROWSE_CUPS)
589eb420 672 cupsdSendCUPSBrowse(p);
903511b4 673#ifdef HAVE_LIBSLP
206d3f94 674 if (BrowseLocalProtocols & BROWSE_SLP)
f3e786fc 675 slp_dereg_printer(p);
903511b4 676#endif /* HAVE_LIBSLP */
677}
678
679
753453e4 680/*
589eb420 681 * 'cupsdSendBrowseList()' - Send new browsing information as necessary.
753453e4 682 */
683
684void
589eb420 685cupsdSendBrowseList(void)
753453e4 686{
ba886a95 687 int count; /* Number of dests to update */
f3e786fc 688 cupsd_printer_t *p; /* Current printer */
ba886a95 689 time_t ut, /* Minimum update time */
690 to; /* Timeout time */
753453e4 691
692
90231631 693 if (!Browsing || !BrowseLocalProtocols || !Printers)
753453e4 694 return;
695
696 /*
697 * Compute the update and timeout times...
698 */
699
700 ut = time(NULL) - BrowseInterval;
701 to = time(NULL) - BrowseTimeout;
702
c47e97cc 703 /*
704 * Figure out how many printers need an update...
705 */
706
707 if (BrowseInterval > 0)
708 {
ba886a95 709 int max_count; /* Maximum number to update */
710
711
712 /*
713 * Throttle the number of printers we'll be updating this time
714 * around based on the number of queues that need updating and
715 * the maximum number of queues to update each second...
716 */
717
90231631 718 max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1;
ba886a95 719
589eb420 720 for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers);
90231631 721 count < max_count && p != NULL;
589eb420 722 p = (cupsd_printer_t *)cupsArrayNext(Printers))
c47e97cc 723 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
25392f52 724 p->shared && p->browse_time < ut)
c47e97cc 725 count ++;
726
727 /*
ba886a95 728 * Loop through all of the printers and send local updates as needed...
c47e97cc 729 */
730
589eb420 731 for (p = (cupsd_printer_t *)cupsArrayFind(Printers, BrowseNext->name);
90231631 732 count > 0;
589eb420 733 p = (cupsd_printer_t *)cupsArrayNext(Printers))
ba886a95 734 {
735 /*
736 * Check for wraparound...
737 */
738
739 if (!p)
589eb420 740 p = (cupsd_printer_t *)cupsArrayFirst(Printers);
ba886a95 741
fd35db0b 742 if (!p)
743 break;
25392f52 744 else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) ||
745 !p->shared)
ba886a95 746 continue;
747 else if (p->browse_time < ut)
748 {
749 /*
750 * Need to send an update...
751 */
752
753 count --;
754
755 p->browse_time = time(NULL);
756
206d3f94 757 if (BrowseLocalProtocols & BROWSE_CUPS)
589eb420 758 cupsdSendCUPSBrowse(p);
ba886a95 759
760#ifdef HAVE_LIBSLP
206d3f94 761 if (BrowseLocalProtocols & BROWSE_SLP)
589eb420 762 cupsdSendSLPBrowse(p);
ba886a95 763#endif /* HAVE_LIBSLP */
764 }
765 }
766
767 /*
768 * Save where we left off so that all printers get updated...
769 */
770
771 BrowseNext = p;
c47e97cc 772 }
c47e97cc 773
753453e4 774 /*
775 * Loop through all of the printers and send local updates as needed...
776 */
777
589eb420 778 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
90231631 779 p;
589eb420 780 p = (cupsd_printer_t *)cupsArrayNext(Printers))
753453e4 781 {
ba886a95 782 /*
783 * If this is a remote queue, see if it needs to be timed out...
784 */
785
753453e4 786 if (p->type & CUPS_PRINTER_REMOTE)
787 {
753453e4 788 if (p->browse_time < to)
789 {
42f94780 790 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
791 "%s \'%s\' deleted by directory services (timeout).",
792 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
793 p->name);
794
f3e786fc 795 cupsdLogMessage(CUPSD_LOG_INFO,
796 "Remote destination \"%s\" has timed out; deleting it...",
797 p->name);
42f94780 798
589eb420 799 cupsdDeletePrinter(p, 1);
753453e4 800 }
801 }
753453e4 802 }
803}
804
805
806/*
589eb420 807 * 'cupsdSendCUPSBrowse()' - Send new browsing information using the CUPS protocol.
753453e4 808 */
809
810void
f3e786fc 811cupsdSendCUPSBrowse(cupsd_printer_t *p) /* I - Printer to send */
753453e4 812{
d7a9de63 813 int i; /* Looping var */
648051ba 814 cups_ptype_t type; /* Printer type */
f3e786fc 815 cupsd_dirsvc_addr_t *b; /* Browse address */
d7a9de63 816 int bytes; /* Length of packet */
817 char packet[1453]; /* Browse data packet */
7d6f99c0 818 char options[1024]; /* Browse local options */
589eb420 819 cupsd_netif_t *iface; /* Network interface */
753453e4 820
821
648051ba 822 /*
823 * Figure out the printer type value...
824 */
825
826 type = p->type | CUPS_PRINTER_REMOTE;
827
828 if (!p->accepting)
829 type |= CUPS_PRINTER_REJECTING;
830
7d6f99c0 831 /*
832 * Initialize the browse options...
833 */
834
835 if (BrowseLocalOptions)
836 {
837 if (BrowseLocalOptions[0] == '?')
838 strlcpy(options, BrowseLocalOptions, sizeof(options));
839 else
840 snprintf(options, sizeof(options), "?%s", BrowseLocalOptions);
841 }
842 else
843 options[0] = '\0';
844
753453e4 845 /*
846 * Send a packet to each browse address...
847 */
848
d7a9de63 849 for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
850 if (b->iface[0])
753453e4 851 {
d7a9de63 852 /*
853 * Send the browse packet to one or more interfaces...
854 */
753453e4 855
d7a9de63 856 if (strcmp(b->iface, "*") == 0)
857 {
858 /*
859 * Send to all local interfaces...
860 */
861
589eb420 862 cupsdNetIFUpdate();
d7a9de63 863
864 for (iface = NetIFList; iface != NULL; iface = iface->next)
865 {
866 /*
867 * Only send to local interfaces...
868 */
869
edd6ee99 870 if (!iface->is_local || !iface->port)
d7a9de63 871 continue;
872
edd6ee99 873 snprintf(packet, sizeof(packet), "%x %x ipp://%s:%d/%s/%s%s \"%s\" \"%s\" \"%s\"\n",
874 type, p->state, iface->hostname, iface->port,
d7a9de63 875 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
7d6f99c0 876 p->name, options, p->location ? p->location : "",
25926905 877 p->info ? p->info : "",
878 p->make_model ? p->make_model : "Unknown");
d7a9de63 879
880 bytes = strlen(packet);
881
f3e786fc 882 cupsdLogMessage(CUPSD_LOG_DEBUG2,
883 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
884 iface->name, packet);
d7a9de63 885
886 if (iface->broadcast.addr.sa_family == AF_INET)
887 {
888 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
889
890 sendto(BrowseSocket, packet, bytes, 0,
891 (struct sockaddr *)&(iface->broadcast),
892 sizeof(struct sockaddr_in));
893 }
a09840c5 894#ifdef AF_INET6
d7a9de63 895 else
896 {
897 iface->broadcast.ipv6.sin6_port = htons(BrowsePort);
898
899 sendto(BrowseSocket, packet, bytes, 0,
900 (struct sockaddr *)&(iface->broadcast),
901 sizeof(struct sockaddr_in6));
902 }
a09840c5 903#endif /* AF_INET6 */
d7a9de63 904 }
905 }
f3e786fc 906 else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
d7a9de63 907 {
908 /*
909 * Send to the named interface...
910 */
911
edd6ee99 912 if (!iface->port)
913 continue;
914
915 snprintf(packet, sizeof(packet), "%x %x ipp://%s:%d/%s/%s%s \"%s\" \"%s\" \"%s\"\n",
916 type, p->state, iface->hostname, iface->port,
d7a9de63 917 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
7d6f99c0 918 p->name, options, p->location ? p->location : "",
25926905 919 p->info ? p->info : "",
920 p->make_model ? p->make_model : "Unknown");
d7a9de63 921
922 bytes = strlen(packet);
923
f3e786fc 924 cupsdLogMessage(CUPSD_LOG_DEBUG2,
925 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
926 iface->name, packet);
d7a9de63 927
928 if (iface->broadcast.addr.sa_family == AF_INET)
929 {
930 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
931
932 sendto(BrowseSocket, packet, bytes, 0,
933 (struct sockaddr *)&(iface->broadcast),
934 sizeof(struct sockaddr_in));
935 }
a09840c5 936#ifdef AF_INET6
d7a9de63 937 else
938 {
939 iface->broadcast.ipv6.sin6_port = htons(BrowsePort);
940
941 sendto(BrowseSocket, packet, bytes, 0,
942 (struct sockaddr *)&(iface->broadcast),
943 sizeof(struct sockaddr_in6));
944 }
a09840c5 945#endif /* AF_INET6 */
d7a9de63 946 }
947 }
948 else
949 {
950 /*
951 * Send the browse packet to the indicated address using
952 * the default server name...
953 */
954
7d6f99c0 955 snprintf(packet, sizeof(packet), "%x %x %s%s \"%s\" \"%s\" \"%s\"\n",
956 type, p->state, p->uri, options,
25926905 957 p->location ? p->location : "",
958 p->info ? p->info : "",
959 p->make_model ? p->make_model : "Unknown");
d7a9de63 960
961 bytes = strlen(packet);
f3e786fc 962 cupsdLogMessage(CUPSD_LOG_DEBUG2,
963 "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
d7a9de63 964
a09840c5 965#ifdef AF_INET6
d7a9de63 966 if (sendto(BrowseSocket, packet, bytes, 0,
967 (struct sockaddr *)&(b->to),
968 b->to.addr.sa_family == AF_INET ?
969 sizeof(struct sockaddr_in) :
970 sizeof(struct sockaddr_in6)) <= 0)
a09840c5 971#else
972 if (sendto(BrowseSocket, packet, bytes, 0,
973 (struct sockaddr *)&(b->to),
974 sizeof(struct sockaddr_in)) <= 0)
975#endif /* AF_INET6 */
d7a9de63 976 {
977 /*
978 * Unable to send browse packet, so remove this address from the
979 * list...
980 */
981
f3e786fc 982 cupsdLogMessage(CUPSD_LOG_ERROR,
983 "cupsdSendBrowseList: sendto failed for browser %d - %s.",
984 b - Browsers + 1, strerror(errno));
d7a9de63 985
986 if (i > 1)
589eb420 987 memcpy(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
d7a9de63 988
989 b --;
990 NumBrowsers --;
991 }
753453e4 992 }
993}
994
995
d6de4648 996/*
589eb420 997 * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
d6de4648 998 */
999
fd8b1cf8 1000void
589eb420 1001cupsdStartBrowsing(void)
fd8b1cf8 1002{
f3e786fc 1003 int val; /* Socket option value */
1004 struct sockaddr_in addr; /* Broadcast address */
d6de4648 1005
1006
206d3f94 1007 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
d6de4648 1008 return;
1009
206d3f94 1010 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
753453e4 1011 {
1012 /*
1013 * Create the broadcast socket...
1014 */
1015
1016 if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1017 {
f3e786fc 1018 cupsdLogMessage(CUPSD_LOG_ERROR,
1019 "cupsdStartBrowsing: Unable to create broadcast socket - %s.",
1020 strerror(errno));
206d3f94 1021 BrowseLocalProtocols &= ~BROWSE_CUPS;
1022 BrowseRemoteProtocols &= ~BROWSE_CUPS;
753453e4 1023 return;
1024 }
1025
1026 /*
1027 * Set the "broadcast" flag...
1028 */
1029
1030 val = 1;
1031 if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
1032 {
f3e786fc 1033 cupsdLogMessage(CUPSD_LOG_ERROR,
1034 "cupsdStartBrowsing: Unable to set broadcast mode - %s.",
1035 strerror(errno));
753453e4 1036
c3026ddc 1037#ifdef WIN32
753453e4 1038 closesocket(BrowseSocket);
c3026ddc 1039#else
753453e4 1040 close(BrowseSocket);
c3026ddc 1041#endif /* WIN32 */
753453e4 1042
206d3f94 1043 BrowseSocket = -1;
1044 BrowseLocalProtocols &= ~BROWSE_CUPS;
1045 BrowseRemoteProtocols &= ~BROWSE_CUPS;
753453e4 1046 return;
1047 }
1048
1049 /*
1050 * Bind the socket to browse port...
1051 */
1052
1053 memset(&addr, 0, sizeof(addr));
1054 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1055 addr.sin_family = AF_INET;
1056 addr.sin_port = htons(BrowsePort);
1057
1058 if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
1059 {
f3e786fc 1060 cupsdLogMessage(CUPSD_LOG_ERROR,
1061 "cupsdStartBrowsing: Unable to bind broadcast socket - %s.",
1062 strerror(errno));
d6de4648 1063
c3026ddc 1064#ifdef WIN32
753453e4 1065 closesocket(BrowseSocket);
c3026ddc 1066#else
753453e4 1067 close(BrowseSocket);
c3026ddc 1068#endif /* WIN32 */
753453e4 1069
206d3f94 1070 BrowseSocket = -1;
1071 BrowseLocalProtocols &= ~BROWSE_CUPS;
1072 BrowseRemoteProtocols &= ~BROWSE_CUPS;
753453e4 1073 return;
1074 }
1075
db3c5bfd 1076 /*
1077 * Close the socket on exec...
1078 */
1079
1080 fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
1081
753453e4 1082 /*
1083 * Finally, add the socket to the input selection set...
1084 */
1085
f3e786fc 1086 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1087 "cupsdStartBrowsing: Adding fd %d to InputSet...",
1088 BrowseSocket);
753453e4 1089
f3bc1068 1090 FD_SET(BrowseSocket, InputSet);
753453e4 1091 }
b59d5057 1092 else
1093 BrowseSocket = -1;
753453e4 1094
1095#ifdef HAVE_LIBSLP
206d3f94 1096 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
d6de4648 1097 {
753453e4 1098 /*
1099 * Open SLP handle...
1100 */
1101
1102 if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
1103 {
f3e786fc 1104 cupsdLogMessage(CUPSD_LOG_ERROR,
1105 "Unable to open an SLP handle; disabling SLP browsing!");
206d3f94 1106 BrowseLocalProtocols &= ~BROWSE_SLP;
1107 BrowseRemoteProtocols &= ~BROWSE_SLP;
753453e4 1108 }
1109
1110 BrowseSLPRefresh = 0;
d6de4648 1111 }
7db52463 1112#endif /* HAVE_LIBSLP */
753453e4 1113}
d6de4648 1114
d6de4648 1115
753453e4 1116/*
589eb420 1117 * 'cupsdStartPolling()' - Start polling servers as needed.
753453e4 1118 */
1119
1120void
589eb420 1121cupsdStartPolling(void)
753453e4 1122{
f3e786fc 1123 int i; /* Looping var */
1124 cupsd_dirsvc_poll_t *poll; /* Current polling server */
1125 char polld[1024]; /* Poll daemon path */
1126 char sport[10]; /* Server port */
1127 char bport[10]; /* Browser port */
1128 char interval[10]; /* Poll interval */
1129 int statusfds[2]; /* Status pipe */
1130 char *argv[6]; /* Arguments */
1131 char *envp[100]; /* Environment */
753453e4 1132
1133
9495ba14 1134 /*
1135 * Don't do anything if we aren't polling...
1136 */
1137
1138 if (NumPolled == 0)
3ff338a6 1139 {
ddd3933d 1140 PollPipe = -1;
1141 PollStatusBuffer = NULL;
9495ba14 1142 return;
3ff338a6 1143 }
9495ba14 1144
5f46b7d1 1145 /*
c316e838 1146 * Setup string arguments for polld, port and interval options.
5f46b7d1 1147 */
1148
c316e838 1149 snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
1150
753453e4 1151 sprintf(bport, "%d", BrowsePort);
1152
1153 if (BrowseInterval)
1154 sprintf(interval, "%d", BrowseInterval);
1155 else
1156 strcpy(interval, "30");
1157
c316e838 1158 argv[0] = "cups-polld";
1159 argv[2] = sport;
1160 argv[3] = interval;
1161 argv[4] = bport;
1162 argv[5] = NULL;
1163
291355eb 1164 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
1165
5f46b7d1 1166 /*
1167 * Create a pipe that receives the status messages from each
1168 * polling daemon...
1169 */
1170
8650fcf2 1171 if (cupsdOpenPipe(statusfds))
5f46b7d1 1172 {
f3e786fc 1173 cupsdLogMessage(CUPSD_LOG_ERROR,
1174 "Unable to create polling status pipes - %s.",
1175 strerror(errno));
ddd3933d 1176 PollPipe = -1;
1177 PollStatusBuffer = NULL;
5f46b7d1 1178 return;
1179 }
1180
ddd3933d 1181 PollPipe = statusfds[0];
1182 PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
5f46b7d1 1183
1184 /*
1185 * Run each polling daemon, redirecting stderr to the polling pipe...
1186 */
1187
753453e4 1188 for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
fd3ece61 1189 {
753453e4 1190 sprintf(sport, "%d", poll->port);
fd3ece61 1191
c316e838 1192 argv[1] = poll->hostname;
b9e3e9a0 1193
291355eb 1194 if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1,
c316e838 1195 0, &(poll->pid)) < 0)
753453e4 1196 {
f3e786fc 1197 cupsdLogMessage(CUPSD_LOG_ERROR,
1198 "cupsdStartPolling: Unable to fork polling daemon - %s",
1199 strerror(errno));
753453e4 1200 poll->pid = 0;
1201 break;
1202 }
1203 else
f3e786fc 1204 cupsdLogMessage(CUPSD_LOG_DEBUG,
1205 "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
1206 poll->hostname, poll->port, poll->pid);
fd3ece61 1207 }
5f46b7d1 1208
1209 close(statusfds[1]);
1210
1211 /*
1212 * Finally, add the pipe to the input selection set...
1213 */
1214
f3e786fc 1215 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1216 "cupsdStartPolling: Adding fd %d to InputSet...", PollPipe);
5f46b7d1 1217
f3bc1068 1218 FD_SET(PollPipe, InputSet);
753453e4 1219}
d6de4648 1220
d6de4648 1221
753453e4 1222/*
589eb420 1223 * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
753453e4 1224 */
1225
1226void
589eb420 1227cupsdStopBrowsing(void)
753453e4 1228{
206d3f94 1229 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
753453e4 1230 return;
d6de4648 1231
206d3f94 1232 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
d6de4648 1233 {
753453e4 1234 /*
1235 * Close the socket and remove it from the input selection set.
1236 */
d6de4648 1237
753453e4 1238 if (BrowseSocket >= 0)
1239 {
c3026ddc 1240#ifdef WIN32
753453e4 1241 closesocket(BrowseSocket);
d6de4648 1242#else
753453e4 1243 close(BrowseSocket);
c3026ddc 1244#endif /* WIN32 */
d6de4648 1245
f3e786fc 1246 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1247 "cupsdStopBrowsing: Removing fd %d from InputSet...",
1248 BrowseSocket);
753453e4 1249
f3bc1068 1250 FD_CLR(BrowseSocket, InputSet);
b59d5057 1251 BrowseSocket = -1;
753453e4 1252 }
d6de4648 1253 }
1254
753453e4 1255#ifdef HAVE_LIBSLP
206d3f94 1256 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
753453e4 1257 {
1258 /*
1259 * Close SLP handle...
1260 */
d6de4648 1261
753453e4 1262 SLPClose(BrowseSLPHandle);
1263 }
1264#endif /* HAVE_LIBSLP */
fd8b1cf8 1265}
1266
1267
d6de4648 1268/*
589eb420 1269 * 'cupsdStopPolling()' - Stop polling servers as needed.
d6de4648 1270 */
1271
fd8b1cf8 1272void
589eb420 1273cupsdStopPolling(void)
fd8b1cf8 1274{
f3e786fc 1275 int i; /* Looping var */
589eb420 1276 cupsd_dirsvc_poll_t *poll; /* Current polling server */
d6de4648 1277
d6de4648 1278
ba31b514 1279 if (PollPipe >= 0)
5f46b7d1 1280 {
ddd3933d 1281 cupsdStatBufDelete(PollStatusBuffer);
5f46b7d1 1282 close(PollPipe);
1283
f3e786fc 1284 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1285 "cupsdStopPolling: removing fd %d from InputSet.", PollPipe);
f3bc1068 1286 FD_CLR(PollPipe, InputSet);
5f46b7d1 1287
ddd3933d 1288 PollPipe = -1;
1289 PollStatusBuffer = NULL;
5f46b7d1 1290 }
1291
753453e4 1292 for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
1293 if (poll->pid)
c316e838 1294 cupsdEndProcess(poll->pid, 0);
fd8b1cf8 1295}
1296
1297
d6de4648 1298/*
589eb420 1299 * 'cupsdUpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol.
d6de4648 1300 */
1301
fd8b1cf8 1302void
589eb420 1303cupsdUpdateCUPSBrowse(void)
fd8b1cf8 1304{
8b43895a 1305 int i; /* Looping var */
e5ebb675 1306 int auth; /* Authorization status */
753453e4 1307 int len; /* Length of name string */
d6de4648 1308 int bytes; /* Number of bytes left */
1e0c2f84 1309 char packet[1541], /* Broadcast packet */
20e0a4cb 1310 *pptr; /* Pointer into packet */
99de6da0 1311 http_addr_t srcaddr; /* Source address */
e5ebb675 1312 char srcname[1024]; /* Source hostname */
f3e786fc 1313 unsigned address[4]; /* Source address */
7abb7137 1314 unsigned type; /* Printer type */
1315 unsigned state; /* Printer state */
d6de4648 1316 char uri[HTTP_MAX_URI], /* Printer URI */
1317 method[HTTP_MAX_URI], /* Method portion of URI */
1318 username[HTTP_MAX_URI], /* Username portion of URI */
1319 host[HTTP_MAX_URI], /* Host portion of URI */
a2c6b8b1 1320 resource[HTTP_MAX_URI], /* Resource portion of URI */
1321 info[IPP_MAX_NAME], /* Information string */
1322 location[IPP_MAX_NAME], /* Location string */
1323 make_model[IPP_MAX_NAME];/* Make and model string */
d6de4648 1324 int port; /* Port portion of URI */
589eb420 1325 cupsd_netif_t *iface; /* Network interface */
d6de4648 1326
1327
1328 /*
1329 * Read a packet from the browse socket...
1330 */
1331
e5ebb675 1332 len = sizeof(srcaddr);
1e0c2f84 1333 if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
1334 (struct sockaddr *)&srcaddr, &len)) < 0)
18d7d592 1335 {
89db771d 1336 /*
1337 * "Connection refused" is returned under Linux if the destination port
1338 * or address is unreachable from a previous sendto(); check for the
1339 * error here and ignore it for now...
1340 */
1341
de5ee36e 1342 if (errno != ECONNREFUSED && errno != EAGAIN)
89db771d 1343 {
f3e786fc 1344 cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
1345 strerror(errno));
1346 cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
89db771d 1347
589eb420 1348 cupsdStopBrowsing();
89db771d 1349 Browsing = 0;
1350 }
1a5606a3 1351
18d7d592 1352 return;
1353 }
1354
1355 packet[bytes] = '\0';
e5ebb675 1356
1357 /*
1358 * Figure out where it came from...
1359 */
1360
99de6da0 1361#ifdef AF_INET6
1362 if (srcaddr.addr.sa_family == AF_INET6)
1363 {
1364 address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
1365 address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
1366 address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
1367 address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
1368 }
e5ebb675 1369 else
99de6da0 1370#endif /* AF_INET6 */
f9bacabb 1371 {
f3e786fc 1372 address[0] = 0;
1373 address[1] = 0;
1374 address[2] = 0;
1375 address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
e5ebb675 1376 }
1a5606a3 1377
99de6da0 1378 if (HostNameLookups)
1379 httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
1380 else
1381 httpAddrString(&srcaddr, srcname, sizeof(srcname));
1382
e5ebb675 1383 len = strlen(srcname);
1384
1385 /*
1386 * Do ACL stuff...
1387 */
1388
aa9b37d6 1389 if (BrowseACL)
e5ebb675 1390 {
aa9b37d6 1391 if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
e5ebb675 1392 {
1393 /*
1394 * Access from localhost (127.0.0.1) is always allowed...
1395 */
1396
1397 auth = AUTH_ALLOW;
1398 }
1399 else
1400 {
1401 /*
1402 * Do authorization checks on the domain/address...
1403 */
1404
d21a7597 1405 switch (BrowseACL->order_type)
e5ebb675 1406 {
d21a7597 1407 default :
1408 auth = AUTH_DENY; /* anti-compiler-warning-code */
1409 break;
1410
e5ebb675 1411 case AUTH_ALLOW : /* Order Deny,Allow */
d21a7597 1412 auth = AUTH_ALLOW;
1413
589eb420 1414 if (cupsdCheckAuth(address, srcname, len,
e5ebb675 1415 BrowseACL->num_deny, BrowseACL->deny))
1416 auth = AUTH_DENY;
1417
589eb420 1418 if (cupsdCheckAuth(address, srcname, len,
e5ebb675 1419 BrowseACL->num_allow, BrowseACL->allow))
1420 auth = AUTH_ALLOW;
1421 break;
1422
1423 case AUTH_DENY : /* Order Allow,Deny */
d21a7597 1424 auth = AUTH_DENY;
1425
589eb420 1426 if (cupsdCheckAuth(address, srcname, len,
e5ebb675 1427 BrowseACL->num_allow, BrowseACL->allow))
1428 auth = AUTH_ALLOW;
1429
589eb420 1430 if (cupsdCheckAuth(address, srcname, len,
e5ebb675 1431 BrowseACL->num_deny, BrowseACL->deny))
1432 auth = AUTH_DENY;
1433 break;
1434 }
1435 }
1436 }
1437 else
1438 auth = AUTH_ALLOW;
1439
1440 if (auth == AUTH_DENY)
1441 {
f3e786fc 1442 cupsdLogMessage(CUPSD_LOG_DEBUG,
1443 "cupsdUpdateCUPSBrowse: Refused %d bytes from %s", bytes,
1444 srcname);
d6de4648 1445 return;
f9bacabb 1446 }
d6de4648 1447
f3e786fc 1448 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1449 "cupsdUpdateCUPSBrowse: (%d bytes from %s) %s", bytes,
1450 srcname, packet);
e5ebb675 1451
1452 /*
1453 * Parse packet...
1454 */
d6de4648 1455
7abb7137 1456 if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
d6de4648 1457 {
f3e786fc 1458 cupsdLogMessage(CUPSD_LOG_WARN,
1459 "cupsdUpdateCUPSBrowse: Garbled browse packet - %s", packet);
d6de4648 1460 return;
1461 }
1462
20e0a4cb 1463 strcpy(location, "Location Unknown");
1464 strcpy(info, "No Information Available");
1465 make_model[0] = '\0';
1466
1467 if ((pptr = strchr(packet, '\"')) != NULL)
1468 {
1469 /*
1470 * Have extended information; can't use sscanf for it because not all
1471 * sscanf's allow empty strings with %[^\"]...
1472 */
1473
1474 for (i = 0, pptr ++;
1475 i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
1476 i ++, pptr ++)
1477 location[i] = *pptr;
1478
1479 if (i)
1480 location[i] = '\0';
1481
1482 if (*pptr == '\"')
1483 pptr ++;
1484
da275f55 1485 while (*pptr && isspace(*pptr & 255))
20e0a4cb 1486 pptr ++;
1487
05156f4e 1488 if (*pptr == '\"')
1489 {
1490 for (i = 0, pptr ++;
1491 i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
1492 i ++, pptr ++)
1493 info[i] = *pptr;
20e0a4cb 1494
05156f4e 1495 if (i)
1496 info[i] = '\0';
20e0a4cb 1497
05156f4e 1498 if (*pptr == '\"')
1499 pptr ++;
20e0a4cb 1500
da275f55 1501 while (*pptr && isspace(*pptr & 255))
05156f4e 1502 pptr ++;
20e0a4cb 1503
05156f4e 1504 if (*pptr == '\"')
1505 {
1506 for (i = 0, pptr ++;
1507 i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
1508 i ++, pptr ++)
1509 make_model[i] = *pptr;
20e0a4cb 1510
05156f4e 1511 if (i)
1512 make_model[i] = '\0';
1513 }
1514 }
20e0a4cb 1515 }
1516
1517 DEBUG_puts(packet);
a2c6b8b1 1518 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
1519 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
1520 type, state, uri, location, info, make_model));
a8b216d5 1521
d6de4648 1522 /*
1523 * Pull the URI apart to see if this is a local or remote printer...
1524 */
1525
1526 httpSeparate(uri, method, username, host, &port, resource);
1527
a8b216d5 1528 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
1529
d7a9de63 1530 /*
1531 * Check for packets from the local server...
1532 */
1533
aa9b37d6 1534 if (!strcasecmp(host, ServerName) && port == LocalPort)
d6de4648 1535 return;
1536
589eb420 1537 cupsdNetIFUpdate();
d7a9de63 1538
1539 for (iface = NetIFList; iface != NULL; iface = iface->next)
aa9b37d6 1540 if (!strcasecmp(host, iface->hostname) && port == LocalPort)
d7a9de63 1541 return;
1542
e5ebb675 1543 /*
1544 * Do relaying...
1545 */
1546
1547 for (i = 0; i < NumRelays; i ++)
589eb420 1548 if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
e5ebb675 1549 if (sendto(BrowseSocket, packet, bytes, 0,
1550 (struct sockaddr *)&(Relays[i].to),
99de6da0 1551 sizeof(http_addr_t)) <= 0)
e5ebb675 1552 {
f3e786fc 1553 cupsdLogMessage(CUPSD_LOG_ERROR,
1554 "cupsdUpdateCUPSBrowse: sendto failed for relay %d - %s.",
1555 i + 1, strerror(errno));
e5ebb675 1556 return;
1557 }
1558
d6de4648 1559 /*
753453e4 1560 * Process the browse data...
d6de4648 1561 */
1562
589eb420 1563 cupsdProcessBrowseData(uri, (cups_ptype_t)type, (ipp_pstate_t)state, location,
f3e786fc 1564 info, make_model);
753453e4 1565}
d6f1ff9a 1566
d6f1ff9a 1567
5f46b7d1 1568/*
589eb420 1569 * 'cupsdUpdatePolling()' - Read status messages from the poll daemons.
5f46b7d1 1570 */
1571
1572void
589eb420 1573cupsdUpdatePolling(void)
5f46b7d1 1574{
ddd3933d 1575 char *ptr, /* Pointer to end of line in buffer */
1576 message[1024]; /* Pointer to message text */
1577 int loglevel; /* Log level for message */
5f46b7d1 1578
1579
ddd3933d 1580 while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
1581 message, sizeof(message))) != NULL)
1582 if (!strchr(PollStatusBuffer->buffer, '\n'))
1583 break;
5f46b7d1 1584
ddd3933d 1585 if (ptr == NULL)
5f46b7d1 1586 {
9495ba14 1587 /*
1588 * All polling processes have died; stop polling...
1589 */
5f46b7d1 1590
f3e786fc 1591 cupsdLogMessage(CUPSD_LOG_ERROR,
1592 "cupsdUpdatePolling: all polling processes have exited!");
589eb420 1593 cupsdStopPolling();
5f46b7d1 1594 }
1595}
1596
1597
753453e4 1598/***********************************************************************
1599 **** SLP Support Code *************************************************
1600 ***********************************************************************/
d6de4648 1601
753453e4 1602#ifdef HAVE_LIBSLP
1603/*
1604 * SLP service name for CUPS...
1605 */
c7fa9d06 1606
753453e4 1607# define SLP_CUPS_SRVTYPE "service:printer"
1608# define SLP_CUPS_SRVLEN 15
c7fa9d06 1609
b2e10895 1610
1611/*
1612 * Printer service URL structure
1613 */
1614
753453e4 1615typedef struct _slpsrvurl
1616{
1617 struct _slpsrvurl *next;
1618 char url[HTTP_MAX_URI];
1619} slpsrvurl_t;
a2c6b8b1 1620
d6de4648 1621
753453e4 1622/*
f3e786fc 1623 * 'slp_reg_callback()' - Empty SLPRegReport.
753453e4 1624 */
c7fa9d06 1625
f3e786fc 1626static void
1627slp_reg_callback(SLPHandle hslp,
753453e4 1628 SLPError errcode,
1629 void *cookie)
1630{
1631 (void)hslp;
1632 (void)errcode;
1633 (void)cookie;
d6f1ff9a 1634
753453e4 1635 return;
1636}
d6f1ff9a 1637
d6f1ff9a 1638
753453e4 1639/*
589eb420 1640 * 'cupsdSendSLPBrowse()' - Register the specified printer with SLP.
753453e4 1641 */
c7fa9d06 1642
753453e4 1643void
f3e786fc 1644cupsdSendSLPBrowse(cupsd_printer_t *p) /* I - Printer to register */
753453e4 1645{
1646 char srvurl[HTTP_MAX_URI], /* Printer service URI */
1647 attrs[8192], /* Printer attributes */
1648 finishings[1024], /* Finishings to support */
1649 make_model[IPP_MAX_NAME * 2],
1650 /* Make and model, quoted */
1651 location[IPP_MAX_NAME * 2],
1652 /* Location, quoted */
f3e786fc 1653 info[IPP_MAX_NAME * 2], /* Info, quoted */
753453e4 1654 *src, /* Pointer to original string */
1655 *dst; /* Pointer to destination string */
1656 ipp_attribute_t *authentication; /* uri-authentication-supported value */
1657 SLPError error; /* SLP error, if any */
1658
1659
f3e786fc 1660 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSendSLPBrowse(%p = \"%s\")", p,
1661 p->name);
c7fa9d06 1662
753453e4 1663 /*
1664 * Make the SLP service URL that conforms to the IANA
1665 * 'printer:' template.
1666 */
c7fa9d06 1667
753453e4 1668 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
a2c6b8b1 1669
f3e786fc 1670 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
d6de4648 1671
1672 /*
753453e4 1673 * Figure out the finishings string...
d6de4648 1674 */
1675
753453e4 1676 if (p->type & CUPS_PRINTER_STAPLE)
1677 strcpy(finishings, "staple");
1678 else
1679 finishings[0] = '\0';
8b43895a 1680
753453e4 1681 if (p->type & CUPS_PRINTER_BIND)
20e0a4cb 1682 {
753453e4 1683 if (finishings[0])
def978d5 1684 strlcat(finishings, ",bind", sizeof(finishings));
753453e4 1685 else
1686 strcpy(finishings, "bind");
20e0a4cb 1687 }
1688
753453e4 1689 if (p->type & CUPS_PRINTER_PUNCH)
20e0a4cb 1690 {
753453e4 1691 if (finishings[0])
def978d5 1692 strlcat(finishings, ",punch", sizeof(finishings));
753453e4 1693 else
1694 strcpy(finishings, "punch");
20e0a4cb 1695 }
1696
753453e4 1697 if (p->type & CUPS_PRINTER_COVER)
20e0a4cb 1698 {
753453e4 1699 if (finishings[0])
def978d5 1700 strlcat(finishings, ",cover", sizeof(finishings));
753453e4 1701 else
1702 strcpy(finishings, "cover");
20e0a4cb 1703 }
1704
753453e4 1705 if (p->type & CUPS_PRINTER_SORT)
20e0a4cb 1706 {
753453e4 1707 if (finishings[0])
def978d5 1708 strlcat(finishings, ",sort", sizeof(finishings));
20e0a4cb 1709 else
753453e4 1710 strcpy(finishings, "sort");
20e0a4cb 1711 }
753453e4 1712
1713 if (!finishings[0])
1714 strcpy(finishings, "none");
1715
753453e4 1716 /*
25e057a4 1717 * Quote any commas in the make and model, location, and info strings...
753453e4 1718 */
1719
25e057a4 1720 for (src = p->make_model, dst = make_model;
1721 src && *src && dst < (make_model + sizeof(make_model) - 2);)
753453e4 1722 {
1723 if (*src == ',' || *src == '\\' || *src == ')')
1724 *dst++ = '\\';
1725
1726 *dst++ = *src++;
1727 }
1728
1729 *dst = '\0';
1730
1731 if (!make_model[0])
1732 strcpy(make_model, "Unknown");
1733
25e057a4 1734 for (src = p->location, dst = location;
1735 src && *src && dst < (location + sizeof(location) - 2);)
20e0a4cb 1736 {
753453e4 1737 if (*src == ',' || *src == '\\' || *src == ')')
1738 *dst++ = '\\';
1739
1740 *dst++ = *src++;
20e0a4cb 1741 }
1742
753453e4 1743 *dst = '\0';
1744
1745 if (!location[0])
1746 strcpy(location, "Unknown");
1747
25e057a4 1748 for (src = p->info, dst = info;
1749 src && *src && dst < (info + sizeof(info) - 2);)
20e0a4cb 1750 {
753453e4 1751 if (*src == ',' || *src == '\\' || *src == ')')
1752 *dst++ = '\\';
1753
1754 *dst++ = *src++;
20e0a4cb 1755 }
1756
753453e4 1757 *dst = '\0';
1758
1759 if (!info[0])
1760 strcpy(info, "Unknown");
1761
1762 /*
1763 * Get the authentication value...
1764 */
1765
1766 authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
1767 IPP_TAG_KEYWORD);
a2c6b8b1 1768
fb00e262 1769 /*
753453e4 1770 * Make the SLP attribute string list that conforms to
1771 * the IANA 'printer:' template.
fb00e262 1772 */
1773
753453e4 1774 snprintf(attrs, sizeof(attrs),
1775 "(printer-uri-supported=%s),"
1776 "(uri-authentication-supported=%s>),"
bcf61448 1777#ifdef HAVE_SSL
753453e4 1778 "(uri-security-supported=tls>),"
1779#else
1780 "(uri-security-supported=none>),"
bcf61448 1781#endif /* HAVE_SSL */
753453e4 1782 "(printer-name=%s),"
1783 "(printer-location=%s),"
1784 "(printer-info=%s),"
1785 "(printer-more-info=%s),"
1786 "(printer-make-and-model=%s),"
1787 "(charset-supported=utf-8),"
1788 "(natural-language-configured=%s),"
1789 "(natural-language-supported=de,en,es,fr,it),"
1790 "(color-supported=%s),"
1791 "(finishings-supported=%s),"
1792 "(sides-supported=one-sided%s),"
1793 "(multiple-document-jobs-supported=true)"
1794 "(ipp-versions-supported=1.0,1.1)",
1795 p->uri, authentication->values[0].string.text, p->name, location,
1796 info, p->uri, make_model, DefaultLanguage,
1797 p->type & CUPS_PRINTER_COLOR ? "true" : "false",
1798 finishings,
1799 p->type & CUPS_PRINTER_DUPLEX ?
1800 ",two-sided-long-edge,two-sided-short-edge" : "");
1801
f3e786fc 1802 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
fb00e262 1803
8b43895a 1804 /*
753453e4 1805 * Register the printer with the SLP server...
8b43895a 1806 */
1807
753453e4 1808 error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
f3e786fc 1809 SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
753453e4 1810
1811 if (error != SLP_OK)
f3e786fc 1812 cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
1813 error);
753453e4 1814}
1815
1816
1817/*
f3e786fc 1818 * 'slp_dereg_printer()' - SLPDereg() the specified printer
753453e4 1819 */
1820
f3e786fc 1821static void
1822slp_dereg_printer(cupsd_printer_t *p)
753453e4 1823{
1824 char srvurl[HTTP_MAX_URI]; /* Printer service URI */
1825
1826
f3e786fc 1827 cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
903511b4 1828
f3e786fc 1829 if (!(p->type & CUPS_PRINTER_REMOTE))
8b43895a 1830 {
1831 /*
753453e4 1832 * Make the SLP service URL that conforms to the IANA
1833 * 'printer:' template.
8b43895a 1834 */
1835
753453e4 1836 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
b5cb0608 1837
753453e4 1838 /*
1839 * Deregister the printer...
1840 */
b5cb0608 1841
f3e786fc 1842 SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
753453e4 1843 }
1844}
8b43895a 1845
8b43895a 1846
753453e4 1847/*
f3e786fc 1848 * 'slp_get_attr()' - Get an attribute from an SLP registration.
753453e4 1849 */
8b43895a 1850
f3e786fc 1851static int /* O - 0 on success */
1852slp_get_attr(const char *attrlist, /* I - Attribute list string */
1853 const char *tag, /* I - Name of attribute */
1854 char **valbuf) /* O - Value */
753453e4 1855{
1856 char *ptr1, /* Pointer into string */
1857 *ptr2; /* ... */
1858
1859
589eb420 1860 cupsdClearString(valbuf);
753453e4 1861
1862 if ((ptr1 = strstr(attrlist, tag)) != NULL)
1863 {
1864 ptr1 += strlen(tag);
1865
1866 if ((ptr2 = strchr(ptr1,')')) != NULL)
1867 {
a782f61f 1868 /*
1869 * Copy the value...
1870 */
8b43895a 1871
25e057a4 1872 *valbuf = calloc(ptr2 - ptr1 + 1, 1);
1873 strncpy(*valbuf, ptr1, ptr2 - ptr1);
a782f61f 1874
1875 /*
1876 * Dequote the value...
1877 */
4139b718 1878
f2bdef84 1879 for (ptr1 = *valbuf; *ptr1; ptr1 ++)
a782f61f 1880 if (*ptr1 == '\\' && ptr1[1])
e22bb235 1881 _cups_strcpy(ptr1, ptr1 + 1);
20da3efb 1882
a782f61f 1883 return (0);
753453e4 1884 }
1885 }
8b43895a 1886
753453e4 1887 return (-1);
1888}
8b43895a 1889
8b43895a 1890
753453e4 1891/*
f3e786fc 1892 * 'slp_attr_callback()' - SLP attribute callback
753453e4 1893 */
8b43895a 1894
f3e786fc 1895static SLPBoolean /* O - SLP_TRUE for success */
1896slp_attr_callback(
1897 SLPHandle hslp, /* I - SLP handle */
1898 const char *attrlist, /* I - Attribute list */
1899 SLPError errcode, /* I - Parsing status for this attr */
1900 void *cookie) /* I - Current printer */
753453e4 1901{
f3e786fc 1902 char *tmp = 0;
1903 cupsd_printer_t *p = (cupsd_printer_t*)cookie;
8b43895a 1904
8b43895a 1905
753453e4 1906 /*
1907 * Let the compiler know we won't be using these...
1908 */
8b43895a 1909
753453e4 1910 (void)hslp;
782359ca 1911
753453e4 1912 /*
1913 * Bail if there was an error
1914 */
782359ca 1915
753453e4 1916 if (errcode != SLP_OK)
1917 return (SLP_TRUE);
782359ca 1918
753453e4 1919 /*
1920 * Parse the attrlist to obtain things needed to build CUPS browse packet
1921 */
1922
589eb420 1923 memset(p, 0, sizeof(cupsd_printer_t));
753453e4 1924
1925 p->type = CUPS_PRINTER_REMOTE;
1926
f3e786fc 1927 if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
753453e4 1928 return (SLP_FALSE);
f3e786fc 1929 if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
d6d2f8e2 1930 return (SLP_FALSE);
f3e786fc 1931 if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
753453e4 1932 return (SLP_FALSE);
1933
f3e786fc 1934 if (slp_get_attr(attrlist, "(color-supported=", &tmp))
753453e4 1935 return (SLP_FALSE);
1936 if (strcasecmp(tmp, "true") == 0)
1937 p->type |= CUPS_PRINTER_COLOR;
1938
f3e786fc 1939 if (slp_get_attr(attrlist, "(finishings-supported=", &tmp))
753453e4 1940 return (SLP_FALSE);
1941 if (strstr(tmp, "staple"))
1942 p->type |= CUPS_PRINTER_STAPLE;
1943 if (strstr(tmp, "bind"))
1944 p->type |= CUPS_PRINTER_BIND;
1945 if (strstr(tmp, "punch"))
1946 p->type |= CUPS_PRINTER_PUNCH;
1947
f3e786fc 1948 if (slp_get_attr(attrlist, "(sides-supported=", &tmp))
753453e4 1949 return (SLP_FALSE);
1950 if (strstr(tmp,"two-sided"))
1951 p->type |= CUPS_PRINTER_DUPLEX;
1952
589eb420 1953 cupsdClearString(&tmp);
a782f61f 1954
753453e4 1955 return (SLP_TRUE);
fd8b1cf8 1956}
1957
1958
d6de4648 1959/*
f3e786fc 1960 * 'slp_url_callback()' - SLP service url callback
d6de4648 1961 */
1962
f3e786fc 1963static SLPBoolean /* O - TRUE = OK, FALSE = error */
1964slp_url_callback(
1965 SLPHandle hslp, /* I - SLP handle */
1966 const char *srvurl, /* I - URL of service */
1967 unsigned short lifetime, /* I - Life of service */
1968 SLPError errcode, /* I - Existing error code */
1969 void *cookie) /* I - Pointer to service list */
fd8b1cf8 1970{
753453e4 1971 slpsrvurl_t *s, /* New service entry */
1972 **head; /* Pointer to head of entry */
d6de4648 1973
1974
753453e4 1975 /*
1976 * Let the compiler know we won't be using these vars...
1977 */
1978
1979 (void)hslp;
1980 (void)lifetime;
f63a2256 1981
d6de4648 1982 /*
753453e4 1983 * Bail if there was an error
d6de4648 1984 */
1985
753453e4 1986 if (errcode != SLP_OK)
1987 return (SLP_TRUE);
d6de4648 1988
1989 /*
753453e4 1990 * Grab the head of the list...
d6de4648 1991 */
1992
753453e4 1993 head = (slpsrvurl_t**)cookie;
d6de4648 1994
753453e4 1995 /*
1996 * Allocate a *temporary* slpsrvurl_t to hold this entry.
1997 */
d6de4648 1998
753453e4 1999 if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
2000 return (SLP_FALSE);
d6de4648 2001
753453e4 2002 /*
2003 * Copy the SLP service URL...
2004 */
d6de4648 2005
def978d5 2006 strlcpy(s->url, srvurl, sizeof(s->url));
a2c6b8b1 2007
753453e4 2008 /*
2009 * Link the SLP service URL into the head of the list
2010 */
d6de4648 2011
753453e4 2012 if (*head)
2013 s->next = *head;
d6de4648 2014
753453e4 2015 *head = s;
f63a2256 2016
753453e4 2017 return (SLP_TRUE);
fd8b1cf8 2018}
a129ddbd 2019
2020
2021/*
589eb420 2022 * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
03081fd2 2023 */
2024
2025void
589eb420 2026cupsdUpdateSLPBrowse(void)
03081fd2 2027{
753453e4 2028 slpsrvurl_t *s, /* Temporary list of service URLs */
2029 *next; /* Next service in list */
589eb420 2030 cupsd_printer_t p; /* Printer information */
753453e4 2031 const char *uri; /* Pointer to printer URI */
2032 char method[HTTP_MAX_URI], /* Method portion of URI */
2033 username[HTTP_MAX_URI], /* Username portion of URI */
2034 host[HTTP_MAX_URI], /* Host portion of URI */
2035 resource[HTTP_MAX_URI]; /* Resource portion of URI */
2036 int port; /* Port portion of URI */
e5ebb675 2037
2038
f3e786fc 2039 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdUpdateSLPBrowse() Start...");
b1ac1113 2040
753453e4 2041 /*
2042 * Reset the refresh time...
2043 */
e5ebb675 2044
c75e768d 2045 BrowseSLPRefresh = time(NULL) + BrowseInterval;
e5ebb675 2046
753453e4 2047 /*
2048 * Poll for remote printers using SLP...
2049 */
e5ebb675 2050
753453e4 2051 s = NULL;
5aeb433c 2052
753453e4 2053 SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
f3e786fc 2054 slp_url_callback, &s);
5aeb433c 2055
753453e4 2056 /*
2057 * Loop through the list of available printers...
2058 */
2059
2060 for (; s; s = next)
2061 {
e0ba31cd 2062 /*
2063 * Save the "next" pointer...
2064 */
2065
2066 next = s->next;
2067
753453e4 2068 /*
589eb420 2069 * Load a cupsd_printer_t structure with the SLP service attributes...
753453e4 2070 */
2071
f3e786fc 2072 SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
753453e4 2073
2074 /*
2075 * Process this printer entry...
2076 */
2077
2078 uri = s->url + SLP_CUPS_SRVLEN + 1;
5aeb433c 2079
753453e4 2080 if (strncmp(uri, "http://", 7) == 0 ||
2081 strncmp(uri, "ipp://", 6) == 0)
2082 {
5aeb433c 2083 /*
753453e4 2084 * Pull the URI apart to see if this is a local or remote printer...
5aeb433c 2085 */
2086
753453e4 2087 httpSeparate(uri, method, username, host, &port, resource);
2088
2089 if (strcasecmp(host, ServerName) == 0)
2090 continue;
5aeb433c 2091
2092 /*
753453e4 2093 * OK, at least an IPP printer, see if it is a CUPS printer or
2094 * class...
5aeb433c 2095 */
e5ebb675 2096
753453e4 2097 if (strstr(uri, "/printers/") != NULL)
589eb420 2098 cupsdProcessBrowseData(uri, p.type, IPP_PRINTER_IDLE, p.location,
753453e4 2099 p.info, p.make_model);
2100 else if (strstr(uri, "/classes/") != NULL)
589eb420 2101 cupsdProcessBrowseData(uri, p.type | CUPS_PRINTER_CLASS, IPP_PRINTER_IDLE,
753453e4 2102 p.location, p.info, p.make_model);
e5ebb675 2103 }
03081fd2 2104
753453e4 2105 /*
e0ba31cd 2106 * Free this listing...
753453e4 2107 */
e5ebb675 2108
753453e4 2109 free(s);
2110 }
e5ebb675 2111
f3e786fc 2112 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdUpdateSLPBrowse() End...");
03081fd2 2113}
753453e4 2114#endif /* HAVE_LIBSLP */
03081fd2 2115
2116
2117/*
b2e10895 2118 * End of "$Id$".
a129ddbd 2119 */