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