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