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