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