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