]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/dirsvc.c
Write printcap file as needed from callers to add/delete printer/class and
[thirdparty/cups.git] / scheduler / dirsvc.c
CommitLineData
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 *
9b4efe89 26 * cupsdLoadRemoteCache() - Load the remote printer cache.
27 * cupsdProcessBrowseData() - Process new browse data.
28 * cupsdProcessImplicitClasses() - Create/update implicit classes as needed.
29 * cupsdSaveRemoteCache() - Save the remote printer cache.
30 * cupsdSendBrowseDelete() - Send a "browse delete" message for a
31 * printer.
32 * cupsdSendBrowseList() - Send new browsing information as necessary.
33 * cupsdSendCUPSBrowse() - Send new browsing information using the
34 * CUPS protocol.
35 * cupsdSendSLPBrowse() - Register the specified printer with SLP.
36 * cupsdStartBrowsing() - Start sending and receiving broadcast
37 * information.
38 * cupsdStartPolling() - Start polling servers as needed.
39 * cupsdStopBrowsing() - Stop sending and receiving broadcast
40 * information.
41 * cupsdStopPolling() - Stop polling servers as needed.
42 * cupsdUpdateCUPSBrowse() - Update the browse lists using the CUPS
43 * protocol.
44 * cupsdUpdatePolling() - Read status messages from the poll daemons.
45 * cupsdUpdateSLPBrowse() - Get browsing information via SLP.
46 * slp_attr_callback() - SLP attribute callback
47 * slp_dereg_printer() - SLPDereg() the specified printer
48 * slp_get_attr() - Get an attribute from an SLP registration.
49 * slp_reg_callback() - Empty SLPRegReport.
50 * slp_url_callback() - SLP service url callback
a129ddbd 51 */
52
53/*
54 * Include necessary headers...
55 */
56
fd8b1cf8 57#include "cupsd.h"
7a91f14b 58#include <grp.h>
fd8b1cf8 59
60
e6e44566 61/*
62 * SLP definitions...
63 */
64
65#ifdef HAVE_LIBSLP
66/*
67 * SLP service name for CUPS...
68 */
69
70# define SLP_CUPS_SRVTYPE "service:printer"
71# define SLP_CUPS_SRVLEN 15
72
73
74/*
75 * Printer service URL structure
76 */
77
78typedef struct _slpsrvurl_s /**** SLP URL list ****/
79{
80 struct _slpsrvurl_s *next; /* Next URL in list */
81 char url[HTTP_MAX_URI];
82 /* URL */
83} slpsrvurl_t;
84
85
86/*
87 * Local functions...
88 */
89
90static SLPBoolean slp_attr_callback(SLPHandle hslp, const char *attrlist,
91 SLPError errcode, void *cookie);
92static void slp_dereg_printer(cupsd_printer_t *p);
93static int slp_get_attr(const char *attrlist, const char *tag,
94 char **valbuf);
95static void slp_reg_callback(SLPHandle hslp, SLPError errcode,
96 void *cookie);
97static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl,
98 unsigned short lifetime,
99 SLPError errcode, void *cookie);
903511b4 100#endif /* HAVE_LIBSLP */
101
102
5ca53bd2 103/*
104 * 'cupsdLoadRemoteCache()' - Load the remote printer cache.
105 */
106
107void
108cupsdLoadRemoteCache(void)
109{
9b4efe89 110 cups_file_t *fp; /* remote.cache file */
111 int linenum; /* Current line number */
112 char line[1024], /* Line from file */
113 *value, /* Pointer to value */
114 *valueptr; /* Pointer into value */
115 cupsd_printer_t *p; /* Current printer */
116 time_t now; /* Current time */
117
118
119 /*
120 * Open the remote.cache file...
121 */
122
123 snprintf(line, sizeof(line), "%s/remote.cache", CacheDir);
124 if ((fp = cupsFileOpen(line, "r")) == NULL)
125 return;
126
127 /*
128 * Read printer configurations until we hit EOF...
129 */
130
131 linenum = 0;
132 p = NULL;
133 now = time(NULL);
134
135 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
136 {
137 /*
138 * Decode the directive...
139 */
140
141 if (!strcasecmp(line, "<Printer") ||
142 !strcasecmp(line, "<DefaultPrinter"))
143 {
144 /*
145 * <Printer name> or <DefaultPrinter name>
146 */
147
148 if (p == NULL && value)
149 {
150 /*
151 * Add the printer and a base file type...
152 */
153
154 cupsdLogMessage(CUPSD_LOG_DEBUG,
155 "cupsdLoadRemoteCache: Loading printer %s...", value);
156
157 p = cupsdAddPrinter(value);
158 p->accepting = 1;
159 p->state = IPP_PRINTER_IDLE;
160 p->type |= CUPS_PRINTER_REMOTE;
161 p->browse_time = now + BrowseTimeout;
162
163 /*
164 * Set the default printer as needed...
165 */
166
167 if (!strcasecmp(line, "<DefaultPrinter"))
168 DefaultPrinter = p;
169 }
170 else
171 {
172 cupsdLogMessage(CUPSD_LOG_ERROR,
173 "Syntax error on line %d of remote.cache.", linenum);
174 return;
175 }
176 }
177 else if (!strcasecmp(line, "<Class") ||
178 !strcasecmp(line, "<DefaultClass"))
179 {
180 /*
181 * <Class name> or <DefaultClass name>
182 */
183
184 if (p == NULL && value)
185 {
186 /*
187 * Add the printer and a base file type...
188 */
189
190 cupsdLogMessage(CUPSD_LOG_DEBUG,
191 "cupsdLoadRemoteCache: Loading class %s...", value);
192
193 p = cupsdAddClass(value);
194 p->accepting = 1;
195 p->state = IPP_PRINTER_IDLE;
196 p->type |= CUPS_PRINTER_REMOTE;
197 p->browse_time = now + BrowseTimeout;
198
199 /*
200 * Set the default printer as needed...
201 */
202
203 if (!strcasecmp(line, "<DefaultClass"))
204 DefaultPrinter = p;
205 }
206 else
207 {
208 cupsdLogMessage(CUPSD_LOG_ERROR,
209 "Syntax error on line %d of remote.cache.", linenum);
210 return;
211 }
212 }
213 else if (!strcasecmp(line, "</Printer>") ||
214 !strcasecmp(line, "</Class>"))
215 {
216 if (p != NULL)
217 {
218 /*
219 * Close out the current printer...
220 */
221
222 cupsdSetPrinterAttrs(p);
223
224 p = NULL;
225 }
226 else
227 {
228 cupsdLogMessage(CUPSD_LOG_ERROR,
229 "Syntax error on line %d of remote.cache.", linenum);
230 return;
231 }
232 }
233 else if (!p)
234 {
235 cupsdLogMessage(CUPSD_LOG_ERROR,
236 "Syntax error on line %d of remote.cache.", linenum);
237 return;
238 }
239 else if (!strcasecmp(line, "Info"))
240 {
241 if (value)
242 cupsdSetString(&p->info, value);
243 }
b537a9b8 244 else if (!strcasecmp(line, "MakeModel"))
245 {
246 if (value)
247 cupsdSetString(&p->make_model, value);
248 }
9b4efe89 249 else if (!strcasecmp(line, "Location"))
250 {
251 if (value)
252 cupsdSetString(&p->location, value);
253 }
254 else if (!strcasecmp(line, "DeviceURI"))
255 {
256 if (value)
257 cupsdSetString(&p->device_uri, value);
258 else
259 {
260 cupsdLogMessage(CUPSD_LOG_ERROR,
261 "Syntax error on line %d of remote.cache.", linenum);
262 return;
263 }
264 }
265 else if (!strcasecmp(line, "State"))
266 {
267 /*
268 * Set the initial queue state...
269 */
270
271 if (value && !strcasecmp(value, "idle"))
272 p->state = IPP_PRINTER_IDLE;
273 else if (value && !strcasecmp(value, "stopped"))
274 p->state = IPP_PRINTER_STOPPED;
275 else
276 {
277 cupsdLogMessage(CUPSD_LOG_ERROR,
278 "Syntax error on line %d of remote.cache.", linenum);
279 return;
280 }
281 }
282 else if (!strcasecmp(line, "StateMessage"))
283 {
284 /*
285 * Set the initial queue state message...
286 */
287
288 if (value)
289 strlcpy(p->state_message, value, sizeof(p->state_message));
290 }
291 else if (!strcasecmp(line, "Accepting"))
292 {
293 /*
294 * Set the initial accepting state...
295 */
296
297 if (value &&
298 (!strcasecmp(value, "yes") ||
299 !strcasecmp(value, "on") ||
300 !strcasecmp(value, "true")))
301 p->accepting = 1;
302 else if (value &&
303 (!strcasecmp(value, "no") ||
304 !strcasecmp(value, "off") ||
305 !strcasecmp(value, "false")))
306 p->accepting = 0;
307 else
308 {
309 cupsdLogMessage(CUPSD_LOG_ERROR,
310 "Syntax error on line %d of remote.cache.", linenum);
311 return;
312 }
313 }
314 else if (!strcasecmp(line, "Type"))
315 {
316 if (value)
317 p->type = atoi(value);
318 else
319 {
320 cupsdLogMessage(CUPSD_LOG_ERROR,
321 "Syntax error on line %d of remote.cache.", linenum);
322 return;
323 }
324 }
325 else if (!strcasecmp(line, "BrowseTime"))
326 {
327 if (value)
328 {
329 time_t t = atoi(value);
330
331 if (t > (now + BrowseInterval))
332 p->browse_time = t;
333 }
334 else
335 {
336 cupsdLogMessage(CUPSD_LOG_ERROR,
337 "Syntax error on line %d of remote.cache.", linenum);
338 return;
339 }
340 }
341 else if (!strcasecmp(line, "JobSheets"))
342 {
343 /*
344 * Set the initial job sheets...
345 */
346
347 if (value)
348 {
349 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
350
351 if (*valueptr)
352 *valueptr++ = '\0';
353
354 cupsdSetString(&p->job_sheets[0], value);
355
356 while (isspace(*valueptr & 255))
357 valueptr ++;
358
359 if (*valueptr)
360 {
361 for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
362
363 if (*valueptr)
364 *valueptr++ = '\0';
365
366 cupsdSetString(&p->job_sheets[1], value);
367 }
368 }
369 else
370 {
371 cupsdLogMessage(CUPSD_LOG_ERROR,
372 "Syntax error on line %d of remote.cache.", linenum);
373 return;
374 }
375 }
376 else if (!strcasecmp(line, "AllowUser"))
377 {
378 if (value)
379 {
380 p->deny_users = 0;
381 cupsdAddPrinterUser(p, value);
382 }
383 else
384 {
385 cupsdLogMessage(CUPSD_LOG_ERROR,
386 "Syntax error on line %d of remote.cache.", linenum);
387 return;
388 }
389 }
390 else if (!strcasecmp(line, "DenyUser"))
391 {
392 if (value)
393 {
394 p->deny_users = 1;
395 cupsdAddPrinterUser(p, value);
396 }
397 else
398 {
399 cupsdLogMessage(CUPSD_LOG_ERROR,
400 "Syntax error on line %d of remote.cache.", linenum);
401 return;
402 }
403 }
404 else
405 {
406 /*
407 * Something else we don't understand...
408 */
409
410 cupsdLogMessage(CUPSD_LOG_ERROR,
411 "Unknown configuration directive %s on line %d of remote.cache.",
412 line, linenum);
413 }
414 }
415
416 cupsFileClose(fp);
417
418 /*
419 * Do auto-classing if needed...
420 */
421
422 cupsdProcessImplicitClasses();
5ca53bd2 423}
424
425
753453e4 426/*
589eb420 427 * 'cupsdProcessBrowseData()' - Process new browse data.
753453e4 428 */
429
430void
f3e786fc 431cupsdProcessBrowseData(
5ca53bd2 432 const char *uri, /* I - URI of printer/class */
433 cups_ptype_t type, /* I - Printer type */
434 ipp_pstate_t state, /* I - Printer state */
435 const char *location, /* I - Printer location */
436 const char *info, /* I - Printer information */
437 const char *make_model, /* I - Printer make and model */
438 int num_attrs, /* I - Number of attributes */
439 cups_option_t *attrs) /* I - Attributes */
753453e4 440{
753453e4 441 int update; /* Update printer attributes? */
7d6f99c0 442 char finaluri[HTTP_MAX_URI], /* Final URI for printer */
443 method[HTTP_MAX_URI], /* Method portion of URI */
753453e4 444 username[HTTP_MAX_URI], /* Username portion of URI */
445 host[HTTP_MAX_URI], /* Host portion of URI */
446 resource[HTTP_MAX_URI]; /* Resource portion of URI */
447 int port; /* Port portion of URI */
448 char name[IPP_MAX_NAME], /* Name of printer */
449 *hptr, /* Pointer into hostname */
450 *sptr; /* Pointer into ServerName */
451 char local_make_model[IPP_MAX_NAME];
452 /* Local make and model */
9b4efe89 453 cupsd_printer_t *p; /* Printer information */
5ca53bd2 454 const char *ipp_options; /* ipp-options value */
753453e4 455
456
457 /*
458 * Pull the URI apart to see if this is a local or remote printer...
459 */
460
461 httpSeparate(uri, method, username, host, &port, resource);
462
901b295d 463 /*
464 * Determine if the URI contains any illegal characters in it...
465 */
466
584ef899 467 if (strncmp(uri, "ipp://", 6) || !host[0] ||
468 (strncmp(resource, "/printers/", 10) &&
469 strncmp(resource, "/classes/", 9)))
901b295d 470 {
f3e786fc 471 cupsdLogMessage(CUPSD_LOG_ERROR,
472 "cupsdProcessBrowseData: Bad printer URI in browse data: %s",
473 uri);
901b295d 474 return;
475 }
476
584ef899 477 if (strchr(resource, '?') ||
478 (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
479 (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
901b295d 480 {
f3e786fc 481 cupsdLogMessage(CUPSD_LOG_ERROR,
482 "cupsdProcessBrowseData: Bad resource in browse data: %s",
483 resource);
901b295d 484 return;
485 }
7d6f99c0 486
753453e4 487 /*
7d6f99c0 488 * OK, this isn't a local printer; add any remote options...
489 */
490
5ca53bd2 491 ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
492
7d6f99c0 493 if (BrowseRemoteOptions)
494 {
495 if (BrowseRemoteOptions[0] == '?')
496 {
497 /*
5ca53bd2 498 * Override server-supplied options...
7d6f99c0 499 */
500
5ca53bd2 501 snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
502 }
503 else if (ipp_options)
504 {
7d6f99c0 505 /*
5ca53bd2 506 * Combine the server and local options...
7d6f99c0 507 */
508
5ca53bd2 509 snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
510 BrowseRemoteOptions);
7d6f99c0 511 }
7d6f99c0 512 else
5ca53bd2 513 {
514 /*
515 * Just use the local options...
516 */
517
7d6f99c0 518 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
5ca53bd2 519 }
7d6f99c0 520
5ca53bd2 521 uri = finaluri;
522 }
523 else if (ipp_options)
524 {
7d6f99c0 525 /*
5ca53bd2 526 * Just use the server-supplied options...
7d6f99c0 527 */
528
5ca53bd2 529 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
7d6f99c0 530 uri = finaluri;
531 }
532
533 /*
534 * See if we already have it listed in the Printers list, and add it if not...
753453e4 535 */
536
f33b2b47 537 type |= CUPS_PRINTER_REMOTE;
903511b4 538 type &= ~CUPS_PRINTER_IMPLICIT;
753453e4 539 update = 0;
540 hptr = strchr(host, '.');
541 sptr = strchr(ServerName, '.');
542
543 if (sptr != NULL && hptr != NULL)
544 {
545 /*
546 * Strip the common domain name components...
547 */
548
549 while (hptr != NULL)
550 {
584ef899 551 if (!strcasecmp(hptr, sptr))
753453e4 552 {
553 *hptr = '\0';
554 break;
555 }
556 else
557 hptr = strchr(hptr + 1, '.');
558 }
559 }
560
561 if (type & CUPS_PRINTER_CLASS)
562 {
563 /*
564 * Remote destination is a class...
565 */
566
584ef899 567 if (!strncmp(resource, "/classes/", 9))
753453e4 568 snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
569 else
570 return;
571
589eb420 572 if ((p = cupsdFindClass(name)) == NULL && BrowseShortNames)
753453e4 573 {
589eb420 574 if ((p = cupsdFindClass(resource + 9)) != NULL)
753453e4 575 {
584ef899 576 if (p->hostname && strcasecmp(p->hostname, host))
753453e4 577 {
578 /*
579 * Nope, this isn't the same host; if the hostname isn't the local host,
580 * add it to the other class and then find a class using the full host
581 * name...
582 */
583
584 if (p->type & CUPS_PRINTER_REMOTE)
585 {
f3e786fc 586 cupsdLogMessage(CUPSD_LOG_INFO,
587 "Renamed remote class \"%s\" to \"%s@%s\"...",
588 p->name, p->name, p->hostname);
584ef899 589 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
590 "Class \'%s\' deleted by directory services.",
591 p->name);
592
90231631 593 cupsArrayRemove(Printers, p);
589eb420 594 cupsdSetStringf(&p->name, "%s@%s", p->name, p->hostname);
595 cupsdSetPrinterAttrs(p);
90231631 596 cupsArrayAdd(Printers, p);
584ef899 597
598 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
599 "Class \'%s\' added by directory services.",
600 p->name);
753453e4 601 }
602
603 p = NULL;
604 }
36992080 605 else if (!p->hostname)
753453e4 606 {
584ef899 607 /*
608 * Hostname not set, so this must be a cached remote printer
609 * that was created for a pending print job...
610 */
611
589eb420 612 cupsdSetString(&p->hostname, host);
613 cupsdSetString(&p->uri, uri);
614 cupsdSetString(&p->device_uri, uri);
753453e4 615 update = 1;
616 }
617 }
618 else
584ef899 619 {
620 /*
621 * Use the short name for this shared class.
622 */
623
def978d5 624 strlcpy(name, resource + 9, sizeof(name));
584ef899 625 }
753453e4 626 }
584ef899 627 else if (p && !p->hostname)
753453e4 628 {
584ef899 629 /*
630 * Hostname not set, so this must be a cached remote printer
631 * that was created for a pending print job...
632 */
633
589eb420 634 cupsdSetString(&p->hostname, host);
635 cupsdSetString(&p->uri, uri);
636 cupsdSetString(&p->device_uri, uri);
753453e4 637 update = 1;
638 }
639
584ef899 640 if (!p)
753453e4 641 {
642 /*
643 * Class doesn't exist; add it...
644 */
645
589eb420 646 p = cupsdAddClass(name);
753453e4 647
f3e786fc 648 cupsdLogMessage(CUPSD_LOG_INFO, "Added remote class \"%s\"...", name);
753453e4 649
403be522 650 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
42f94780 651 "Class \'%s\' added by directory services.", name);
652
753453e4 653 /*
654 * Force the URI to point to the real server...
655 */
656
648051ba 657 p->type = type & ~CUPS_PRINTER_REJECTING;
db628f45 658 p->accepting = 1;
589eb420 659 cupsdSetString(&p->uri, uri);
660 cupsdSetString(&p->device_uri, uri);
661 cupsdSetString(&p->hostname, host);
753453e4 662
663 update = 1;
664 }
665 }
666 else
667 {
668 /*
669 * Remote destination is a printer...
670 */
671
672 if (strncmp(resource, "/printers/", 10) == 0)
673 snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
674 else
675 return;
676
589eb420 677 if ((p = cupsdFindPrinter(name)) == NULL && BrowseShortNames)
753453e4 678 {
589eb420 679 if ((p = cupsdFindPrinter(resource + 10)) != NULL)
753453e4 680 {
584ef899 681 if (p->hostname && strcasecmp(p->hostname, host))
753453e4 682 {
683 /*
684 * Nope, this isn't the same host; if the hostname isn't the local host,
685 * add it to the other printer and then find a printer using the full host
686 * name...
687 */
688
689 if (p->type & CUPS_PRINTER_REMOTE)
690 {
f3e786fc 691 cupsdLogMessage(CUPSD_LOG_INFO,
692 "Renamed remote printer \"%s\" to \"%s@%s\"...",
693 p->name, p->name, p->hostname);
584ef899 694 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
695 "Printer \'%s\' deleted by directory services.",
696 p->name);
697
90231631 698 cupsArrayRemove(Printers, p);
589eb420 699 cupsdSetStringf(&p->name, "%s@%s", p->name, p->hostname);
700 cupsdSetPrinterAttrs(p);
90231631 701 cupsArrayAdd(Printers, p);
584ef899 702
703 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
704 "Printer \'%s\' added by directory services.",
705 p->name);
753453e4 706 }
707
708 p = NULL;
709 }
36992080 710 else if (!p->hostname)
753453e4 711 {
584ef899 712 /*
713 * Hostname not set, so this must be a cached remote printer
714 * that was created for a pending print job...
715 */
716
589eb420 717 cupsdSetString(&p->hostname, host);
718 cupsdSetString(&p->uri, uri);
719 cupsdSetString(&p->device_uri, uri);
753453e4 720 update = 1;
721 }
722 }
723 else
584ef899 724 {
725 /*
726 * Use the short name for this shared printer.
727 */
728
def978d5 729 strlcpy(name, resource + 10, sizeof(name));
584ef899 730 }
753453e4 731 }
584ef899 732 else if (p && !p->hostname)
753453e4 733 {
584ef899 734 /*
735 * Hostname not set, so this must be a cached remote printer
736 * that was created for a pending print job...
737 */
738
589eb420 739 cupsdSetString(&p->hostname, host);
740 cupsdSetString(&p->uri, uri);
741 cupsdSetString(&p->device_uri, uri);
753453e4 742 update = 1;
743 }
744
584ef899 745 if (!p)
753453e4 746 {
747 /*
748 * Printer doesn't exist; add it...
749 */
750
589eb420 751 p = cupsdAddPrinter(name);
753453e4 752
403be522 753 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
42f94780 754 "Printer \'%s\' added by directory services.", name);
755
f3e786fc 756 cupsdLogMessage(CUPSD_LOG_INFO, "Added remote printer \"%s\"...", name);
753453e4 757
758 /*
759 * Force the URI to point to the real server...
760 */
761
648051ba 762 p->type = type & ~CUPS_PRINTER_REJECTING;
db628f45 763 p->accepting = 1;
589eb420 764 cupsdSetString(&p->hostname, host);
765 cupsdSetString(&p->uri, uri);
766 cupsdSetString(&p->device_uri, uri);
753453e4 767
768 update = 1;
769 }
770 }
771
772 /*
773 * Update the state...
774 */
775
776 p->state = state;
753453e4 777 p->browse_time = time(NULL);
778
648051ba 779 if (type & CUPS_PRINTER_REJECTING)
780 {
781 type &= ~CUPS_PRINTER_REJECTING;
782
783 if (p->accepting)
784 {
785 update = 1;
786 p->accepting = 0;
787 }
788 }
789 else if (!p->accepting)
790 {
791 update = 1;
792 p->accepting = 1;
793 }
794
753453e4 795 if (p->type != type)
796 {
797 p->type = type;
798 update = 1;
799 }
800
d6d2f8e2 801 if (location && (!p->location || strcmp(p->location, location)))
753453e4 802 {
589eb420 803 cupsdSetString(&p->location, location);
753453e4 804 update = 1;
805 }
806
d6d2f8e2 807 if (info && (!p->info || strcmp(p->info, info)))
753453e4 808 {
589eb420 809 cupsdSetString(&p->info, info);
753453e4 810 update = 1;
811 }
812
d6d2f8e2 813 if (!make_model || !make_model[0])
753453e4 814 {
815 if (type & CUPS_PRINTER_CLASS)
816 snprintf(local_make_model, sizeof(local_make_model),
817 "Remote Class on %s", host);
818 else
819 snprintf(local_make_model, sizeof(local_make_model),
820 "Remote Printer on %s", host);
821 }
822 else
823 snprintf(local_make_model, sizeof(local_make_model),
824 "%s on %s", make_model, host);
825
36992080 826 if (!p->make_model || strcmp(p->make_model, local_make_model))
753453e4 827 {
589eb420 828 cupsdSetString(&p->make_model, local_make_model);
753453e4 829 update = 1;
830 }
831
903511b4 832 if (type & CUPS_PRINTER_DELETE)
833 {
42f94780 834 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
835 "%s \'%s\' deleted by directory services.",
836 (type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", p->name);
837
838 cupsdExpireSubscriptions(p, NULL);
839
589eb420 840 cupsdDeletePrinter(p, 1);
841 cupsdUpdateImplicitClasses();
903511b4 842 }
843 else if (update)
a4f3d51c 844 {
589eb420 845 cupsdSetPrinterAttrs(p);
846 cupsdUpdateImplicitClasses();
a4f3d51c 847 }
753453e4 848
849 /*
850 * See if we have a default printer... If not, make the first printer the
851 * default.
852 */
853
854 if (DefaultPrinter == NULL && Printers != NULL)
589eb420 855 DefaultPrinter = (cupsd_printer_t *)cupsArrayFirst(Printers);
753453e4 856
857 /*
858 * Do auto-classing if needed...
859 */
860
9b4efe89 861 cupsdProcessImplicitClasses();
6d6ad4fd 862
863 /*
864 * Update the printcap file...
865 */
866
867 cupsdWritePrintcap();
9b4efe89 868}
869
870
871/*
872 * 'cupsdProcessImplicitClasses()' - Create/update implicit classes as needed.
873 */
874
875void
876cupsdProcessImplicitClasses(void)
877{
878 int i; /* Looping var */
879 int update; /* Update printer attributes? */
880 char name[IPP_MAX_NAME], /* Name of printer */
881 *hptr; /* Pointer into hostname */
882 cupsd_printer_t *p, /* Printer information */
883 *pclass, /* Printer class */
884 *first; /* First printer in class */
885 int offset, /* Offset of name */
886 len; /* Length of name */
887
888
889 if (!ImplicitClasses || !Printers)
890 return;
891
892 /*
893 * Loop through all available printers and create classes as needed...
894 */
895
896 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
897 update = 0, pclass = NULL, first = NULL;
898 p != NULL;
899 p = (cupsd_printer_t *)cupsArrayNext(Printers))
753453e4 900 {
901 /*
9b4efe89 902 * Skip implicit classes...
753453e4 903 */
904
9b4efe89 905 if (p->type & CUPS_PRINTER_IMPLICIT)
753453e4 906 {
9b4efe89 907 len = 0;
908 continue;
909 }
753453e4 910
9b4efe89 911 /*
912 * If len == 0, get the length of this printer name up to the "@"
913 * sign (if any).
914 */
915
916 cupsArraySave(Printers);
753453e4 917
9b4efe89 918 if (len > 0 &&
919 strncasecmp(p->name, name + offset, len) == 0 &&
920 (p->name[len] == '\0' || p->name[len] == '@'))
921 {
753453e4 922 /*
9b4efe89 923 * We have more than one printer with the same name; see if
924 * we have a class, and if this printer is a member...
753453e4 925 */
926
9b4efe89 927 if (pclass && strcasecmp(pclass->name, name))
928 {
929 if (update)
930 cupsdSetPrinterAttrs(pclass);
931
932 update = 0;
933 pclass = NULL;
934 }
e208121a 935
9b4efe89 936 if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
753453e4 937 {
938 /*
9b4efe89 939 * Need to add the class...
753453e4 940 */
941
9b4efe89 942 pclass = cupsdAddPrinter(name);
943 cupsArrayAdd(ImplicitPrinters, pclass);
584ef899 944
9b4efe89 945 pclass->type |= CUPS_PRINTER_IMPLICIT;
946 pclass->accepting = 1;
947 pclass->state = IPP_PRINTER_IDLE;
584ef899 948
9b4efe89 949 cupsdSetString(&pclass->location, p->location);
950 cupsdSetString(&pclass->info, p->info);
e5dc1f76 951
9b4efe89 952 update = 1;
753453e4 953
9b4efe89 954 cupsdLogMessage(CUPSD_LOG_INFO, "Added implicit class \"%s\"...",
955 name);
956 }
753453e4 957
9b4efe89 958 if (first != NULL)
959 {
753453e4 960 for (i = 0; i < pclass->num_printers; i ++)
9b4efe89 961 if (pclass->printers[i] == first)
753453e4 962 break;
963
964 if (i >= pclass->num_printers)
584ef899 965 {
9b4efe89 966 first->in_implicit_class = 1;
967 cupsdAddPrinterToClass(pclass, first);
968 }
969
970 first = NULL;
753453e4 971 }
9b4efe89 972
973 for (i = 0; i < pclass->num_printers; i ++)
974 if (pclass->printers[i] == p)
975 break;
976
977 if (i >= pclass->num_printers)
978 {
979 p->in_implicit_class = 1;
980 cupsdAddPrinterToClass(pclass, p);
981 update = 1;
982 }
983 }
984 else
985 {
986 /*
987 * First time around; just get name length and mark it as first
988 * in the list...
989 */
990
991 if ((hptr = strchr(p->name, '@')) != NULL)
992 len = hptr - p->name;
753453e4 993 else
9b4efe89 994 len = strlen(p->name);
995
996 strncpy(name, p->name, len);
997 name[len] = '\0';
998 offset = 0;
999
1000 if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
1001 !(first->type & CUPS_PRINTER_IMPLICIT))
753453e4 1002 {
1003 /*
9b4efe89 1004 * Can't use same name as a local printer; add "Any" to the
1005 * front of the name, unless we have explicitly disabled
1006 * the "ImplicitAnyClasses"...
753453e4 1007 */
1008
9b4efe89 1009 if (ImplicitAnyClasses && len < (sizeof(name) - 4))
753453e4 1010 {
1011 /*
9b4efe89 1012 * Add "Any" to the class name...
753453e4 1013 */
1014
9b4efe89 1015 strcpy(name, "Any");
1016 strncpy(name + 3, p->name, len);
1017 name[len + 3] = '\0';
1018 offset = 3;
753453e4 1019 }
9b4efe89 1020 else
1021 {
1022 /*
1023 * Don't create an implicit class if we have a local printer
1024 * with the same name...
1025 */
753453e4 1026
9b4efe89 1027 len = 0;
1028 cupsArrayRestore(Printers);
1029 continue;
1030 }
753453e4 1031 }
e208121a 1032
9b4efe89 1033 first = p;
753453e4 1034 }
584ef899 1035
9b4efe89 1036 cupsArrayRestore(Printers);
753453e4 1037 }
9b4efe89 1038
1039 /*
1040 * Update the last printer class as needed...
1041 */
1042
1043 if (pclass && update)
1044 cupsdSetPrinterAttrs(pclass);
753453e4 1045}
1046
1047
5ca53bd2 1048/*
1049 * 'cupsdSaveRemoteCache()' - Save the remote printer cache.
1050 */
1051
1052void
1053cupsdSaveRemoteCache(void)
1054{
9b4efe89 1055 int i; /* Looping var */
1056 cups_file_t *fp; /* printers.conf file */
1057 char temp[1024]; /* Temporary string */
1058 cupsd_printer_t *printer; /* Current printer class */
1059 time_t curtime; /* Current time */
1060 struct tm *curdate; /* Current date */
1061
1062
1063 /*
1064 * Create the remote.cache file...
1065 */
1066
1067 snprintf(temp, sizeof(temp), "%s/remote.cache", CacheDir);
1068
1069 if ((fp = cupsFileOpen(temp, "w")) == NULL)
1070 {
1071 cupsdLogMessage(CUPSD_LOG_ERROR,
1072 "Unable to save remote.cache - %s", strerror(errno));
1073 return;
1074 }
1075 else
1076 cupsdLogMessage(CUPSD_LOG_INFO, "Saving remote.cache...");
1077
1078 /*
1079 * Restrict access to the file...
1080 */
1081
1082 fchown(cupsFileNumber(fp), getuid(), Group);
1083 fchmod(cupsFileNumber(fp), ConfigFilePerm);
1084
1085 /*
1086 * Write a small header to the file...
1087 */
1088
1089 curtime = time(NULL);
1090 curdate = localtime(&curtime);
1091 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
1092
1093 cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n");
1094 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
1095
1096 /*
1097 * Write each local printer known to the system...
1098 */
1099
1100 for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
1101 printer;
1102 printer = (cupsd_printer_t *)cupsArrayNext(Printers))
1103 {
1104 /*
1105 * Skip local destinations...
1106 */
1107
1108 if (!(printer->type & CUPS_PRINTER_REMOTE))
1109 continue;
1110
1111 /*
1112 * Write printers as needed...
1113 */
1114
1115 if (printer == DefaultPrinter)
1116 cupsFilePuts(fp, "<Default");
1117 else
1118 cupsFilePutChar(fp, '<');
1119
1120 if (printer->type & CUPS_PRINTER_CLASS)
1121 cupsFilePrintf(fp, "Class %s>\n", printer->name);
1122 else
1123 cupsFilePrintf(fp, "Printer %s>\n", printer->name);
1124
1125 cupsFilePrintf(fp, "Type %d\n", printer->type);
1126
1127 cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_time);
1128
1129 if (printer->info)
1130 cupsFilePrintf(fp, "Info %s\n", printer->info);
1131
b537a9b8 1132 if (printer->make_model)
1133 cupsFilePrintf(fp, "MakeModel %s\n", printer->make_model);
1134
9b4efe89 1135 if (printer->location)
1136 cupsFilePrintf(fp, "Location %s\n", printer->location);
1137
1138 if (printer->device_uri)
1139 cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
1140
1141 if (printer->state == IPP_PRINTER_STOPPED)
1142 {
1143 cupsFilePuts(fp, "State Stopped\n");
1144 cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message);
1145 }
1146 else
1147 cupsFilePuts(fp, "State Idle\n");
1148
1149 if (printer->accepting)
1150 cupsFilePuts(fp, "Accepting Yes\n");
1151 else
1152 cupsFilePuts(fp, "Accepting No\n");
1153
1154 cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
1155 printer->job_sheets[1]);
1156
1157 for (i = 0; i < printer->num_users; i ++)
1158 cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
1159 printer->users[i]);
1160
1161 if (printer->type & CUPS_PRINTER_CLASS)
1162 cupsFilePuts(fp, "</Class>\n");
1163 else
1164 cupsFilePuts(fp, "</Printer>\n");
1165 }
1166
1167 cupsFileClose(fp);
5ca53bd2 1168}
1169
1170
903511b4 1171/*
589eb420 1172 * 'cupsdSendBrowseDelete()' - Send a "browse delete" message for a printer.
903511b4 1173 */
1174
1175void
f3e786fc 1176cupsdSendBrowseDelete(
1177 cupsd_printer_t *p) /* I - Printer to delete */
903511b4 1178{
1179 /*
1180 * Only announce if browsing is enabled...
1181 */
1182
25392f52 1183 if (!Browsing || !p->shared)
903511b4 1184 return;
1185
1186 /*
1187 * First mark the printer for deletion...
1188 */
1189
1190 p->type |= CUPS_PRINTER_DELETE;
1191
1192 /*
1193 * Announce the deletion...
1194 */
1195
206d3f94 1196 if (BrowseLocalProtocols & BROWSE_CUPS)
589eb420 1197 cupsdSendCUPSBrowse(p);
903511b4 1198#ifdef HAVE_LIBSLP
206d3f94 1199 if (BrowseLocalProtocols & BROWSE_SLP)
f3e786fc 1200 slp_dereg_printer(p);
903511b4 1201#endif /* HAVE_LIBSLP */
1202}
1203
1204
753453e4 1205/*
589eb420 1206 * 'cupsdSendBrowseList()' - Send new browsing information as necessary.
753453e4 1207 */
1208
1209void
589eb420 1210cupsdSendBrowseList(void)
753453e4 1211{
ba886a95 1212 int count; /* Number of dests to update */
f3e786fc 1213 cupsd_printer_t *p; /* Current printer */
ba886a95 1214 time_t ut, /* Minimum update time */
1215 to; /* Timeout time */
753453e4 1216
1217
90231631 1218 if (!Browsing || !BrowseLocalProtocols || !Printers)
753453e4 1219 return;
1220
1221 /*
1222 * Compute the update and timeout times...
1223 */
1224
1225 ut = time(NULL) - BrowseInterval;
1226 to = time(NULL) - BrowseTimeout;
1227
c47e97cc 1228 /*
1229 * Figure out how many printers need an update...
1230 */
1231
1232 if (BrowseInterval > 0)
1233 {
ba886a95 1234 int max_count; /* Maximum number to update */
1235
1236
1237 /*
1238 * Throttle the number of printers we'll be updating this time
1239 * around based on the number of queues that need updating and
1240 * the maximum number of queues to update each second...
1241 */
1242
90231631 1243 max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1;
ba886a95 1244
589eb420 1245 for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers);
90231631 1246 count < max_count && p != NULL;
589eb420 1247 p = (cupsd_printer_t *)cupsArrayNext(Printers))
c47e97cc 1248 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
25392f52 1249 p->shared && p->browse_time < ut)
c47e97cc 1250 count ++;
1251
1252 /*
ba886a95 1253 * Loop through all of the printers and send local updates as needed...
c47e97cc 1254 */
1255
cc1b5936 1256 if (BrowseNext)
9c3413b7 1257 p = (cupsd_printer_t *)cupsArrayFind(Printers, BrowseNext);
cc1b5936 1258 else
1259 p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1260
1261 for (;
90231631 1262 count > 0;
589eb420 1263 p = (cupsd_printer_t *)cupsArrayNext(Printers))
ba886a95 1264 {
1265 /*
1266 * Check for wraparound...
1267 */
1268
1269 if (!p)
589eb420 1270 p = (cupsd_printer_t *)cupsArrayFirst(Printers);
ba886a95 1271
fd35db0b 1272 if (!p)
1273 break;
25392f52 1274 else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) ||
1275 !p->shared)
ba886a95 1276 continue;
1277 else if (p->browse_time < ut)
1278 {
1279 /*
1280 * Need to send an update...
1281 */
1282
1283 count --;
1284
1285 p->browse_time = time(NULL);
1286
206d3f94 1287 if (BrowseLocalProtocols & BROWSE_CUPS)
589eb420 1288 cupsdSendCUPSBrowse(p);
ba886a95 1289
1290#ifdef HAVE_LIBSLP
206d3f94 1291 if (BrowseLocalProtocols & BROWSE_SLP)
589eb420 1292 cupsdSendSLPBrowse(p);
ba886a95 1293#endif /* HAVE_LIBSLP */
1294 }
1295 }
1296
1297 /*
1298 * Save where we left off so that all printers get updated...
1299 */
1300
1301 BrowseNext = p;
c47e97cc 1302 }
c47e97cc 1303
753453e4 1304 /*
1305 * Loop through all of the printers and send local updates as needed...
1306 */
1307
589eb420 1308 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
90231631 1309 p;
589eb420 1310 p = (cupsd_printer_t *)cupsArrayNext(Printers))
753453e4 1311 {
ba886a95 1312 /*
1313 * If this is a remote queue, see if it needs to be timed out...
1314 */
1315
753453e4 1316 if (p->type & CUPS_PRINTER_REMOTE)
1317 {
753453e4 1318 if (p->browse_time < to)
1319 {
42f94780 1320 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
1321 "%s \'%s\' deleted by directory services (timeout).",
1322 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
1323 p->name);
1324
f3e786fc 1325 cupsdLogMessage(CUPSD_LOG_INFO,
1326 "Remote destination \"%s\" has timed out; deleting it...",
1327 p->name);
42f94780 1328
d9394520 1329 cupsArraySave(Printers);
589eb420 1330 cupsdDeletePrinter(p, 1);
d9394520 1331 cupsArrayRestore(Printers);
753453e4 1332 }
1333 }
753453e4 1334 }
1335}
1336
1337
1338/*
589eb420 1339 * 'cupsdSendCUPSBrowse()' - Send new browsing information using the CUPS protocol.
753453e4 1340 */
1341
1342void
f3e786fc 1343cupsdSendCUPSBrowse(cupsd_printer_t *p) /* I - Printer to send */
753453e4 1344{
d7a9de63 1345 int i; /* Looping var */
648051ba 1346 cups_ptype_t type; /* Printer type */
f3e786fc 1347 cupsd_dirsvc_addr_t *b; /* Browse address */
d7a9de63 1348 int bytes; /* Length of packet */
1349 char packet[1453]; /* Browse data packet */
1b7c45db 1350 char uri[1024]; /* Printer URI */
7d6f99c0 1351 char options[1024]; /* Browse local options */
589eb420 1352 cupsd_netif_t *iface; /* Network interface */
753453e4 1353
1354
648051ba 1355 /*
1356 * Figure out the printer type value...
1357 */
1358
1359 type = p->type | CUPS_PRINTER_REMOTE;
1360
1361 if (!p->accepting)
1362 type |= CUPS_PRINTER_REJECTING;
1363
7d6f99c0 1364 /*
1365 * Initialize the browse options...
1366 */
1367
1368 if (BrowseLocalOptions)
5ca53bd2 1369 snprintf(options, sizeof(options), " ipp-options=%s", BrowseLocalOptions);
7d6f99c0 1370 else
1371 options[0] = '\0';
1372
753453e4 1373 /*
1374 * Send a packet to each browse address...
1375 */
1376
d7a9de63 1377 for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
1378 if (b->iface[0])
753453e4 1379 {
d7a9de63 1380 /*
1381 * Send the browse packet to one or more interfaces...
1382 */
753453e4 1383
d7a9de63 1384 if (strcmp(b->iface, "*") == 0)
1385 {
1386 /*
1387 * Send to all local interfaces...
1388 */
1389
589eb420 1390 cupsdNetIFUpdate();
d7a9de63 1391
1392 for (iface = NetIFList; iface != NULL; iface = iface->next)
1393 {
1394 /*
aee873ba 1395 * Only send to local, IPv4 interfaces...
d7a9de63 1396 */
1397
aee873ba 1398 if (!iface->is_local || !iface->port ||
1399 iface->address.addr.sa_family != AF_INET)
d7a9de63 1400 continue;
1401
1b7c45db 1402 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, iface->hostname,
1403 iface->port,
1404 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" :
5ca53bd2 1405 "/printers/%s",
1406 p->name);
1407 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n",
1b7c45db 1408 type, p->state, uri, p->location ? p->location : "",
25926905 1409 p->info ? p->info : "",
5ca53bd2 1410 p->make_model ? p->make_model : "Unknown", options);
d7a9de63 1411
1412 bytes = strlen(packet);
1413
f3e786fc 1414 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1415 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
1416 iface->name, packet);
d7a9de63 1417
aee873ba 1418 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
d7a9de63 1419
aee873ba 1420 sendto(BrowseSocket, packet, bytes, 0,
1421 (struct sockaddr *)&(iface->broadcast),
1422 sizeof(struct sockaddr_in));
d7a9de63 1423 }
1424 }
f3e786fc 1425 else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
d7a9de63 1426 {
1427 /*
aee873ba 1428 * Send to the named interface using the IPv4 address...
d7a9de63 1429 */
1430
aee873ba 1431 while (iface)
1432 if (strcasecmp(b->iface, iface->name))
1433 {
1434 iface = NULL;
1435 break;
1436 }
1437 else if (iface->address.addr.sa_family == AF_INET && iface->port)
1438 break;
1439 else
1440 iface = iface->next;
edd6ee99 1441
aee873ba 1442 if (iface)
1443 {
1b7c45db 1444 httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, iface->hostname,
1445 iface->port,
1446 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" :
5ca53bd2 1447 "/printers/%s",
1448 p->name);
1449 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n",
1b7c45db 1450 type, p->state, uri, p->location ? p->location : "",
aee873ba 1451 p->info ? p->info : "",
5ca53bd2 1452 p->make_model ? p->make_model : "Unknown", options);
d7a9de63 1453
aee873ba 1454 bytes = strlen(packet);
d7a9de63 1455
aee873ba 1456 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1457 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
1458 iface->name, packet);
d7a9de63 1459
d7a9de63 1460 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
1461
1462 sendto(BrowseSocket, packet, bytes, 0,
1463 (struct sockaddr *)&(iface->broadcast),
1464 sizeof(struct sockaddr_in));
1465 }
d7a9de63 1466 }
1467 }
1468 else
1469 {
1470 /*
1471 * Send the browse packet to the indicated address using
1472 * the default server name...
1473 */
1474
5ca53bd2 1475 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n",
1476 type, p->state, p->uri,
25926905 1477 p->location ? p->location : "",
1478 p->info ? p->info : "",
5ca53bd2 1479 p->make_model ? p->make_model : "Unknown", options);
d7a9de63 1480
1481 bytes = strlen(packet);
f3e786fc 1482 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1483 "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
d7a9de63 1484
a09840c5 1485 if (sendto(BrowseSocket, packet, bytes, 0,
1486 (struct sockaddr *)&(b->to),
1487 sizeof(struct sockaddr_in)) <= 0)
d7a9de63 1488 {
1489 /*
1490 * Unable to send browse packet, so remove this address from the
1491 * list...
1492 */
1493
f3e786fc 1494 cupsdLogMessage(CUPSD_LOG_ERROR,
1495 "cupsdSendBrowseList: sendto failed for browser %d - %s.",
1496 b - Browsers + 1, strerror(errno));
d7a9de63 1497
1498 if (i > 1)
589eb420 1499 memcpy(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
d7a9de63 1500
1501 b --;
1502 NumBrowsers --;
1503 }
753453e4 1504 }
1505}
1506
1507
e6e44566 1508#ifdef HAVE_LIBSLP
1509/*
1510 * 'cupsdSendSLPBrowse()' - Register the specified printer with SLP.
1511 */
1512
1513void
1514cupsdSendSLPBrowse(cupsd_printer_t *p) /* I - Printer to register */
1515{
1516 char srvurl[HTTP_MAX_URI], /* Printer service URI */
1517 attrs[8192], /* Printer attributes */
1518 finishings[1024], /* Finishings to support */
1519 make_model[IPP_MAX_NAME * 2],
1520 /* Make and model, quoted */
1521 location[IPP_MAX_NAME * 2],
1522 /* Location, quoted */
1523 info[IPP_MAX_NAME * 2], /* Info, quoted */
1524 *src, /* Pointer to original string */
1525 *dst; /* Pointer to destination string */
1526 ipp_attribute_t *authentication; /* uri-authentication-supported value */
1527 SLPError error; /* SLP error, if any */
1528
1529
1530 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSendSLPBrowse(%p = \"%s\")", p,
1531 p->name);
1532
1533 /*
1534 * Make the SLP service URL that conforms to the IANA
1535 * 'printer:' template.
1536 */
1537
1538 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
1539
1540 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
1541
1542 /*
1543 * Figure out the finishings string...
1544 */
1545
1546 if (p->type & CUPS_PRINTER_STAPLE)
1547 strcpy(finishings, "staple");
1548 else
1549 finishings[0] = '\0';
1550
1551 if (p->type & CUPS_PRINTER_BIND)
1552 {
1553 if (finishings[0])
1554 strlcat(finishings, ",bind", sizeof(finishings));
1555 else
1556 strcpy(finishings, "bind");
1557 }
1558
1559 if (p->type & CUPS_PRINTER_PUNCH)
1560 {
1561 if (finishings[0])
1562 strlcat(finishings, ",punch", sizeof(finishings));
1563 else
1564 strcpy(finishings, "punch");
1565 }
1566
1567 if (p->type & CUPS_PRINTER_COVER)
1568 {
1569 if (finishings[0])
1570 strlcat(finishings, ",cover", sizeof(finishings));
1571 else
1572 strcpy(finishings, "cover");
1573 }
1574
1575 if (p->type & CUPS_PRINTER_SORT)
1576 {
1577 if (finishings[0])
1578 strlcat(finishings, ",sort", sizeof(finishings));
1579 else
1580 strcpy(finishings, "sort");
1581 }
1582
1583 if (!finishings[0])
1584 strcpy(finishings, "none");
1585
1586 /*
1587 * Quote any commas in the make and model, location, and info strings...
1588 */
1589
1590 for (src = p->make_model, dst = make_model;
1591 src && *src && dst < (make_model + sizeof(make_model) - 2);)
1592 {
1593 if (*src == ',' || *src == '\\' || *src == ')')
1594 *dst++ = '\\';
1595
1596 *dst++ = *src++;
1597 }
1598
1599 *dst = '\0';
1600
1601 if (!make_model[0])
1602 strcpy(make_model, "Unknown");
1603
1604 for (src = p->location, dst = location;
1605 src && *src && dst < (location + sizeof(location) - 2);)
1606 {
1607 if (*src == ',' || *src == '\\' || *src == ')')
1608 *dst++ = '\\';
1609
1610 *dst++ = *src++;
1611 }
1612
1613 *dst = '\0';
1614
1615 if (!location[0])
1616 strcpy(location, "Unknown");
1617
1618 for (src = p->info, dst = info;
1619 src && *src && dst < (info + sizeof(info) - 2);)
1620 {
1621 if (*src == ',' || *src == '\\' || *src == ')')
1622 *dst++ = '\\';
1623
1624 *dst++ = *src++;
1625 }
1626
1627 *dst = '\0';
1628
1629 if (!info[0])
1630 strcpy(info, "Unknown");
1631
1632 /*
1633 * Get the authentication value...
1634 */
1635
1636 authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
1637 IPP_TAG_KEYWORD);
1638
1639 /*
1640 * Make the SLP attribute string list that conforms to
1641 * the IANA 'printer:' template.
1642 */
1643
1644 snprintf(attrs, sizeof(attrs),
1645 "(printer-uri-supported=%s),"
1646 "(uri-authentication-supported=%s>),"
1647#ifdef HAVE_SSL
1648 "(uri-security-supported=tls>),"
1649#else
1650 "(uri-security-supported=none>),"
1651#endif /* HAVE_SSL */
1652 "(printer-name=%s),"
1653 "(printer-location=%s),"
1654 "(printer-info=%s),"
1655 "(printer-more-info=%s),"
1656 "(printer-make-and-model=%s),"
1657 "(charset-supported=utf-8),"
1658 "(natural-language-configured=%s),"
1659 "(natural-language-supported=de,en,es,fr,it),"
1660 "(color-supported=%s),"
1661 "(finishings-supported=%s),"
1662 "(sides-supported=one-sided%s),"
1663 "(multiple-document-jobs-supported=true)"
1664 "(ipp-versions-supported=1.0,1.1)",
1665 p->uri, authentication->values[0].string.text, p->name, location,
1666 info, p->uri, make_model, DefaultLanguage,
1667 p->type & CUPS_PRINTER_COLOR ? "true" : "false",
1668 finishings,
1669 p->type & CUPS_PRINTER_DUPLEX ?
1670 ",two-sided-long-edge,two-sided-short-edge" : "");
1671
1672 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
1673
1674 /*
1675 * Register the printer with the SLP server...
1676 */
1677
1678 error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
1679 SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
1680
1681 if (error != SLP_OK)
1682 cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
1683 error);
1684}
1685#endif /* HAVE_LIBSLP */
1686
1687
d6de4648 1688/*
589eb420 1689 * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
d6de4648 1690 */
1691
fd8b1cf8 1692void
589eb420 1693cupsdStartBrowsing(void)
fd8b1cf8 1694{
f3e786fc 1695 int val; /* Socket option value */
1696 struct sockaddr_in addr; /* Broadcast address */
d6de4648 1697
1698
9c3413b7 1699 BrowseNext = NULL;
1700
206d3f94 1701 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
d6de4648 1702 return;
1703
206d3f94 1704 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
753453e4 1705 {
1706 /*
1707 * Create the broadcast socket...
1708 */
1709
1710 if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1711 {
f3e786fc 1712 cupsdLogMessage(CUPSD_LOG_ERROR,
1713 "cupsdStartBrowsing: Unable to create broadcast socket - %s.",
1714 strerror(errno));
206d3f94 1715 BrowseLocalProtocols &= ~BROWSE_CUPS;
1716 BrowseRemoteProtocols &= ~BROWSE_CUPS;
753453e4 1717 return;
1718 }
1719
1720 /*
1721 * Set the "broadcast" flag...
1722 */
1723
1724 val = 1;
1725 if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
1726 {
f3e786fc 1727 cupsdLogMessage(CUPSD_LOG_ERROR,
1728 "cupsdStartBrowsing: Unable to set broadcast mode - %s.",
1729 strerror(errno));
753453e4 1730
c3026ddc 1731#ifdef WIN32
753453e4 1732 closesocket(BrowseSocket);
c3026ddc 1733#else
753453e4 1734 close(BrowseSocket);
c3026ddc 1735#endif /* WIN32 */
753453e4 1736
206d3f94 1737 BrowseSocket = -1;
1738 BrowseLocalProtocols &= ~BROWSE_CUPS;
1739 BrowseRemoteProtocols &= ~BROWSE_CUPS;
753453e4 1740 return;
1741 }
1742
1743 /*
1744 * Bind the socket to browse port...
1745 */
1746
1747 memset(&addr, 0, sizeof(addr));
1748 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1749 addr.sin_family = AF_INET;
1750 addr.sin_port = htons(BrowsePort);
1751
1752 if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
1753 {
f3e786fc 1754 cupsdLogMessage(CUPSD_LOG_ERROR,
1755 "cupsdStartBrowsing: Unable to bind broadcast socket - %s.",
1756 strerror(errno));
d6de4648 1757
c3026ddc 1758#ifdef WIN32
753453e4 1759 closesocket(BrowseSocket);
c3026ddc 1760#else
753453e4 1761 close(BrowseSocket);
c3026ddc 1762#endif /* WIN32 */
753453e4 1763
206d3f94 1764 BrowseSocket = -1;
1765 BrowseLocalProtocols &= ~BROWSE_CUPS;
1766 BrowseRemoteProtocols &= ~BROWSE_CUPS;
753453e4 1767 return;
1768 }
1769
db3c5bfd 1770 /*
1771 * Close the socket on exec...
1772 */
1773
1774 fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
1775
753453e4 1776 /*
1777 * Finally, add the socket to the input selection set...
1778 */
1779
f3e786fc 1780 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1781 "cupsdStartBrowsing: Adding fd %d to InputSet...",
1782 BrowseSocket);
753453e4 1783
f3bc1068 1784 FD_SET(BrowseSocket, InputSet);
753453e4 1785 }
b59d5057 1786 else
1787 BrowseSocket = -1;
753453e4 1788
1789#ifdef HAVE_LIBSLP
206d3f94 1790 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
d6de4648 1791 {
753453e4 1792 /*
1793 * Open SLP handle...
1794 */
1795
1796 if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
1797 {
f3e786fc 1798 cupsdLogMessage(CUPSD_LOG_ERROR,
1799 "Unable to open an SLP handle; disabling SLP browsing!");
206d3f94 1800 BrowseLocalProtocols &= ~BROWSE_SLP;
1801 BrowseRemoteProtocols &= ~BROWSE_SLP;
753453e4 1802 }
1803
1804 BrowseSLPRefresh = 0;
d6de4648 1805 }
7db52463 1806#endif /* HAVE_LIBSLP */
753453e4 1807}
d6de4648 1808
d6de4648 1809
753453e4 1810/*
589eb420 1811 * 'cupsdStartPolling()' - Start polling servers as needed.
753453e4 1812 */
1813
1814void
589eb420 1815cupsdStartPolling(void)
753453e4 1816{
f3e786fc 1817 int i; /* Looping var */
1a59b1c1 1818 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
f3e786fc 1819 char polld[1024]; /* Poll daemon path */
1820 char sport[10]; /* Server port */
1821 char bport[10]; /* Browser port */
1822 char interval[10]; /* Poll interval */
1823 int statusfds[2]; /* Status pipe */
1824 char *argv[6]; /* Arguments */
1825 char *envp[100]; /* Environment */
753453e4 1826
1827
9495ba14 1828 /*
1829 * Don't do anything if we aren't polling...
1830 */
1831
1832 if (NumPolled == 0)
3ff338a6 1833 {
ddd3933d 1834 PollPipe = -1;
1835 PollStatusBuffer = NULL;
9495ba14 1836 return;
3ff338a6 1837 }
9495ba14 1838
5f46b7d1 1839 /*
c316e838 1840 * Setup string arguments for polld, port and interval options.
5f46b7d1 1841 */
1842
c316e838 1843 snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
1844
753453e4 1845 sprintf(bport, "%d", BrowsePort);
1846
1847 if (BrowseInterval)
1848 sprintf(interval, "%d", BrowseInterval);
1849 else
1850 strcpy(interval, "30");
1851
c316e838 1852 argv[0] = "cups-polld";
1853 argv[2] = sport;
1854 argv[3] = interval;
1855 argv[4] = bport;
1856 argv[5] = NULL;
1857
291355eb 1858 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
1859
5f46b7d1 1860 /*
1861 * Create a pipe that receives the status messages from each
1862 * polling daemon...
1863 */
1864
8650fcf2 1865 if (cupsdOpenPipe(statusfds))
5f46b7d1 1866 {
f3e786fc 1867 cupsdLogMessage(CUPSD_LOG_ERROR,
1868 "Unable to create polling status pipes - %s.",
1869 strerror(errno));
ddd3933d 1870 PollPipe = -1;
1871 PollStatusBuffer = NULL;
5f46b7d1 1872 return;
1873 }
1874
ddd3933d 1875 PollPipe = statusfds[0];
1876 PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
5f46b7d1 1877
1878 /*
1879 * Run each polling daemon, redirecting stderr to the polling pipe...
1880 */
1881
1a59b1c1 1882 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
fd3ece61 1883 {
1a59b1c1 1884 sprintf(sport, "%d", pollp->port);
fd3ece61 1885
1a59b1c1 1886 argv[1] = pollp->hostname;
b9e3e9a0 1887
291355eb 1888 if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1,
1a59b1c1 1889 0, &(pollp->pid)) < 0)
753453e4 1890 {
f3e786fc 1891 cupsdLogMessage(CUPSD_LOG_ERROR,
1892 "cupsdStartPolling: Unable to fork polling daemon - %s",
1893 strerror(errno));
1a59b1c1 1894 pollp->pid = 0;
753453e4 1895 break;
1896 }
1897 else
f3e786fc 1898 cupsdLogMessage(CUPSD_LOG_DEBUG,
1899 "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
1a59b1c1 1900 pollp->hostname, pollp->port, pollp->pid);
fd3ece61 1901 }
5f46b7d1 1902
1903 close(statusfds[1]);
1904
1905 /*
1906 * Finally, add the pipe to the input selection set...
1907 */
1908
f3e786fc 1909 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1910 "cupsdStartPolling: Adding fd %d to InputSet...", PollPipe);
5f46b7d1 1911
f3bc1068 1912 FD_SET(PollPipe, InputSet);
753453e4 1913}
d6de4648 1914
d6de4648 1915
753453e4 1916/*
589eb420 1917 * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
753453e4 1918 */
1919
1920void
589eb420 1921cupsdStopBrowsing(void)
753453e4 1922{
206d3f94 1923 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
753453e4 1924 return;
d6de4648 1925
206d3f94 1926 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
d6de4648 1927 {
753453e4 1928 /*
1929 * Close the socket and remove it from the input selection set.
1930 */
d6de4648 1931
753453e4 1932 if (BrowseSocket >= 0)
1933 {
c3026ddc 1934#ifdef WIN32
753453e4 1935 closesocket(BrowseSocket);
d6de4648 1936#else
753453e4 1937 close(BrowseSocket);
c3026ddc 1938#endif /* WIN32 */
d6de4648 1939
f3e786fc 1940 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1941 "cupsdStopBrowsing: Removing fd %d from InputSet...",
1942 BrowseSocket);
753453e4 1943
f3bc1068 1944 FD_CLR(BrowseSocket, InputSet);
b59d5057 1945 BrowseSocket = -1;
753453e4 1946 }
d6de4648 1947 }
1948
753453e4 1949#ifdef HAVE_LIBSLP
206d3f94 1950 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
753453e4 1951 {
1952 /*
1953 * Close SLP handle...
1954 */
d6de4648 1955
753453e4 1956 SLPClose(BrowseSLPHandle);
1957 }
1958#endif /* HAVE_LIBSLP */
fd8b1cf8 1959}
1960
1961
d6de4648 1962/*
589eb420 1963 * 'cupsdStopPolling()' - Stop polling servers as needed.
d6de4648 1964 */
1965
fd8b1cf8 1966void
589eb420 1967cupsdStopPolling(void)
fd8b1cf8 1968{
f3e786fc 1969 int i; /* Looping var */
1a59b1c1 1970 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
d6de4648 1971
d6de4648 1972
ba31b514 1973 if (PollPipe >= 0)
5f46b7d1 1974 {
ddd3933d 1975 cupsdStatBufDelete(PollStatusBuffer);
5f46b7d1 1976 close(PollPipe);
1977
f3e786fc 1978 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1979 "cupsdStopPolling: removing fd %d from InputSet.", PollPipe);
f3bc1068 1980 FD_CLR(PollPipe, InputSet);
5f46b7d1 1981
ddd3933d 1982 PollPipe = -1;
1983 PollStatusBuffer = NULL;
5f46b7d1 1984 }
1985
1a59b1c1 1986 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1987 if (pollp->pid)
1988 cupsdEndProcess(pollp->pid, 0);
fd8b1cf8 1989}
1990
1991
d6de4648 1992/*
589eb420 1993 * 'cupsdUpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol.
d6de4648 1994 */
1995
fd8b1cf8 1996void
589eb420 1997cupsdUpdateCUPSBrowse(void)
fd8b1cf8 1998{
8b43895a 1999 int i; /* Looping var */
e5ebb675 2000 int auth; /* Authorization status */
753453e4 2001 int len; /* Length of name string */
d6de4648 2002 int bytes; /* Number of bytes left */
1e0c2f84 2003 char packet[1541], /* Broadcast packet */
20e0a4cb 2004 *pptr; /* Pointer into packet */
bdb1331d 2005 socklen_t srclen; /* Length of source address */
99de6da0 2006 http_addr_t srcaddr; /* Source address */
e5ebb675 2007 char srcname[1024]; /* Source hostname */
f3e786fc 2008 unsigned address[4]; /* Source address */
7abb7137 2009 unsigned type; /* Printer type */
2010 unsigned state; /* Printer state */
d6de4648 2011 char uri[HTTP_MAX_URI], /* Printer URI */
2012 method[HTTP_MAX_URI], /* Method portion of URI */
2013 username[HTTP_MAX_URI], /* Username portion of URI */
2014 host[HTTP_MAX_URI], /* Host portion of URI */
a2c6b8b1 2015 resource[HTTP_MAX_URI], /* Resource portion of URI */
2016 info[IPP_MAX_NAME], /* Information string */
2017 location[IPP_MAX_NAME], /* Location string */
2018 make_model[IPP_MAX_NAME];/* Make and model string */
d6de4648 2019 int port; /* Port portion of URI */
589eb420 2020 cupsd_netif_t *iface; /* Network interface */
5ca53bd2 2021 int num_attrs; /* Number of attributes */
2022 cups_option_t *attrs; /* Attributes */
d6de4648 2023
2024
2025 /*
2026 * Read a packet from the browse socket...
2027 */
2028
bdb1331d 2029 srclen = sizeof(srcaddr);
1e0c2f84 2030 if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
bdb1331d 2031 (struct sockaddr *)&srcaddr, &srclen)) < 0)
18d7d592 2032 {
89db771d 2033 /*
2034 * "Connection refused" is returned under Linux if the destination port
2035 * or address is unreachable from a previous sendto(); check for the
2036 * error here and ignore it for now...
2037 */
2038
de5ee36e 2039 if (errno != ECONNREFUSED && errno != EAGAIN)
89db771d 2040 {
f3e786fc 2041 cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
2042 strerror(errno));
2043 cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
89db771d 2044
589eb420 2045 cupsdStopBrowsing();
89db771d 2046 Browsing = 0;
2047 }
1a5606a3 2048
18d7d592 2049 return;
2050 }
2051
2052 packet[bytes] = '\0';
e5ebb675 2053
2054 /*
2055 * Figure out where it came from...
2056 */
2057
99de6da0 2058#ifdef AF_INET6
2059 if (srcaddr.addr.sa_family == AF_INET6)
2060 {
2061 address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
2062 address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
2063 address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
2064 address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
2065 }
e5ebb675 2066 else
99de6da0 2067#endif /* AF_INET6 */
f9bacabb 2068 {
f3e786fc 2069 address[0] = 0;
2070 address[1] = 0;
2071 address[2] = 0;
2072 address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
e5ebb675 2073 }
1a5606a3 2074
99de6da0 2075 if (HostNameLookups)
2076 httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
2077 else
2078 httpAddrString(&srcaddr, srcname, sizeof(srcname));
2079
e5ebb675 2080 len = strlen(srcname);
2081
2082 /*
2083 * Do ACL stuff...
2084 */
2085
aa9b37d6 2086 if (BrowseACL)
e5ebb675 2087 {
aa9b37d6 2088 if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
e5ebb675 2089 {
2090 /*
2091 * Access from localhost (127.0.0.1) is always allowed...
2092 */
2093
2094 auth = AUTH_ALLOW;
2095 }
2096 else
2097 {
2098 /*
2099 * Do authorization checks on the domain/address...
2100 */
2101
d21a7597 2102 switch (BrowseACL->order_type)
e5ebb675 2103 {
d21a7597 2104 default :
2105 auth = AUTH_DENY; /* anti-compiler-warning-code */
2106 break;
2107
e5ebb675 2108 case AUTH_ALLOW : /* Order Deny,Allow */
d21a7597 2109 auth = AUTH_ALLOW;
2110
589eb420 2111 if (cupsdCheckAuth(address, srcname, len,
e5ebb675 2112 BrowseACL->num_deny, BrowseACL->deny))
2113 auth = AUTH_DENY;
2114
589eb420 2115 if (cupsdCheckAuth(address, srcname, len,
e5ebb675 2116 BrowseACL->num_allow, BrowseACL->allow))
2117 auth = AUTH_ALLOW;
2118 break;
2119
2120 case AUTH_DENY : /* Order Allow,Deny */
d21a7597 2121 auth = AUTH_DENY;
2122
589eb420 2123 if (cupsdCheckAuth(address, srcname, len,
e5ebb675 2124 BrowseACL->num_allow, BrowseACL->allow))
2125 auth = AUTH_ALLOW;
2126
589eb420 2127 if (cupsdCheckAuth(address, srcname, len,
e5ebb675 2128 BrowseACL->num_deny, BrowseACL->deny))
2129 auth = AUTH_DENY;
2130 break;
2131 }
2132 }
2133 }
2134 else
2135 auth = AUTH_ALLOW;
2136
2137 if (auth == AUTH_DENY)
2138 {
f3e786fc 2139 cupsdLogMessage(CUPSD_LOG_DEBUG,
2140 "cupsdUpdateCUPSBrowse: Refused %d bytes from %s", bytes,
2141 srcname);
d6de4648 2142 return;
f9bacabb 2143 }
d6de4648 2144
f3e786fc 2145 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2146 "cupsdUpdateCUPSBrowse: (%d bytes from %s) %s", bytes,
2147 srcname, packet);
e5ebb675 2148
2149 /*
2150 * Parse packet...
2151 */
d6de4648 2152
7abb7137 2153 if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
d6de4648 2154 {
f3e786fc 2155 cupsdLogMessage(CUPSD_LOG_WARN,
2156 "cupsdUpdateCUPSBrowse: Garbled browse packet - %s", packet);
d6de4648 2157 return;
2158 }
2159
20e0a4cb 2160 strcpy(location, "Location Unknown");
2161 strcpy(info, "No Information Available");
2162 make_model[0] = '\0';
5ca53bd2 2163 num_attrs = 0;
2164 attrs = NULL;
20e0a4cb 2165
2166 if ((pptr = strchr(packet, '\"')) != NULL)
2167 {
2168 /*
2169 * Have extended information; can't use sscanf for it because not all
2170 * sscanf's allow empty strings with %[^\"]...
2171 */
2172
2173 for (i = 0, pptr ++;
2174 i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
2175 i ++, pptr ++)
2176 location[i] = *pptr;
2177
2178 if (i)
2179 location[i] = '\0';
2180
2181 if (*pptr == '\"')
2182 pptr ++;
2183
da275f55 2184 while (*pptr && isspace(*pptr & 255))
20e0a4cb 2185 pptr ++;
2186
05156f4e 2187 if (*pptr == '\"')
2188 {
2189 for (i = 0, pptr ++;
2190 i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
2191 i ++, pptr ++)
2192 info[i] = *pptr;
20e0a4cb 2193
5ca53bd2 2194 info[i] = '\0';
20e0a4cb 2195
05156f4e 2196 if (*pptr == '\"')
2197 pptr ++;
20e0a4cb 2198
da275f55 2199 while (*pptr && isspace(*pptr & 255))
05156f4e 2200 pptr ++;
20e0a4cb 2201
05156f4e 2202 if (*pptr == '\"')
2203 {
2204 for (i = 0, pptr ++;
2205 i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
2206 i ++, pptr ++)
2207 make_model[i] = *pptr;
20e0a4cb 2208
5ca53bd2 2209 if (*pptr == '\"')
2210 pptr ++;
2211
2212 make_model[i] = '\0';
2213
2214 if (*pptr)
2215 num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
05156f4e 2216 }
2217 }
20e0a4cb 2218 }
2219
2220 DEBUG_puts(packet);
a2c6b8b1 2221 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
2222 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
2223 type, state, uri, location, info, make_model));
a8b216d5 2224
d6de4648 2225 /*
2226 * Pull the URI apart to see if this is a local or remote printer...
2227 */
2228
2229 httpSeparate(uri, method, username, host, &port, resource);
2230
a8b216d5 2231 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
2232
d7a9de63 2233 /*
2234 * Check for packets from the local server...
2235 */
2236
aa9b37d6 2237 if (!strcasecmp(host, ServerName) && port == LocalPort)
5ca53bd2 2238 {
2239 cupsFreeOptions(num_attrs, attrs);
d6de4648 2240 return;
5ca53bd2 2241 }
d6de4648 2242
589eb420 2243 cupsdNetIFUpdate();
d7a9de63 2244
2245 for (iface = NetIFList; iface != NULL; iface = iface->next)
5ca53bd2 2246 if (!strcasecmp(host, iface->hostname) && port == iface->port)
2247 {
2248 cupsFreeOptions(num_attrs, attrs);
d7a9de63 2249 return;
5ca53bd2 2250 }
d7a9de63 2251
e5ebb675 2252 /*
2253 * Do relaying...
2254 */
2255
2256 for (i = 0; i < NumRelays; i ++)
589eb420 2257 if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
e5ebb675 2258 if (sendto(BrowseSocket, packet, bytes, 0,
2259 (struct sockaddr *)&(Relays[i].to),
99de6da0 2260 sizeof(http_addr_t)) <= 0)
e5ebb675 2261 {
f3e786fc 2262 cupsdLogMessage(CUPSD_LOG_ERROR,
2263 "cupsdUpdateCUPSBrowse: sendto failed for relay %d - %s.",
2264 i + 1, strerror(errno));
5ca53bd2 2265 cupsFreeOptions(num_attrs, attrs);
e5ebb675 2266 return;
2267 }
2268
d6de4648 2269 /*
753453e4 2270 * Process the browse data...
d6de4648 2271 */
2272
589eb420 2273 cupsdProcessBrowseData(uri, (cups_ptype_t)type, (ipp_pstate_t)state, location,
5ca53bd2 2274 info, make_model, num_attrs, attrs);
2275 cupsFreeOptions(num_attrs, attrs);
753453e4 2276}
d6f1ff9a 2277
d6f1ff9a 2278
5f46b7d1 2279/*
589eb420 2280 * 'cupsdUpdatePolling()' - Read status messages from the poll daemons.
5f46b7d1 2281 */
2282
2283void
589eb420 2284cupsdUpdatePolling(void)
5f46b7d1 2285{
ddd3933d 2286 char *ptr, /* Pointer to end of line in buffer */
2287 message[1024]; /* Pointer to message text */
2288 int loglevel; /* Log level for message */
5f46b7d1 2289
2290
ddd3933d 2291 while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
2292 message, sizeof(message))) != NULL)
2293 if (!strchr(PollStatusBuffer->buffer, '\n'))
2294 break;
5f46b7d1 2295
ddd3933d 2296 if (ptr == NULL)
5f46b7d1 2297 {
9495ba14 2298 /*
2299 * All polling processes have died; stop polling...
2300 */
5f46b7d1 2301
f3e786fc 2302 cupsdLogMessage(CUPSD_LOG_ERROR,
2303 "cupsdUpdatePolling: all polling processes have exited!");
589eb420 2304 cupsdStopPolling();
5f46b7d1 2305 }
2306}
2307
2308
753453e4 2309#ifdef HAVE_LIBSLP
2310/*
e6e44566 2311 * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
753453e4 2312 */
c7fa9d06 2313
e6e44566 2314void
2315cupsdUpdateSLPBrowse(void)
2316{
2317 slpsrvurl_t *s, /* Temporary list of service URLs */
2318 *next; /* Next service in list */
2319 cupsd_printer_t p; /* Printer information */
2320 const char *uri; /* Pointer to printer URI */
2321 char method[HTTP_MAX_URI],
2322 /* Method portion of URI */
2323 username[HTTP_MAX_URI],
2324 /* Username portion of URI */
2325 host[HTTP_MAX_URI],
2326 /* Host portion of URI */
2327 resource[HTTP_MAX_URI];
2328 /* Resource portion of URI */
2329 int port; /* Port portion of URI */
b2e10895 2330
b2e10895 2331
e6e44566 2332 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdUpdateSLPBrowse() Start...");
a2c6b8b1 2333
e6e44566 2334 /*
2335 * Reset the refresh time...
2336 */
d6de4648 2337
e6e44566 2338 BrowseSLPRefresh = time(NULL) + BrowseInterval;
c7fa9d06 2339
e6e44566 2340 /*
2341 * Poll for remote printers using SLP...
2342 */
d6f1ff9a 2343
e6e44566 2344 s = NULL;
d6f1ff9a 2345
e6e44566 2346 SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
2347 slp_url_callback, &s);
d6f1ff9a 2348
e6e44566 2349 /*
2350 * Loop through the list of available printers...
2351 */
c7fa9d06 2352
e6e44566 2353 for (; s; s = next)
20e0a4cb 2354 {
e6e44566 2355 /*
2356 * Save the "next" pointer...
2357 */
20e0a4cb 2358
e6e44566 2359 next = s->next;
20e0a4cb 2360
e6e44566 2361 /*
2362 * Load a cupsd_printer_t structure with the SLP service attributes...
2363 */
20e0a4cb 2364
e6e44566 2365 SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
753453e4 2366
e6e44566 2367 /*
2368 * Process this printer entry...
2369 */
753453e4 2370
e6e44566 2371 uri = s->url + SLP_CUPS_SRVLEN + 1;
753453e4 2372
1b7c45db 2373 if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
e6e44566 2374 {
2375 /*
2376 * Pull the URI apart to see if this is a local or remote printer...
2377 */
753453e4 2378
e6e44566 2379 httpSeparate(uri, method, username, host, &port, resource);
753453e4 2380
e6e44566 2381 if (strcasecmp(host, ServerName) == 0)
2382 continue;
753453e4 2383
e6e44566 2384 /*
2385 * OK, at least an IPP printer, see if it is a CUPS printer or
2386 * class...
2387 */
753453e4 2388
e6e44566 2389 if (strstr(uri, "/printers/") != NULL)
2390 cupsdProcessBrowseData(uri, p.type, IPP_PRINTER_IDLE, p.location,
d5f6de33 2391 p.info, p.make_model, 0, NULL);
e6e44566 2392 else if (strstr(uri, "/classes/") != NULL)
2393 cupsdProcessBrowseData(uri, p.type | CUPS_PRINTER_CLASS, IPP_PRINTER_IDLE,
d5f6de33 2394 p.location, p.info, p.make_model, 0, NULL);
e6e44566 2395 }
753453e4 2396
e6e44566 2397 /*
2398 * Free this listing...
2399 */
20e0a4cb 2400
e6e44566 2401 free(s);
2402 }
753453e4 2403
e6e44566 2404 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdUpdateSLPBrowse() End...");
2405}
753453e4 2406
753453e4 2407
e6e44566 2408/*
2409 * 'slp_attr_callback()' - SLP attribute callback
2410 */
20e0a4cb 2411
e6e44566 2412static SLPBoolean /* O - SLP_TRUE for success */
2413slp_attr_callback(
2414 SLPHandle hslp, /* I - SLP handle */
2415 const char *attrlist, /* I - Attribute list */
2416 SLPError errcode, /* I - Parsing status for this attr */
2417 void *cookie) /* I - Current printer */
2418{
2419 char *tmp = 0;
2420 cupsd_printer_t *p = (cupsd_printer_t*)cookie;
753453e4 2421
753453e4 2422
2423 /*
e6e44566 2424 * Let the compiler know we won't be using these...
753453e4 2425 */
2426
e6e44566 2427 (void)hslp;
a2c6b8b1 2428
fb00e262 2429 /*
e6e44566 2430 * Bail if there was an error
fb00e262 2431 */
2432
e6e44566 2433 if (errcode != SLP_OK)
2434 return (SLP_TRUE);
fb00e262 2435
8b43895a 2436 /*
e6e44566 2437 * Parse the attrlist to obtain things needed to build CUPS browse packet
8b43895a 2438 */
2439
e6e44566 2440 memset(p, 0, sizeof(cupsd_printer_t));
753453e4 2441
e6e44566 2442 p->type = CUPS_PRINTER_REMOTE;
2443
2444 if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
2445 return (SLP_FALSE);
2446 if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
2447 return (SLP_FALSE);
2448 if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
2449 return (SLP_FALSE);
2450
2451 if (slp_get_attr(attrlist, "(color-supported=", &tmp))
2452 return (SLP_FALSE);
2453 if (strcasecmp(tmp, "true") == 0)
2454 p->type |= CUPS_PRINTER_COLOR;
2455
2456 if (slp_get_attr(attrlist, "(finishings-supported=", &tmp))
2457 return (SLP_FALSE);
2458 if (strstr(tmp, "staple"))
2459 p->type |= CUPS_PRINTER_STAPLE;
2460 if (strstr(tmp, "bind"))
2461 p->type |= CUPS_PRINTER_BIND;
2462 if (strstr(tmp, "punch"))
2463 p->type |= CUPS_PRINTER_PUNCH;
2464
2465 if (slp_get_attr(attrlist, "(sides-supported=", &tmp))
2466 return (SLP_FALSE);
2467 if (strstr(tmp,"two-sided"))
2468 p->type |= CUPS_PRINTER_DUPLEX;
2469
2470 cupsdClearString(&tmp);
2471
2472 return (SLP_TRUE);
753453e4 2473}
2474
2475
2476/*
f3e786fc 2477 * 'slp_dereg_printer()' - SLPDereg() the specified printer
753453e4 2478 */
2479
f3e786fc 2480static void
e6e44566 2481slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
753453e4 2482{
e6e44566 2483 char srvurl[HTTP_MAX_URI]; /* Printer service URI */
753453e4 2484
2485
f3e786fc 2486 cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
903511b4 2487
f3e786fc 2488 if (!(p->type & CUPS_PRINTER_REMOTE))
8b43895a 2489 {
2490 /*
753453e4 2491 * Make the SLP service URL that conforms to the IANA
2492 * 'printer:' template.
8b43895a 2493 */
2494
753453e4 2495 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
b5cb0608 2496
753453e4 2497 /*
2498 * Deregister the printer...
2499 */
b5cb0608 2500
f3e786fc 2501 SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
753453e4 2502 }
2503}
8b43895a 2504
8b43895a 2505
753453e4 2506/*
f3e786fc 2507 * 'slp_get_attr()' - Get an attribute from an SLP registration.
753453e4 2508 */
8b43895a 2509
f3e786fc 2510static int /* O - 0 on success */
2511slp_get_attr(const char *attrlist, /* I - Attribute list string */
2512 const char *tag, /* I - Name of attribute */
2513 char **valbuf) /* O - Value */
753453e4 2514{
2515 char *ptr1, /* Pointer into string */
2516 *ptr2; /* ... */
2517
2518
589eb420 2519 cupsdClearString(valbuf);
753453e4 2520
2521 if ((ptr1 = strstr(attrlist, tag)) != NULL)
2522 {
2523 ptr1 += strlen(tag);
2524
2525 if ((ptr2 = strchr(ptr1,')')) != NULL)
2526 {
a782f61f 2527 /*
2528 * Copy the value...
2529 */
8b43895a 2530
25e057a4 2531 *valbuf = calloc(ptr2 - ptr1 + 1, 1);
2532 strncpy(*valbuf, ptr1, ptr2 - ptr1);
a782f61f 2533
2534 /*
2535 * Dequote the value...
2536 */
4139b718 2537
f2bdef84 2538 for (ptr1 = *valbuf; *ptr1; ptr1 ++)
a782f61f 2539 if (*ptr1 == '\\' && ptr1[1])
e22bb235 2540 _cups_strcpy(ptr1, ptr1 + 1);
20da3efb 2541
a782f61f 2542 return (0);
753453e4 2543 }
2544 }
8b43895a 2545
753453e4 2546 return (-1);
2547}
8b43895a 2548
8b43895a 2549
753453e4 2550/*
e6e44566 2551 * 'slp_reg_callback()' - Empty SLPRegReport.
753453e4 2552 */
8b43895a 2553
e6e44566 2554static void
2555slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
2556 SLPError errcode, /* I - Error code, if any */
2557 void *cookie) /* I - App data */
753453e4 2558{
753453e4 2559 (void)hslp;
e6e44566 2560 (void)errcode;
2561 (void)cookie;
782359ca 2562
e6e44566 2563 return;
fd8b1cf8 2564}
2565
2566
d6de4648 2567/*
f3e786fc 2568 * 'slp_url_callback()' - SLP service url callback
d6de4648 2569 */
2570
f3e786fc 2571static SLPBoolean /* O - TRUE = OK, FALSE = error */
2572slp_url_callback(
2573 SLPHandle hslp, /* I - SLP handle */
2574 const char *srvurl, /* I - URL of service */
2575 unsigned short lifetime, /* I - Life of service */
2576 SLPError errcode, /* I - Existing error code */
2577 void *cookie) /* I - Pointer to service list */
fd8b1cf8 2578{
753453e4 2579 slpsrvurl_t *s, /* New service entry */
2580 **head; /* Pointer to head of entry */
d6de4648 2581
2582
753453e4 2583 /*
2584 * Let the compiler know we won't be using these vars...
2585 */
2586
2587 (void)hslp;
2588 (void)lifetime;
f63a2256 2589
d6de4648 2590 /*
753453e4 2591 * Bail if there was an error
d6de4648 2592 */
2593
753453e4 2594 if (errcode != SLP_OK)
2595 return (SLP_TRUE);
d6de4648 2596
2597 /*
753453e4 2598 * Grab the head of the list...
d6de4648 2599 */
2600
753453e4 2601 head = (slpsrvurl_t**)cookie;
d6de4648 2602
753453e4 2603 /*
2604 * Allocate a *temporary* slpsrvurl_t to hold this entry.
2605 */
d6de4648 2606
753453e4 2607 if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
2608 return (SLP_FALSE);
d6de4648 2609
753453e4 2610 /*
2611 * Copy the SLP service URL...
2612 */
d6de4648 2613
def978d5 2614 strlcpy(s->url, srvurl, sizeof(s->url));
a2c6b8b1 2615
753453e4 2616 /*
2617 * Link the SLP service URL into the head of the list
2618 */
d6de4648 2619
753453e4 2620 if (*head)
2621 s->next = *head;
d6de4648 2622
753453e4 2623 *head = s;
f63a2256 2624
753453e4 2625 return (SLP_TRUE);
fd8b1cf8 2626}
753453e4 2627#endif /* HAVE_LIBSLP */
03081fd2 2628
2629
2630/*
b2e10895 2631 * End of "$Id$".
a129ddbd 2632 */