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