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