]>
Commit | Line | Data |
---|---|---|
a129ddbd | 1 | /* |
1a5606a3 | 2 | * "$Id: dirsvc.c,v 1.41 1999/09/17 19:11:46 mike Exp $" |
a129ddbd | 3 | * |
d6de4648 | 4 | * Directory services routines for the Common UNIX Printing System (CUPS). |
a129ddbd | 5 | * |
a9de544f | 6 | * Copyright 1997-1999 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 | * | |
cbbfcc63 | 26 | * StartBrowsing() - Start sending and receiving broadcast information. |
27 | * StopBrowsing() - Stop sending and receiving broadcast information. | |
28 | * UpdateBrowseList() - Update the browse lists for any new browse data. | |
29 | * SendBrowseList() - Send new browsing information. | |
a129ddbd | 30 | */ |
31 | ||
32 | /* | |
33 | * Include necessary headers... | |
34 | */ | |
35 | ||
fd8b1cf8 | 36 | #include "cupsd.h" |
37 | ||
38 | ||
d6de4648 | 39 | /* |
40 | * 'StartBrowsing()' - Start sending and receiving broadcast information. | |
41 | */ | |
42 | ||
fd8b1cf8 | 43 | void |
44 | StartBrowsing(void) | |
45 | { | |
d6de4648 | 46 | int val; /* Socket option value */ |
47 | struct sockaddr_in addr; /* Broadcast address */ | |
48 | ||
49 | ||
8828fd5f | 50 | if (!Browsing) |
d6de4648 | 51 | return; |
52 | ||
53 | /* | |
54 | * Create the broadcast socket... | |
55 | */ | |
56 | ||
900b10ea | 57 | if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) |
d6de4648 | 58 | { |
59 | LogMessage(LOG_ERROR, "StartBrowsing: Unable to create broadcast socket - %s.", | |
60 | strerror(errno)); | |
61 | return; | |
62 | } | |
63 | ||
64 | /* | |
900b10ea | 65 | * Set the "broadcast" flag... |
d6de4648 | 66 | */ |
67 | ||
68 | val = 1; | |
e9e40963 | 69 | if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val))) |
fd3ece61 | 70 | { |
71 | LogMessage(LOG_ERROR, "StartBrowsing: Unable to set broadcast mode - %s.", | |
72 | strerror(errno)); | |
73 | ||
74 | #if defined(WIN32) || defined(__EMX__) | |
75 | closesocket(BrowseSocket); | |
76 | #else | |
77 | close(BrowseSocket); | |
78 | #endif /* WIN32 || __EMX__ */ | |
79 | ||
80 | BrowseSocket = -1; | |
81 | return; | |
82 | } | |
d6de4648 | 83 | |
d6de4648 | 84 | /* |
85 | * Bind the socket to browse port... | |
86 | */ | |
87 | ||
d6de4648 | 88 | memset(&addr, 0, sizeof(addr)); |
89 | addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
90 | addr.sin_family = AF_INET; | |
91 | addr.sin_port = htons(BrowsePort); | |
92 | ||
16b0a852 | 93 | if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr))) |
d6de4648 | 94 | { |
95 | LogMessage(LOG_ERROR, "StartBrowsing: Unable to bind broadcast socket - %s.", | |
96 | strerror(errno)); | |
97 | ||
98 | #if defined(WIN32) || defined(__EMX__) | |
99 | closesocket(BrowseSocket); | |
100 | #else | |
101 | close(BrowseSocket); | |
102 | #endif /* WIN32 || __EMX__ */ | |
103 | ||
104 | BrowseSocket = -1; | |
105 | return; | |
106 | } | |
107 | ||
108 | /* | |
109 | * Finally, add the socket to the input selection set... | |
110 | */ | |
111 | ||
112 | FD_SET(BrowseSocket, &InputSet); | |
fd8b1cf8 | 113 | } |
114 | ||
115 | ||
d6de4648 | 116 | /* |
117 | * 'StopBrowsing()' - Stop sending and receiving broadcast information. | |
118 | */ | |
119 | ||
fd8b1cf8 | 120 | void |
121 | StopBrowsing(void) | |
122 | { | |
8828fd5f | 123 | if (!Browsing) |
d6de4648 | 124 | return; |
125 | ||
126 | /* | |
127 | * Close the socket and remove it from the input selection set. | |
128 | */ | |
129 | ||
3c7bb4a2 | 130 | if (BrowseSocket >= 0) |
131 | { | |
d6de4648 | 132 | #if defined(WIN32) || defined(__EMX__) |
3c7bb4a2 | 133 | closesocket(BrowseSocket); |
d6de4648 | 134 | #else |
3c7bb4a2 | 135 | close(BrowseSocket); |
d6de4648 | 136 | #endif /* WIN32 || __EMX__ */ |
137 | ||
3c7bb4a2 | 138 | FD_CLR(BrowseSocket, &InputSet); |
139 | } | |
fd8b1cf8 | 140 | } |
141 | ||
142 | ||
d6de4648 | 143 | /* |
144 | * 'UpdateBrowseList()' - Update the browse lists for any new browse data. | |
145 | */ | |
146 | ||
fd8b1cf8 | 147 | void |
148 | UpdateBrowseList(void) | |
149 | { | |
8b43895a | 150 | int i; /* Looping var */ |
eef5ad1b | 151 | int len, /* Length of name string */ |
152 | offset; /* Offset in name string */ | |
d6de4648 | 153 | int bytes; /* Number of bytes left */ |
154 | char packet[1540]; /* Broadcast packet */ | |
155 | cups_ptype_t type; /* Printer type */ | |
156 | ipp_pstate_t state; /* Printer state */ | |
157 | char uri[HTTP_MAX_URI], /* Printer URI */ | |
158 | method[HTTP_MAX_URI], /* Method portion of URI */ | |
159 | username[HTTP_MAX_URI], /* Username portion of URI */ | |
160 | host[HTTP_MAX_URI], /* Host portion of URI */ | |
161 | resource[HTTP_MAX_URI]; /* Resource portion of URI */ | |
162 | int port; /* Port portion of URI */ | |
163 | char name[IPP_MAX_NAME], /* Name of printer */ | |
8b43895a | 164 | *hptr, /* Pointer into hostname */ |
165 | *sptr; /* Pointer into ServerName */ | |
166 | printer_t *p, /* Printer information */ | |
167 | *pclass, /* Printer class */ | |
168 | *first; /* First printer in class */ | |
d6de4648 | 169 | |
170 | ||
171 | /* | |
172 | * Read a packet from the browse socket... | |
173 | */ | |
174 | ||
18d7d592 | 175 | #ifdef DEBUG |
176 | struct sockaddr_in addr; | |
18d7d592 | 177 | |
178 | ||
179 | len = sizeof(addr); | |
16b0a852 | 180 | if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet), 0, |
181 | (struct sockaddr *)&addr, &len)) <= 0) | |
18d7d592 | 182 | { |
1a5606a3 | 183 | LogMessage(LOG_ERROR, "Browse recv failed - %s.", |
18d7d592 | 184 | strerror(errno)); |
1a5606a3 | 185 | LogMessage(LOG_ERROR, "Browsing turned off."); |
186 | ||
187 | StopBrowsing(); | |
188 | Browsing = 0; | |
18d7d592 | 189 | return; |
190 | } | |
191 | ||
192 | packet[bytes] = '\0'; | |
193 | printf("UpdateBrowseList: (%d bytes from %08x) %s", bytes, | |
194 | ntohl(addr.sin_addr.s_addr), packet); | |
195 | #else | |
d6de4648 | 196 | if ((bytes = recv(BrowseSocket, packet, sizeof(packet), 0)) <= 0) |
f9bacabb | 197 | { |
1a5606a3 | 198 | LogMessage(LOG_ERROR, "Browse recv failed - %s.", |
8828fd5f | 199 | strerror(errno)); |
1a5606a3 | 200 | LogMessage(LOG_ERROR, "Browsing turned off."); |
201 | ||
202 | StopBrowsing(); | |
203 | Browsing = 0; | |
d6de4648 | 204 | return; |
f9bacabb | 205 | } |
d6de4648 | 206 | |
207 | packet[bytes] = '\0'; | |
18d7d592 | 208 | #endif /* DEBUG */ |
d6de4648 | 209 | |
210 | if (sscanf(packet, "%x%x%s", &type, &state, uri) != 3) | |
211 | { | |
212 | LogMessage(LOG_WARN, "UpdateBrowseList: Garbled browse packet - %s", | |
213 | packet); | |
214 | return; | |
215 | } | |
216 | ||
a8b216d5 | 217 | DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n", type, state, uri)); |
218 | ||
d6de4648 | 219 | /* |
220 | * Pull the URI apart to see if this is a local or remote printer... | |
221 | */ | |
222 | ||
223 | httpSeparate(uri, method, username, host, &port, resource); | |
224 | ||
a8b216d5 | 225 | DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName)); |
226 | ||
d6de4648 | 227 | if (strcasecmp(host, ServerName) == 0) |
228 | return; | |
229 | ||
230 | /* | |
231 | * OK, this isn't a local printer; see if we already have it listed in | |
232 | * the Printers list, and add it if not... | |
233 | */ | |
234 | ||
8b43895a | 235 | hptr = strchr(host, '.'); |
236 | sptr = strchr(ServerName, '.'); | |
237 | ||
238 | if (hptr != NULL && sptr != NULL && | |
239 | strcasecmp(hptr, sptr) == 0) | |
240 | *hptr = '\0'; | |
d6de4648 | 241 | |
c7fa9d06 | 242 | if (type & CUPS_PRINTER_CLASS) |
d6de4648 | 243 | { |
244 | /* | |
c7fa9d06 | 245 | * Remote destination is a class... |
d6de4648 | 246 | */ |
247 | ||
c7fa9d06 | 248 | if (strncmp(resource, "/classes/", 9) == 0) |
a71f40c4 | 249 | sprintf(name, "%s@%s", resource + 9, host); |
c7fa9d06 | 250 | else |
251 | return; | |
252 | ||
253 | if ((p = FindClass(name)) == NULL) | |
a71f40c4 | 254 | if ((p = FindClass(resource + 9)) != NULL) |
eef5ad1b | 255 | { |
a71f40c4 | 256 | if (strcasecmp(p->hostname, host) != 0) |
257 | { | |
258 | /* | |
259 | * Nope, this isn't the same host; if the hostname isn't the local host, | |
260 | * add it to the other class and then find a class using the full host | |
261 | * name... | |
262 | */ | |
263 | ||
18d7d592 | 264 | if (p->type & CUPS_PRINTER_REMOTE) |
a71f40c4 | 265 | { |
266 | strcat(p->name, "@"); | |
267 | strcat(p->name, p->hostname); | |
23050703 | 268 | SetPrinterAttrs(p); |
1cab4605 | 269 | SortPrinters(); |
a71f40c4 | 270 | } |
271 | ||
272 | p = NULL; | |
273 | } | |
eef5ad1b | 274 | } |
275 | else | |
276 | strcpy(name, resource + 9); | |
a71f40c4 | 277 | |
278 | if (p == NULL) | |
c7fa9d06 | 279 | { |
280 | /* | |
281 | * Class doesn't exist; add it... | |
282 | */ | |
d6de4648 | 283 | |
782359ca | 284 | p = AddClass(name); |
c7fa9d06 | 285 | |
286 | /* | |
782359ca | 287 | * Force the URI to point to the real server... |
c7fa9d06 | 288 | */ |
289 | ||
5057ad3b | 290 | p->type = type; |
c7fa9d06 | 291 | strcpy(p->uri, uri); |
292 | strcpy(p->device_uri, uri); | |
67a6c918 | 293 | strcpy(p->hostname, host); |
5057ad3b | 294 | SetPrinterAttrs(p); |
c7fa9d06 | 295 | } |
296 | } | |
297 | else | |
298 | { | |
d6de4648 | 299 | /* |
c7fa9d06 | 300 | * Remote destination is a printer... |
d6de4648 | 301 | */ |
302 | ||
c7fa9d06 | 303 | if (strncmp(resource, "/printers/", 10) == 0) |
a71f40c4 | 304 | sprintf(name, "%s@%s", resource + 10, host); |
c7fa9d06 | 305 | else |
306 | return; | |
307 | ||
308 | if ((p = FindPrinter(name)) == NULL) | |
a71f40c4 | 309 | if ((p = FindPrinter(resource + 10)) != NULL) |
eef5ad1b | 310 | { |
a71f40c4 | 311 | if (strcasecmp(p->hostname, host) != 0) |
312 | { | |
313 | /* | |
314 | * Nope, this isn't the same host; if the hostname isn't the local host, | |
315 | * add it to the other printer and then find a printer using the full host | |
316 | * name... | |
317 | */ | |
318 | ||
18d7d592 | 319 | if (p->type & CUPS_PRINTER_REMOTE) |
a71f40c4 | 320 | { |
321 | strcat(p->name, "@"); | |
322 | strcat(p->name, p->hostname); | |
23050703 | 323 | SetPrinterAttrs(p); |
1cab4605 | 324 | SortPrinters(); |
a71f40c4 | 325 | } |
326 | ||
327 | p = NULL; | |
328 | } | |
eef5ad1b | 329 | } |
330 | else | |
331 | strcpy(name, resource + 10); | |
a71f40c4 | 332 | |
333 | if (p == NULL) | |
c7fa9d06 | 334 | { |
335 | /* | |
336 | * Printer doesn't exist; add it... | |
337 | */ | |
338 | ||
339 | p = AddPrinter(name); | |
340 | ||
341 | /* | |
5057ad3b | 342 | * Force the URI to point to the real server... |
c7fa9d06 | 343 | */ |
344 | ||
5057ad3b | 345 | p->type = type; |
c7fa9d06 | 346 | strcpy(p->uri, uri); |
347 | strcpy(p->device_uri, uri); | |
67a6c918 | 348 | strcpy(p->hostname, host); |
5057ad3b | 349 | SetPrinterAttrs(p); |
c7fa9d06 | 350 | } |
d6de4648 | 351 | } |
352 | ||
353 | /* | |
354 | * Update the state... | |
355 | */ | |
356 | ||
f925c8de | 357 | p->type = type; |
d6de4648 | 358 | p->state = state; |
0948b55b | 359 | p->accepting = state != IPP_PRINTER_STOPPED; |
d6de4648 | 360 | p->browse_time = time(NULL); |
8b43895a | 361 | |
fb00e262 | 362 | /* |
4621b86f | 363 | * See if we have a default printer... If not, make the first printer the |
364 | * default. | |
fb00e262 | 365 | */ |
366 | ||
367 | if (DefaultPrinter == NULL && Printers != NULL) | |
368 | DefaultPrinter = Printers; | |
369 | ||
8b43895a | 370 | /* |
371 | * Do auto-classing if needed... | |
372 | */ | |
373 | ||
374 | if (ImplicitClasses) | |
375 | { | |
376 | /* | |
377 | * Loop through all available printers and create classes as needed... | |
378 | */ | |
379 | ||
eef5ad1b | 380 | for (p = Printers, len = 0, offset = 0; p != NULL; p = p->next) |
8b43895a | 381 | { |
382 | /* | |
383 | * Skip classes... | |
384 | */ | |
385 | ||
386 | if (p->type & CUPS_PRINTER_CLASS) | |
387 | { | |
388 | len = 0; | |
389 | continue; | |
390 | } | |
391 | ||
392 | /* | |
393 | * If len == 0, get the length of this printer name up to the "@" | |
394 | * sign (if any). | |
395 | */ | |
396 | ||
397 | if (len > 0 && | |
eef5ad1b | 398 | strncasecmp(p->name, name + offset, len) == 0 && |
8b43895a | 399 | (p->name[len] == '\0' || p->name[len] == '@')) |
400 | { | |
401 | /* | |
402 | * We have more than one printer with the same name; see if | |
403 | * we have a class, and if this printer is a member... | |
404 | */ | |
405 | ||
406 | if ((pclass = FindClass(name)) == NULL) | |
18d7d592 | 407 | { |
4139b718 | 408 | /* |
409 | * Need to add the class... | |
410 | */ | |
411 | ||
8b43895a | 412 | pclass = AddClass(name); |
4139b718 | 413 | pclass->type |= CUPS_PRINTER_IMPLICIT; |
414 | pclass->accepting = 1; | |
415 | pclass->state = IPP_PRINTER_IDLE; | |
416 | ||
417 | SetPrinterAttrs(pclass); | |
20da3efb | 418 | |
419 | DEBUG_printf(("Added new class \"%s\", type = %x\n", name, | |
420 | pclass->type)); | |
18d7d592 | 421 | } |
8b43895a | 422 | |
423 | if (first != NULL) | |
424 | { | |
425 | for (i = 0; i < pclass->num_printers; i ++) | |
426 | if (pclass->printers[i] == first) | |
427 | break; | |
428 | ||
429 | if (i >= pclass->num_printers) | |
430 | AddPrinterToClass(pclass, first); | |
431 | ||
432 | first = NULL; | |
433 | } | |
434 | ||
435 | for (i = 0; i < pclass->num_printers; i ++) | |
436 | if (pclass->printers[i] == p) | |
437 | break; | |
438 | ||
439 | if (i >= pclass->num_printers) | |
440 | AddPrinterToClass(pclass, p); | |
441 | } | |
442 | else | |
443 | { | |
444 | /* | |
445 | * First time around; just get name length and mark it as first | |
446 | * in the list... | |
447 | */ | |
448 | ||
449 | if ((hptr = strchr(p->name, '@')) != NULL) | |
450 | len = hptr - p->name; | |
451 | else | |
452 | len = strlen(p->name); | |
453 | ||
782359ca | 454 | strncpy(name, p->name, len); |
455 | name[len] = '\0'; | |
eef5ad1b | 456 | offset = 0; |
782359ca | 457 | |
458 | if (FindPrinter(name) != NULL) | |
459 | { | |
460 | /* | |
461 | * Can't use same name as printer; add "Any" to the front of the | |
462 | * name... | |
463 | */ | |
464 | ||
465 | strcpy(name, "Any"); | |
466 | strncpy(name + 3, p->name, len); | |
467 | name[len + 3] = '\0'; | |
eef5ad1b | 468 | offset = 3; |
782359ca | 469 | } |
470 | ||
8b43895a | 471 | first = p; |
472 | } | |
473 | } | |
474 | } | |
fd8b1cf8 | 475 | } |
476 | ||
477 | ||
d6de4648 | 478 | /* |
479 | * 'SendBrowseList()' - Send new browsing information. | |
480 | */ | |
481 | ||
fd8b1cf8 | 482 | void |
483 | SendBrowseList(void) | |
484 | { | |
d6de4648 | 485 | int i; /* Looping var */ |
486 | printer_t *p, /* Current printer */ | |
487 | *np; /* Next printer */ | |
f9d6449d | 488 | time_t ut, /* Minimum update time */ |
489 | to; /* Timeout time */ | |
d6de4648 | 490 | int bytes; /* Length of packet */ |
491 | char packet[1540]; | |
492 | /* Browse data packet */ | |
493 | ||
494 | ||
495 | /* | |
496 | * Compute the update time... | |
497 | */ | |
498 | ||
f9d6449d | 499 | ut = time(NULL) - BrowseInterval; |
500 | to = time(NULL) - BrowseTimeout; | |
d6de4648 | 501 | |
502 | /* | |
503 | * Loop through all of the printers and send local updates as needed... | |
504 | */ | |
505 | ||
506 | for (p = Printers; p != NULL; p = np) | |
507 | { | |
508 | np = p->next; | |
509 | ||
510 | if (p->type & CUPS_PRINTER_REMOTE) | |
511 | { | |
512 | /* | |
513 | * See if this printer needs to be timed out... | |
514 | */ | |
515 | ||
f9d6449d | 516 | if (p->browse_time < to) |
e63d9801 | 517 | { |
518 | DEBUG_printf(("Printer \"%s\" has timed out (%d < %d...)\n", | |
519 | p->name, p->browse_time, to)); | |
d6de4648 | 520 | DeletePrinter(p); |
e63d9801 | 521 | } |
d6de4648 | 522 | } |
18d7d592 | 523 | else if (p->browse_time < ut && !(p->type & CUPS_PRINTER_IMPLICIT)) |
d6de4648 | 524 | { |
525 | /* | |
526 | * Need to send an update... | |
527 | */ | |
528 | ||
529 | p->browse_time = time(NULL); | |
530 | ||
ae5f9b38 | 531 | sprintf(packet, "%x %x %s\n", p->type | CUPS_PRINTER_REMOTE, p->state, |
532 | p->uri); | |
d6de4648 | 533 | bytes = strlen(packet); |
8828fd5f | 534 | DEBUG_printf(("SendBrowseList: (%d bytes) %s", bytes, packet)); |
d6de4648 | 535 | |
536 | /* | |
537 | * Send a packet to each browse address... | |
538 | */ | |
539 | ||
540 | for (i = 0; i < NumBrowsers; i ++) | |
16b0a852 | 541 | if (sendto(BrowseSocket, packet, bytes, 0, |
542 | (struct sockaddr *)Browsers + i, sizeof(Browsers[0])) <= 0) | |
8828fd5f | 543 | LogMessage(LOG_ERROR, "SendBrowseList: sendto failed for browser %d - %s.", |
fd3ece61 | 544 | i + 1, strerror(errno)); |
d6de4648 | 545 | } |
546 | } | |
fd8b1cf8 | 547 | } |
a129ddbd | 548 | |
549 | ||
550 | /* | |
1a5606a3 | 551 | * End of "$Id: dirsvc.c,v 1.41 1999/09/17 19:11:46 mike Exp $". |
a129ddbd | 552 | */ |