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