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