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