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