]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/dirsvc.c
Copyright update.
[thirdparty/cups.git] / scheduler / dirsvc.c
1 /*
2 * "$Id: dirsvc.c,v 1.73.2.20 2003/01/07 18:27:19 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 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 if (iface->broadcast.addr.sa_family == AF_INET)
631 {
632 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
633
634 sendto(BrowseSocket, packet, bytes, 0,
635 (struct sockaddr *)&(iface->broadcast),
636 sizeof(struct sockaddr_in));
637 }
638 else
639 {
640 iface->broadcast.ipv6.sin6_port = htons(BrowsePort);
641
642 sendto(BrowseSocket, packet, bytes, 0,
643 (struct sockaddr *)&(iface->broadcast),
644 sizeof(struct sockaddr_in6));
645 }
646 }
647 }
648 else if ((iface = NetIFFind(b->iface)) != NULL)
649 {
650 /*
651 * Send to the named interface...
652 */
653
654 snprintf(packet, sizeof(packet), "%x %x ipp://%s/%s/%s \"%s\" \"%s\" \"%s\"\n",
655 p->type | CUPS_PRINTER_REMOTE, p->state, iface->hostname,
656 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
657 p->name, p->location, p->info, p->make_model);
658
659 bytes = strlen(packet);
660
661 LogMessage(L_DEBUG2, "SendBrowseList: (%d bytes to \"%s\") %s", bytes,
662 iface->name, packet);
663
664 if (iface->broadcast.addr.sa_family == AF_INET)
665 {
666 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
667
668 sendto(BrowseSocket, packet, bytes, 0,
669 (struct sockaddr *)&(iface->broadcast),
670 sizeof(struct sockaddr_in));
671 }
672 else
673 {
674 iface->broadcast.ipv6.sin6_port = htons(BrowsePort);
675
676 sendto(BrowseSocket, packet, bytes, 0,
677 (struct sockaddr *)&(iface->broadcast),
678 sizeof(struct sockaddr_in6));
679 }
680 }
681 }
682 else
683 {
684 /*
685 * Send the browse packet to the indicated address using
686 * the default server name...
687 */
688
689 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"\n",
690 p->type | CUPS_PRINTER_REMOTE, p->state, p->uri,
691 p->location, p->info, p->make_model);
692
693 bytes = strlen(packet);
694 LogMessage(L_DEBUG2, "SendBrowseList: (%d bytes) %s", bytes, packet);
695
696 if (sendto(BrowseSocket, packet, bytes, 0,
697 (struct sockaddr *)&(b->to),
698 b->to.addr.sa_family == AF_INET ?
699 sizeof(struct sockaddr_in) :
700 sizeof(struct sockaddr_in6)) <= 0)
701 {
702 /*
703 * Unable to send browse packet, so remove this address from the
704 * list...
705 */
706
707 LogMessage(L_ERROR, "SendBrowseList: sendto failed for browser %d - %s.",
708 b - Browsers + 1, strerror(errno));
709
710 if (i > 1)
711 memcpy(b, b + 1, (i - 1) * sizeof(dirsvc_addr_t));
712
713 b --;
714 NumBrowsers --;
715 }
716 }
717 }
718
719
720 /*
721 * 'StartBrowsing()' - Start sending and receiving broadcast information.
722 */
723
724 void
725 StartBrowsing(void)
726 {
727 int val; /* Socket option value */
728 struct sockaddr_in addr; /* Broadcast address */
729
730
731 if (!Browsing)
732 return;
733
734 if (BrowseProtocols & BROWSE_CUPS)
735 {
736 /*
737 * Create the broadcast socket...
738 */
739
740 if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
741 {
742 LogMessage(L_ERROR, "StartBrowsing: Unable to create broadcast socket - %s.",
743 strerror(errno));
744 Browsing = 0;
745 return;
746 }
747
748 /*
749 * Set the "broadcast" flag...
750 */
751
752 val = 1;
753 if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
754 {
755 LogMessage(L_ERROR, "StartBrowsing: Unable to set broadcast mode - %s.",
756 strerror(errno));
757
758 #ifdef WIN32
759 closesocket(BrowseSocket);
760 #else
761 close(BrowseSocket);
762 #endif /* WIN32 */
763
764 BrowseSocket = -1;
765 Browsing = 0;
766 return;
767 }
768
769 /*
770 * Bind the socket to browse port...
771 */
772
773 memset(&addr, 0, sizeof(addr));
774 addr.sin_addr.s_addr = htonl(INADDR_ANY);
775 addr.sin_family = AF_INET;
776 addr.sin_port = htons(BrowsePort);
777
778 if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
779 {
780 LogMessage(L_ERROR, "StartBrowsing: Unable to bind broadcast socket - %s.",
781 strerror(errno));
782
783 #ifdef WIN32
784 closesocket(BrowseSocket);
785 #else
786 close(BrowseSocket);
787 #endif /* WIN32 */
788
789 BrowseSocket = -1;
790 Browsing = 0;
791 return;
792 }
793
794 /*
795 * Finally, add the socket to the input selection set...
796 */
797
798 LogMessage(L_DEBUG2, "StartBrowsing: Adding fd %d to InputSet...",
799 BrowseSocket);
800
801 FD_SET(BrowseSocket, &InputSet);
802 }
803
804 #ifdef HAVE_LIBSLP
805 if (BrowseProtocols & BROWSE_SLP)
806 {
807 /*
808 * Open SLP handle...
809 */
810
811 if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
812 {
813 LogMessage(L_ERROR, "Unable to open an SLP handle; disabling SLP browsing!");
814 BrowseProtocols &= ~BROWSE_SLP;
815 }
816
817 BrowseSLPRefresh = 0;
818 }
819 #endif /* HAVE_LIBSLP */
820 }
821
822
823 /*
824 * 'StartPolling()' - Start polling servers as needed.
825 */
826
827 void
828 StartPolling(void)
829 {
830 int i; /* Looping var */
831 dirsvc_poll_t *poll; /* Current polling server */
832 int pid; /* New process ID */
833 char sport[10]; /* Server port */
834 char bport[10]; /* Browser port */
835 char interval[10]; /* Poll interval */
836 int statusfds[2]; /* Status pipe */
837 int fd; /* Current file descriptor */
838
839
840 /*
841 * Don't do anything if we aren't polling...
842 */
843
844 if (NumPolled == 0)
845 {
846 PollPipe = -1;
847 return;
848 }
849
850 /*
851 * Setup string arguments for port and interval options.
852 */
853
854 sprintf(bport, "%d", BrowsePort);
855
856 if (BrowseInterval)
857 sprintf(interval, "%d", BrowseInterval);
858 else
859 strcpy(interval, "30");
860
861 /*
862 * Create a pipe that receives the status messages from each
863 * polling daemon...
864 */
865
866 if (pipe(statusfds))
867 {
868 LogMessage(L_ERROR, "Unable to create polling status pipes - %s.",
869 strerror(errno));
870 PollPipe = -1;
871 return;
872 }
873
874 PollPipe = statusfds[0];
875
876 /*
877 * Run each polling daemon, redirecting stderr to the polling pipe...
878 */
879
880 for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
881 {
882 sprintf(sport, "%d", poll->port);
883
884 if ((pid = fork()) == 0)
885 {
886 /*
887 * Child...
888 */
889
890 if (getuid() == 0)
891 {
892 /*
893 * Running as root, so change to non-priviledged user...
894 */
895
896 if (setgid(Group))
897 exit(errno);
898
899 if (setuid(User))
900 exit(errno);
901 }
902
903 /*
904 * Reset group membership to just the main one we belong to.
905 */
906
907 setgroups(0, NULL);
908
909 /*
910 * Redirect stdin and stdout to /dev/null, and stderr to the
911 * status pipe. Close all other files.
912 */
913
914 close(0);
915 open("/dev/null", O_RDONLY);
916
917 close(1);
918 open("/dev/null", O_WRONLY);
919
920 close(2);
921 dup(statusfds[1]);
922
923 for (fd = 3; fd < MaxFDs; fd ++)
924 close(fd);
925
926 /*
927 * Execute the polling daemon...
928 */
929
930 execl(CUPS_SERVERBIN "/daemon/cups-polld", "cups-polld", poll->hostname,
931 sport, interval, bport, NULL);
932 exit(errno);
933 }
934 else if (pid < 0)
935 {
936 LogMessage(L_ERROR, "StartPolling: Unable to fork polling daemon - %s",
937 strerror(errno));
938 poll->pid = 0;
939 break;
940 }
941 else
942 {
943 poll->pid = pid;
944 LogMessage(L_DEBUG, "StartPolling: Started polling daemon for %s:%d, pid = %d",
945 poll->hostname, poll->port, pid);
946 }
947 }
948
949 close(statusfds[1]);
950
951 /*
952 * Finally, add the pipe to the input selection set...
953 */
954
955 LogMessage(L_DEBUG2, "StartPolling: Adding fd %d to InputSet...",
956 PollPipe);
957
958 FD_SET(PollPipe, &InputSet);
959 }
960
961
962 /*
963 * 'StopBrowsing()' - Stop sending and receiving broadcast information.
964 */
965
966 void
967 StopBrowsing(void)
968 {
969 if (!Browsing)
970 return;
971
972 if (BrowseProtocols & BROWSE_CUPS)
973 {
974 /*
975 * Close the socket and remove it from the input selection set.
976 */
977
978 if (BrowseSocket >= 0)
979 {
980 #ifdef WIN32
981 closesocket(BrowseSocket);
982 #else
983 close(BrowseSocket);
984 #endif /* WIN32 */
985
986 LogMessage(L_DEBUG2, "StopBrowsing: Removing fd %d from InputSet...",
987 BrowseSocket);
988
989 FD_CLR(BrowseSocket, &InputSet);
990 BrowseSocket = 0;
991 }
992 }
993
994 #ifdef HAVE_LIBSLP
995 if (BrowseProtocols & BROWSE_SLP)
996 {
997 /*
998 * Close SLP handle...
999 */
1000
1001 SLPClose(BrowseSLPHandle);
1002 }
1003 #endif /* HAVE_LIBSLP */
1004 }
1005
1006
1007 /*
1008 * 'StopPolling()' - Stop polling servers as needed.
1009 */
1010
1011 void
1012 StopPolling(void)
1013 {
1014 int i; /* Looping var */
1015 dirsvc_poll_t *poll; /* Current polling server */
1016
1017
1018 if (PollPipe >= 0)
1019 {
1020 close(PollPipe);
1021
1022 LogMessage(L_DEBUG2, "StopPolling: removing fd %d from InputSet.",
1023 PollPipe);
1024 FD_CLR(PollPipe, &InputSet);
1025
1026 PollPipe = -1;
1027 }
1028
1029 for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
1030 if (poll->pid)
1031 kill(poll->pid, SIGTERM);
1032 }
1033
1034
1035 /*
1036 * 'UpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol.
1037 */
1038
1039 void
1040 UpdateCUPSBrowse(void)
1041 {
1042 int i; /* Looping var */
1043 int auth; /* Authorization status */
1044 int len; /* Length of name string */
1045 int bytes; /* Number of bytes left */
1046 char packet[1540], /* Broadcast packet */
1047 *pptr; /* Pointer into packet */
1048 http_addr_t srcaddr; /* Source address */
1049 char srcname[1024]; /* Source hostname */
1050 unsigned address[4], /* Source address */
1051 temp; /* Temporary address var (host order) */
1052 cups_ptype_t type; /* Printer type */
1053 ipp_pstate_t state; /* Printer state */
1054 char uri[HTTP_MAX_URI], /* Printer URI */
1055 method[HTTP_MAX_URI], /* Method portion of URI */
1056 username[HTTP_MAX_URI], /* Username portion of URI */
1057 host[HTTP_MAX_URI], /* Host portion of URI */
1058 resource[HTTP_MAX_URI], /* Resource portion of URI */
1059 info[IPP_MAX_NAME], /* Information string */
1060 location[IPP_MAX_NAME], /* Location string */
1061 make_model[IPP_MAX_NAME];/* Make and model string */
1062 int port; /* Port portion of URI */
1063 cups_netif_t *iface; /* Network interface */
1064
1065
1066 /*
1067 * Read a packet from the browse socket...
1068 */
1069
1070 len = sizeof(srcaddr);
1071 if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet), 0,
1072 (struct sockaddr *)&srcaddr, &len)) <= 0)
1073 {
1074 /*
1075 * "Connection refused" is returned under Linux if the destination port
1076 * or address is unreachable from a previous sendto(); check for the
1077 * error here and ignore it for now...
1078 */
1079
1080 if (errno != ECONNREFUSED)
1081 {
1082 LogMessage(L_ERROR, "Browse recv failed - %s.", strerror(errno));
1083 LogMessage(L_ERROR, "Browsing turned off.");
1084
1085 StopBrowsing();
1086 Browsing = 0;
1087 }
1088
1089 return;
1090 }
1091
1092 packet[bytes] = '\0';
1093
1094 /*
1095 * Figure out where it came from...
1096 */
1097
1098 #ifdef AF_INET6
1099 if (srcaddr.addr.sa_family == AF_INET6)
1100 {
1101 address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
1102 address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
1103 address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
1104 address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
1105 }
1106 else
1107 #endif /* AF_INET6 */
1108 {
1109 temp = ntohl(srcaddr.ipv4.sin_addr.s_addr);
1110
1111 address[3] = temp & 255;
1112 temp >>= 8;
1113 address[2] = temp & 255;
1114 temp >>= 8;
1115 address[1] = temp & 255;
1116 temp >>= 8;
1117 address[0] = temp & 255;
1118 }
1119
1120 if (HostNameLookups)
1121 httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
1122 else
1123 httpAddrString(&srcaddr, srcname, sizeof(srcname));
1124
1125 len = strlen(srcname);
1126
1127 /*
1128 * Do ACL stuff...
1129 */
1130
1131 if (BrowseACL && (BrowseACL->num_allow || BrowseACL->num_deny))
1132 {
1133 if (httpAddrLocalhost(&srcaddr) || strcasecmp(srcname, "localhost") == 0)
1134 {
1135 /*
1136 * Access from localhost (127.0.0.1) is always allowed...
1137 */
1138
1139 auth = AUTH_ALLOW;
1140 }
1141 else
1142 {
1143 /*
1144 * Do authorization checks on the domain/address...
1145 */
1146
1147 switch (BrowseACL->order_type)
1148 {
1149 default :
1150 auth = AUTH_DENY; /* anti-compiler-warning-code */
1151 break;
1152
1153 case AUTH_ALLOW : /* Order Deny,Allow */
1154 auth = AUTH_ALLOW;
1155
1156 if (CheckAuth(address, srcname, len,
1157 BrowseACL->num_deny, BrowseACL->deny))
1158 auth = AUTH_DENY;
1159
1160 if (CheckAuth(address, srcname, len,
1161 BrowseACL->num_allow, BrowseACL->allow))
1162 auth = AUTH_ALLOW;
1163 break;
1164
1165 case AUTH_DENY : /* Order Allow,Deny */
1166 auth = AUTH_DENY;
1167
1168 if (CheckAuth(address, srcname, len,
1169 BrowseACL->num_allow, BrowseACL->allow))
1170 auth = AUTH_ALLOW;
1171
1172 if (CheckAuth(address, srcname, len,
1173 BrowseACL->num_deny, BrowseACL->deny))
1174 auth = AUTH_DENY;
1175 break;
1176 }
1177 }
1178 }
1179 else
1180 auth = AUTH_ALLOW;
1181
1182 if (auth == AUTH_DENY)
1183 {
1184 LogMessage(L_DEBUG, "UpdateCUPSBrowse: Refused %d bytes from %s", bytes,
1185 srcname);
1186 return;
1187 }
1188
1189 LogMessage(L_DEBUG2, "UpdateCUPSBrowse: (%d bytes from %s) %s", bytes, srcname,
1190 packet);
1191
1192 /*
1193 * Parse packet...
1194 */
1195
1196 if (sscanf(packet, "%x%x%1023s", (unsigned *)&type, (unsigned *)&state,
1197 uri) < 3)
1198 {
1199 LogMessage(L_WARN, "UpdateCUPSBrowse: Garbled browse packet - %s",
1200 packet);
1201 return;
1202 }
1203
1204 strcpy(location, "Location Unknown");
1205 strcpy(info, "No Information Available");
1206 make_model[0] = '\0';
1207
1208 if ((pptr = strchr(packet, '\"')) != NULL)
1209 {
1210 /*
1211 * Have extended information; can't use sscanf for it because not all
1212 * sscanf's allow empty strings with %[^\"]...
1213 */
1214
1215 for (i = 0, pptr ++;
1216 i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
1217 i ++, pptr ++)
1218 location[i] = *pptr;
1219
1220 if (i)
1221 location[i] = '\0';
1222
1223 if (*pptr == '\"')
1224 pptr ++;
1225
1226 while (*pptr && isspace(*pptr))
1227 pptr ++;
1228
1229 if (*pptr == '\"')
1230 {
1231 for (i = 0, pptr ++;
1232 i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
1233 i ++, pptr ++)
1234 info[i] = *pptr;
1235
1236 if (i)
1237 info[i] = '\0';
1238
1239 if (*pptr == '\"')
1240 pptr ++;
1241
1242 while (*pptr && isspace(*pptr))
1243 pptr ++;
1244
1245 if (*pptr == '\"')
1246 {
1247 for (i = 0, pptr ++;
1248 i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
1249 i ++, pptr ++)
1250 make_model[i] = *pptr;
1251
1252 if (i)
1253 make_model[i] = '\0';
1254 }
1255 }
1256 }
1257
1258 DEBUG_puts(packet);
1259 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
1260 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
1261 type, state, uri, location, info, make_model));
1262
1263 /*
1264 * Pull the URI apart to see if this is a local or remote printer...
1265 */
1266
1267 httpSeparate(uri, method, username, host, &port, resource);
1268
1269 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
1270
1271 /*
1272 * Check for packets from the local server...
1273 */
1274
1275 if (strcasecmp(host, ServerName) == 0)
1276 return;
1277
1278 NetIFUpdate();
1279
1280 for (iface = NetIFList; iface != NULL; iface = iface->next)
1281 if (strcasecmp(host, iface->hostname) == 0)
1282 return;
1283
1284 /*
1285 * Do relaying...
1286 */
1287
1288 for (i = 0; i < NumRelays; i ++)
1289 if (CheckAuth(address, srcname, len, 1, &(Relays[i].from)))
1290 if (sendto(BrowseSocket, packet, bytes, 0,
1291 (struct sockaddr *)&(Relays[i].to),
1292 sizeof(http_addr_t)) <= 0)
1293 {
1294 LogMessage(L_ERROR, "UpdateCUPSBrowse: sendto failed for relay %d - %s.",
1295 i + 1, strerror(errno));
1296 return;
1297 }
1298
1299 /*
1300 * Process the browse data...
1301 */
1302
1303 ProcessBrowseData(uri, type, state, location, info, make_model);
1304 }
1305
1306
1307 /*
1308 * 'UpdatePolling()' - Read status messages from the poll daemons.
1309 */
1310
1311 void
1312 UpdatePolling(void)
1313 {
1314 int bytes; /* Number of bytes read */
1315 char *lineptr; /* Pointer to end of line in buffer */
1316 static int bufused = 0; /* Number of bytes used in buffer */
1317 static char buffer[1024]; /* Status buffer */
1318
1319
1320 if ((bytes = read(PollPipe, buffer + bufused,
1321 sizeof(buffer) - bufused - 1)) > 0)
1322 {
1323 bufused += bytes;
1324 buffer[bufused] = '\0';
1325 lineptr = strchr(buffer, '\n');
1326 }
1327 else if (bytes < 0 && errno == EINTR)
1328 return;
1329 else
1330 {
1331 lineptr = buffer + bufused;
1332 lineptr[1] = 0;
1333 }
1334
1335 if (bytes == 0 && bufused == 0)
1336 lineptr = NULL;
1337
1338 while (lineptr != NULL)
1339 {
1340 /*
1341 * Terminate each line and process it...
1342 */
1343
1344 *lineptr++ = '\0';
1345
1346 LogMessage(L_ERROR, "%s", buffer);
1347
1348 /*
1349 * Copy over the buffer data we've used up...
1350 */
1351
1352 strcpy(buffer, lineptr);
1353 bufused -= lineptr - buffer;
1354
1355 if (bufused < 0)
1356 bufused = 0;
1357
1358 lineptr = strchr(buffer, '\n');
1359 }
1360
1361 if (bytes <= 0)
1362 {
1363 /*
1364 * All polling processes have died; stop polling...
1365 */
1366
1367 LogMessage(L_ERROR, "UpdatePolling: all polling processes have exited!");
1368 StopPolling();
1369 }
1370 }
1371
1372
1373 /***********************************************************************
1374 **** SLP Support Code *************************************************
1375 ***********************************************************************/
1376
1377 #ifdef HAVE_LIBSLP
1378 /*
1379 * SLP service name for CUPS...
1380 */
1381
1382 # define SLP_CUPS_SRVTYPE "service:printer"
1383 # define SLP_CUPS_SRVLEN 15
1384
1385 typedef struct _slpsrvurl
1386 {
1387 struct _slpsrvurl *next;
1388 char url[HTTP_MAX_URI];
1389 } slpsrvurl_t;
1390
1391
1392 /*
1393 * 'RegReportCallback()' - Empty SLPRegReport.
1394 */
1395
1396 void
1397 RegReportCallback(SLPHandle hslp,
1398 SLPError errcode,
1399 void *cookie)
1400 {
1401 (void)hslp;
1402 (void)errcode;
1403 (void)cookie;
1404
1405 return;
1406 }
1407
1408
1409 /*
1410 * 'SendSLPBrowse()' - Register the specified printer with SLP.
1411 */
1412
1413 void
1414 SendSLPBrowse(printer_t *p) /* I - Printer to register */
1415 {
1416 char srvurl[HTTP_MAX_URI], /* Printer service URI */
1417 attrs[8192], /* Printer attributes */
1418 finishings[1024], /* Finishings to support */
1419 make_model[IPP_MAX_NAME * 2],
1420 /* Make and model, quoted */
1421 location[IPP_MAX_NAME * 2],
1422 /* Location, quoted */
1423 info[IPP_MAX_NAME * 2],
1424 /* Info, quoted */
1425 *src, /* Pointer to original string */
1426 *dst; /* Pointer to destination string */
1427 ipp_attribute_t *authentication; /* uri-authentication-supported value */
1428 SLPError error; /* SLP error, if any */
1429
1430
1431 LogMessage(L_DEBUG, "SendSLPBrowse(%p = \"%s\")", p, p->name);
1432
1433 /*
1434 * Make the SLP service URL that conforms to the IANA
1435 * 'printer:' template.
1436 */
1437
1438 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
1439
1440 LogMessage(L_DEBUG2, "Service URL = \"%s\"", srvurl);
1441
1442 /*
1443 * Figure out the finishings string...
1444 */
1445
1446 if (p->type & CUPS_PRINTER_STAPLE)
1447 strcpy(finishings, "staple");
1448 else
1449 finishings[0] = '\0';
1450
1451 if (p->type & CUPS_PRINTER_BIND)
1452 {
1453 if (finishings[0])
1454 strlcat(finishings, ",bind", sizeof(finishings));
1455 else
1456 strcpy(finishings, "bind");
1457 }
1458
1459 if (p->type & CUPS_PRINTER_PUNCH)
1460 {
1461 if (finishings[0])
1462 strlcat(finishings, ",punch", sizeof(finishings));
1463 else
1464 strcpy(finishings, "punch");
1465 }
1466
1467 if (p->type & CUPS_PRINTER_COVER)
1468 {
1469 if (finishings[0])
1470 strlcat(finishings, ",cover", sizeof(finishings));
1471 else
1472 strcpy(finishings, "cover");
1473 }
1474
1475 if (p->type & CUPS_PRINTER_SORT)
1476 {
1477 if (finishings[0])
1478 strlcat(finishings, ",sort", sizeof(finishings));
1479 else
1480 strcpy(finishings, "sort");
1481 }
1482
1483 if (!finishings[0])
1484 strcpy(finishings, "none");
1485
1486 /*
1487 * Quote any commas in the make and model, location, and info strings
1488 * (local strings are twice the size of the ones in the printer_t
1489 * structure, so no buffer overflow is possible...)
1490 */
1491
1492 for (src = p->make_model, dst = make_model; *src;)
1493 {
1494 if (*src == ',' || *src == '\\' || *src == ')')
1495 *dst++ = '\\';
1496
1497 *dst++ = *src++;
1498 }
1499
1500 *dst = '\0';
1501
1502 if (!make_model[0])
1503 strcpy(make_model, "Unknown");
1504
1505 for (src = p->location, dst = location; *src;)
1506 {
1507 if (*src == ',' || *src == '\\' || *src == ')')
1508 *dst++ = '\\';
1509
1510 *dst++ = *src++;
1511 }
1512
1513 *dst = '\0';
1514
1515 if (!location[0])
1516 strcpy(location, "Unknown");
1517
1518 for (src = p->info, dst = info; *src;)
1519 {
1520 if (*src == ',' || *src == '\\' || *src == ')')
1521 *dst++ = '\\';
1522
1523 *dst++ = *src++;
1524 }
1525
1526 *dst = '\0';
1527
1528 if (!info[0])
1529 strcpy(info, "Unknown");
1530
1531 /*
1532 * Get the authentication value...
1533 */
1534
1535 authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
1536 IPP_TAG_KEYWORD);
1537
1538 /*
1539 * Make the SLP attribute string list that conforms to
1540 * the IANA 'printer:' template.
1541 */
1542
1543 snprintf(attrs, sizeof(attrs),
1544 "(printer-uri-supported=%s),"
1545 "(uri-authentication-supported=%s>),"
1546 #ifdef HAVE_LIBSSL
1547 "(uri-security-supported=tls>),"
1548 #else
1549 "(uri-security-supported=none>),"
1550 #endif /* HAVE_LIBSSL */
1551 "(printer-name=%s),"
1552 "(printer-location=%s),"
1553 "(printer-info=%s),"
1554 "(printer-more-info=%s),"
1555 "(printer-make-and-model=%s),"
1556 "(charset-supported=utf-8),"
1557 "(natural-language-configured=%s),"
1558 "(natural-language-supported=de,en,es,fr,it),"
1559 "(color-supported=%s),"
1560 "(finishings-supported=%s),"
1561 "(sides-supported=one-sided%s),"
1562 "(multiple-document-jobs-supported=true)"
1563 "(ipp-versions-supported=1.0,1.1)",
1564 p->uri, authentication->values[0].string.text, p->name, location,
1565 info, p->uri, make_model, DefaultLanguage,
1566 p->type & CUPS_PRINTER_COLOR ? "true" : "false",
1567 finishings,
1568 p->type & CUPS_PRINTER_DUPLEX ?
1569 ",two-sided-long-edge,two-sided-short-edge" : "");
1570
1571 LogMessage(L_DEBUG2, "Attributes = \"%s\"", attrs);
1572
1573 /*
1574 * Register the printer with the SLP server...
1575 */
1576
1577 error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
1578 SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, RegReportCallback, 0);
1579
1580 if (error != SLP_OK)
1581 LogMessage(L_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
1582 error);
1583 }
1584
1585
1586 /*
1587 * 'SLPDeregPrinter()' - SLPDereg() the specified printer
1588 */
1589
1590 void
1591 SLPDeregPrinter(printer_t *p)
1592 {
1593 char srvurl[HTTP_MAX_URI]; /* Printer service URI */
1594
1595
1596 if((p->type & CUPS_PRINTER_REMOTE) == 0)
1597 {
1598 /*
1599 * Make the SLP service URL that conforms to the IANA
1600 * 'printer:' template.
1601 */
1602
1603 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
1604
1605 /*
1606 * Deregister the printer...
1607 */
1608
1609 SLPDereg(BrowseSLPHandle, srvurl, RegReportCallback, 0);
1610 }
1611 }
1612
1613
1614 /*
1615 * 'GetSlpAttrVal()' - Get an attribute from an SLP registration.
1616 */
1617
1618 int /* O - 0 on success */
1619 GetSlpAttrVal(const char *attrlist, /* I - Attribute list string */
1620 const char *tag, /* I - Name of attribute */
1621 char *valbuf, /* O - Value */
1622 int valbuflen) /* I - Max length of value */
1623 {
1624 char *ptr1, /* Pointer into string */
1625 *ptr2; /* ... */
1626
1627
1628 valbuf[0] = '\0';
1629
1630 if ((ptr1 = strstr(attrlist, tag)) != NULL)
1631 {
1632 ptr1 += strlen(tag);
1633
1634 if ((ptr2 = strchr(ptr1,')')) != NULL)
1635 {
1636 if (valbuflen > (ptr2 - ptr1))
1637 {
1638 /*
1639 * Copy the value...
1640 */
1641
1642 strncpy(valbuf, ptr1, ptr2 - ptr1);
1643 valbuf[ptr2 - ptr1] = '\0';
1644
1645 /*
1646 * Dequote the value...
1647 */
1648
1649 for (ptr1 = valbuf; *ptr1; ptr1 ++)
1650 if (*ptr1 == '\\' && ptr1[1])
1651 strcpy(ptr1, ptr1 + 1);
1652
1653 return (0);
1654 }
1655 }
1656 }
1657
1658 return (-1);
1659 }
1660
1661
1662 /*
1663 * 'AttrCallback()' - SLP attribute callback
1664 */
1665
1666 SLPBoolean
1667 AttrCallback(SLPHandle hslp,
1668 const char *attrlist,
1669 SLPError errcode,
1670 void *cookie)
1671 {
1672 char tmp[IPP_MAX_NAME];
1673 printer_t *p = (printer_t*)cookie;
1674
1675
1676 /*
1677 * Let the compiler know we won't be using these...
1678 */
1679
1680 (void)hslp;
1681
1682 /*
1683 * Bail if there was an error
1684 */
1685
1686 if (errcode != SLP_OK)
1687 return (SLP_TRUE);
1688
1689 /*
1690 * Parse the attrlist to obtain things needed to build CUPS browse packet
1691 */
1692
1693 memset(p, 0, sizeof(printer_t));
1694
1695 p->type = CUPS_PRINTER_REMOTE;
1696
1697 if (GetSlpAttrVal(attrlist, "(printer-location=", p->location,
1698 sizeof(p->location)))
1699 return (SLP_FALSE);
1700 if (GetSlpAttrVal(attrlist, "(printer-make-and-model=", p->make_model,
1701 sizeof(p->make_model)))
1702 return (SLP_FALSE);
1703
1704 if (GetSlpAttrVal(attrlist, "(color-supported=", tmp, sizeof(tmp)))
1705 return (SLP_FALSE);
1706 if (strcasecmp(tmp, "true") == 0)
1707 p->type |= CUPS_PRINTER_COLOR;
1708
1709 if (GetSlpAttrVal(attrlist, "(finishings-supported=", tmp, sizeof(tmp)))
1710 return (SLP_FALSE);
1711 if (strstr(tmp, "staple"))
1712 p->type |= CUPS_PRINTER_STAPLE;
1713 if (strstr(tmp, "bind"))
1714 p->type |= CUPS_PRINTER_BIND;
1715 if (strstr(tmp, "punch"))
1716 p->type |= CUPS_PRINTER_PUNCH;
1717
1718 if (GetSlpAttrVal(attrlist, "(sides-supported=", tmp, sizeof(tmp)))
1719 return (SLP_FALSE);
1720 if (strstr(tmp,"two-sided"))
1721 p->type |= CUPS_PRINTER_DUPLEX;
1722
1723 return (SLP_TRUE);
1724 }
1725
1726
1727 /*
1728 * 'SrvUrlCallback()' - SLP service url callback
1729 */
1730
1731 SLPBoolean /* O - TRUE = OK, FALSE = error */
1732 SrvUrlCallback(SLPHandle hslp, /* I - SLP handle */
1733 const char *srvurl, /* I - URL of service */
1734 unsigned short lifetime, /* I - Life of service */
1735 SLPError errcode, /* I - Existing error code */
1736 void *cookie) /* I - Pointer to service list */
1737 {
1738 slpsrvurl_t *s, /* New service entry */
1739 **head; /* Pointer to head of entry */
1740
1741
1742 /*
1743 * Let the compiler know we won't be using these vars...
1744 */
1745
1746 (void)hslp;
1747 (void)lifetime;
1748
1749 /*
1750 * Bail if there was an error
1751 */
1752
1753 if (errcode != SLP_OK)
1754 return (SLP_TRUE);
1755
1756 /*
1757 * Grab the head of the list...
1758 */
1759
1760 head = (slpsrvurl_t**)cookie;
1761
1762 /*
1763 * Allocate a *temporary* slpsrvurl_t to hold this entry.
1764 */
1765
1766 if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
1767 return (SLP_FALSE);
1768
1769 /*
1770 * Copy the SLP service URL...
1771 */
1772
1773 strlcpy(s->url, srvurl, sizeof(s->url));
1774
1775 /*
1776 * Link the SLP service URL into the head of the list
1777 */
1778
1779 if (*head)
1780 s->next = *head;
1781
1782 *head = s;
1783
1784 return (SLP_TRUE);
1785 }
1786
1787
1788 /*
1789 * 'UpdateSLPBrowse()' - Get browsing information via SLP.
1790 */
1791
1792 void
1793 UpdateSLPBrowse(void)
1794 {
1795 slpsrvurl_t *s, /* Temporary list of service URLs */
1796 *next; /* Next service in list */
1797 printer_t p; /* Printer information */
1798 const char *uri; /* Pointer to printer URI */
1799 char method[HTTP_MAX_URI], /* Method portion of URI */
1800 username[HTTP_MAX_URI], /* Username portion of URI */
1801 host[HTTP_MAX_URI], /* Host portion of URI */
1802 resource[HTTP_MAX_URI]; /* Resource portion of URI */
1803 int port; /* Port portion of URI */
1804
1805
1806 LogMessage(L_DEBUG, "UpdateSLPBrowse() Start...");
1807
1808 /*
1809 * Reset the refresh time...
1810 */
1811
1812 BrowseSLPRefresh = time(NULL) + BrowseTimeout - BrowseInterval;
1813
1814 /*
1815 * Poll for remote printers using SLP...
1816 */
1817
1818 s = NULL;
1819
1820 SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
1821 SrvUrlCallback, &s);
1822
1823 /*
1824 * Loop through the list of available printers...
1825 */
1826
1827 for (; s; s = next)
1828 {
1829 /*
1830 * Save the "next" pointer...
1831 */
1832
1833 next = s->next;
1834
1835 /*
1836 * Load a printer_t structure with the SLP service attributes...
1837 */
1838
1839 SLPFindAttrs(BrowseSLPHandle, s->url, "", "", AttrCallback, &p);
1840
1841 /*
1842 * Process this printer entry...
1843 */
1844
1845 uri = s->url + SLP_CUPS_SRVLEN + 1;
1846
1847 if (strncmp(uri, "http://", 7) == 0 ||
1848 strncmp(uri, "ipp://", 6) == 0)
1849 {
1850 /*
1851 * Pull the URI apart to see if this is a local or remote printer...
1852 */
1853
1854 httpSeparate(uri, method, username, host, &port, resource);
1855
1856 if (strcasecmp(host, ServerName) == 0)
1857 continue;
1858
1859 /*
1860 * OK, at least an IPP printer, see if it is a CUPS printer or
1861 * class...
1862 */
1863
1864 if (strstr(uri, "/printers/") != NULL)
1865 ProcessBrowseData(uri, p.type, IPP_PRINTER_IDLE, p.location,
1866 p.info, p.make_model);
1867 else if (strstr(uri, "/classes/") != NULL)
1868 ProcessBrowseData(uri, p.type | CUPS_PRINTER_CLASS, IPP_PRINTER_IDLE,
1869 p.location, p.info, p.make_model);
1870 }
1871
1872 /*
1873 * Free this listing...
1874 */
1875
1876 free(s);
1877 }
1878
1879 LogMessage(L_DEBUG, "UpdateSLPBrowse() End...");
1880 }
1881 #endif /* HAVE_LIBSLP */
1882
1883
1884 /*
1885 * End of "$Id: dirsvc.c,v 1.73.2.20 2003/01/07 18:27:19 mike Exp $".
1886 */