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