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