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