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