]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/dirsvc.c
Added lpinfo and lpmove commands.
[thirdparty/cups.git] / scheduler / dirsvc.c
CommitLineData
a129ddbd 1/*
5374d18c 2 * "$Id: dirsvc.c,v 1.53 2000/04/19 15:18:55 mike Exp $"
a129ddbd 3 *
d6de4648 4 * Directory services routines for the Common UNIX Printing System (CUPS).
a129ddbd 5 *
71fe22b7 6 * Copyright 1997-2000 by Easy Software Products, all rights reserved.
a129ddbd 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
8784b6a6 17 * 44141 Airport View Drive, Suite 204
a129ddbd 18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
cbbfcc63 26 * StartBrowsing() - Start sending and receiving broadcast information.
27 * StopBrowsing() - Stop sending and receiving broadcast information.
28 * UpdateBrowseList() - Update the browse lists for any new browse data.
29 * SendBrowseList() - Send new browsing information.
03081fd2 30 * StartPolling() - Start polling servers as needed.
31 * StopPolling() - Stop polling servers as needed.
a129ddbd 32 */
33
34/*
35 * Include necessary headers...
36 */
37
fd8b1cf8 38#include "cupsd.h"
39
40
d6de4648 41/*
42 * 'StartBrowsing()' - Start sending and receiving broadcast information.
43 */
44
fd8b1cf8 45void
46StartBrowsing(void)
47{
d6de4648 48 int val; /* Socket option value */
49 struct sockaddr_in addr; /* Broadcast address */
50
51
8828fd5f 52 if (!Browsing)
d6de4648 53 return;
54
55 /*
56 * Create the broadcast socket...
57 */
58
900b10ea 59 if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
d6de4648 60 {
5ea8888e 61 LogMessage(L_ERROR, "StartBrowsing: Unable to create broadcast socket - %s.",
d6de4648 62 strerror(errno));
63 return;
64 }
65
66 /*
900b10ea 67 * Set the "broadcast" flag...
d6de4648 68 */
69
70 val = 1;
e9e40963 71 if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
fd3ece61 72 {
5ea8888e 73 LogMessage(L_ERROR, "StartBrowsing: Unable to set broadcast mode - %s.",
fd3ece61 74 strerror(errno));
75
76#if defined(WIN32) || defined(__EMX__)
77 closesocket(BrowseSocket);
78#else
79 close(BrowseSocket);
80#endif /* WIN32 || __EMX__ */
81
82 BrowseSocket = -1;
83 return;
84 }
d6de4648 85
d6de4648 86 /*
87 * Bind the socket to browse port...
88 */
89
d6de4648 90 memset(&addr, 0, sizeof(addr));
91 addr.sin_addr.s_addr = htonl(INADDR_ANY);
92 addr.sin_family = AF_INET;
93 addr.sin_port = htons(BrowsePort);
94
16b0a852 95 if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
d6de4648 96 {
5ea8888e 97 LogMessage(L_ERROR, "StartBrowsing: Unable to bind broadcast socket - %s.",
d6de4648 98 strerror(errno));
99
100#if defined(WIN32) || defined(__EMX__)
101 closesocket(BrowseSocket);
102#else
103 close(BrowseSocket);
104#endif /* WIN32 || __EMX__ */
105
106 BrowseSocket = -1;
107 return;
108 }
109
110 /*
111 * Finally, add the socket to the input selection set...
112 */
113
114 FD_SET(BrowseSocket, &InputSet);
fd8b1cf8 115}
116
117
d6de4648 118/*
119 * 'StopBrowsing()' - Stop sending and receiving broadcast information.
120 */
121
fd8b1cf8 122void
123StopBrowsing(void)
124{
8828fd5f 125 if (!Browsing)
d6de4648 126 return;
127
128 /*
129 * Close the socket and remove it from the input selection set.
130 */
131
3c7bb4a2 132 if (BrowseSocket >= 0)
133 {
d6de4648 134#if defined(WIN32) || defined(__EMX__)
3c7bb4a2 135 closesocket(BrowseSocket);
d6de4648 136#else
3c7bb4a2 137 close(BrowseSocket);
d6de4648 138#endif /* WIN32 || __EMX__ */
139
3c7bb4a2 140 FD_CLR(BrowseSocket, &InputSet);
f63a2256 141 BrowseSocket = 0;
3c7bb4a2 142 }
fd8b1cf8 143}
144
145
d6de4648 146/*
147 * 'UpdateBrowseList()' - Update the browse lists for any new browse data.
148 */
149
fd8b1cf8 150void
151UpdateBrowseList(void)
152{
8b43895a 153 int i; /* Looping var */
e5ebb675 154 int auth; /* Authorization status */
eef5ad1b 155 int len, /* Length of name string */
156 offset; /* Offset in name string */
d6de4648 157 int bytes; /* Number of bytes left */
158 char packet[1540]; /* Broadcast packet */
e5ebb675 159 struct sockaddr_in srcaddr; /* Source address */
160 char srcname[1024]; /* Source hostname */
161 unsigned address; /* Source address (host order) */
162 struct hostent *srchost; /* Host entry for source address */
d6de4648 163 cups_ptype_t type; /* Printer type */
164 ipp_pstate_t state; /* Printer state */
165 char uri[HTTP_MAX_URI], /* Printer URI */
166 method[HTTP_MAX_URI], /* Method portion of URI */
167 username[HTTP_MAX_URI], /* Username portion of URI */
168 host[HTTP_MAX_URI], /* Host portion of URI */
a2c6b8b1 169 resource[HTTP_MAX_URI], /* Resource portion of URI */
170 info[IPP_MAX_NAME], /* Information string */
171 location[IPP_MAX_NAME], /* Location string */
172 make_model[IPP_MAX_NAME];/* Make and model string */
d6de4648 173 int port; /* Port portion of URI */
174 char name[IPP_MAX_NAME], /* Name of printer */
8b43895a 175 *hptr, /* Pointer into hostname */
176 *sptr; /* Pointer into ServerName */
177 printer_t *p, /* Printer information */
178 *pclass, /* Printer class */
179 *first; /* First printer in class */
d6de4648 180
181
182 /*
183 * Read a packet from the browse socket...
184 */
185
e5ebb675 186 len = sizeof(srcaddr);
16b0a852 187 if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet), 0,
e5ebb675 188 (struct sockaddr *)&srcaddr, &len)) <= 0)
18d7d592 189 {
5ea8888e 190 LogMessage(L_ERROR, "Browse recv failed - %s.",
18d7d592 191 strerror(errno));
5ea8888e 192 LogMessage(L_ERROR, "Browsing turned off.");
1a5606a3 193
194 StopBrowsing();
195 Browsing = 0;
18d7d592 196 return;
197 }
198
199 packet[bytes] = '\0';
e5ebb675 200
201 /*
202 * Figure out where it came from...
203 */
204
205 address = ntohl(srcaddr.sin_addr.s_addr);
206
207 if (HostNameLookups)
208#ifndef __sgi
209 srchost = gethostbyaddr((char *)&(srcaddr.sin_addr), sizeof(struct in_addr),
210 AF_INET);
18d7d592 211#else
e5ebb675 212 srchost = gethostbyaddr(&(srcaddr.sin_addr), sizeof(struct in_addr),
213 AF_INET);
214#endif /* !__sgi */
215 else
216 srchost = NULL;
217
218 if (srchost == NULL)
219 sprintf(srcname, "%d.%d.%d.%d", address >> 24, (address >> 16) & 255,
220 (address >> 8) & 255, address & 255);
221 else
f9bacabb 222 {
e5ebb675 223 strncpy(srcname, srchost->h_name, sizeof(srcname) - 1);
224 srcname[sizeof(srcname) - 1] = '\0';
225 }
1a5606a3 226
e5ebb675 227 len = strlen(srcname);
228
229 /*
230 * Do ACL stuff...
231 */
232
233 if (BrowseACL)
234 {
235 if (address == 0x7f000001 || strcasecmp(srcname, "localhost") == 0)
236 {
237 /*
238 * Access from localhost (127.0.0.1) is always allowed...
239 */
240
241 auth = AUTH_ALLOW;
242 }
243 else
244 {
245 /*
246 * Do authorization checks on the domain/address...
247 */
248
d21a7597 249 switch (BrowseACL->order_type)
e5ebb675 250 {
d21a7597 251 default :
252 auth = AUTH_DENY; /* anti-compiler-warning-code */
253 break;
254
e5ebb675 255 case AUTH_ALLOW : /* Order Deny,Allow */
d21a7597 256 auth = AUTH_ALLOW;
257
e5ebb675 258 if (CheckAuth(address, srcname, len,
259 BrowseACL->num_deny, BrowseACL->deny))
260 auth = AUTH_DENY;
261
262 if (CheckAuth(address, srcname, len,
263 BrowseACL->num_allow, BrowseACL->allow))
264 auth = AUTH_ALLOW;
265 break;
266
267 case AUTH_DENY : /* Order Allow,Deny */
d21a7597 268 auth = AUTH_DENY;
269
e5ebb675 270 if (CheckAuth(address, srcname, len,
271 BrowseACL->num_allow, BrowseACL->allow))
272 auth = AUTH_ALLOW;
273
274 if (CheckAuth(address, srcname, len,
275 BrowseACL->num_deny, BrowseACL->deny))
276 auth = AUTH_DENY;
277 break;
278 }
279 }
280 }
281 else
282 auth = AUTH_ALLOW;
283
284 if (auth == AUTH_DENY)
285 {
286 LogMessage(L_DEBUG, "UpdateBrowseList: Refused %d bytes from %s", bytes,
287 srcname);
d6de4648 288 return;
f9bacabb 289 }
d6de4648 290
e5ebb675 291 LogMessage(L_DEBUG, "UpdateBrowseList: (%d bytes from %s) %s", bytes, srcname,
292 packet);
293
294 /*
295 * Parse packet...
296 */
d6de4648 297
a2c6b8b1 298 location[0] = '\0';
299 info[0] = '\0';
300 make_model[0] = '\0';
301
302 if (sscanf(packet,
303 "%x%x%1023s%*[^\"]\"%127[^\"]%*[^\"]\"%127[^\"]%*[^\"]\"%127[^\"]",
d21a7597 304 (unsigned *)&type, (unsigned *)&state, uri, location, info,
305 make_model) < 3)
d6de4648 306 {
5ea8888e 307 LogMessage(L_WARN, "UpdateBrowseList: Garbled browse packet - %s",
d6de4648 308 packet);
309 return;
310 }
311
a2c6b8b1 312 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
313 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
314 type, state, uri, location, info, make_model));
a8b216d5 315
d6de4648 316 /*
317 * Pull the URI apart to see if this is a local or remote printer...
318 */
319
320 httpSeparate(uri, method, username, host, &port, resource);
321
a8b216d5 322 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
323
d6de4648 324 if (strcasecmp(host, ServerName) == 0)
325 return;
326
e5ebb675 327 /*
328 * Do relaying...
329 */
330
331 for (i = 0; i < NumRelays; i ++)
332 if (CheckAuth(address, srcname, len, 1, &(Relays[i].from)))
333 if (sendto(BrowseSocket, packet, bytes, 0,
334 (struct sockaddr *)&(Relays[i].to),
335 sizeof(struct sockaddr_in)) <= 0)
336 {
337 LogMessage(L_ERROR, "UpdateBrowseList: sendto failed for relay %d - %s.",
338 i + 1, strerror(errno));
339 return;
340 }
341
d6de4648 342 /*
343 * OK, this isn't a local printer; see if we already have it listed in
344 * the Printers list, and add it if not...
345 */
346
8b43895a 347 hptr = strchr(host, '.');
348 sptr = strchr(ServerName, '.');
349
350 if (hptr != NULL && sptr != NULL &&
351 strcasecmp(hptr, sptr) == 0)
352 *hptr = '\0';
d6de4648 353
c7fa9d06 354 if (type & CUPS_PRINTER_CLASS)
d6de4648 355 {
356 /*
c7fa9d06 357 * Remote destination is a class...
d6de4648 358 */
359
c7fa9d06 360 if (strncmp(resource, "/classes/", 9) == 0)
970017a4 361 snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
c7fa9d06 362 else
363 return;
364
365 if ((p = FindClass(name)) == NULL)
366 {
367 /*
368 * Class doesn't exist; add it...
369 */
d6de4648 370
782359ca 371 p = AddClass(name);
c7fa9d06 372
373 /*
782359ca 374 * Force the URI to point to the real server...
c7fa9d06 375 */
376
5057ad3b 377 p->type = type;
c7fa9d06 378 strcpy(p->uri, uri);
5374d18c 379 strcpy(p->more_info, uri);
c7fa9d06 380 strcpy(p->device_uri, uri);
67a6c918 381 strcpy(p->hostname, host);
a2c6b8b1 382
383 strcpy(p->location, "Location Unknown");
384 strcpy(p->info, "No Information Available");
385 snprintf(p->make_model, sizeof(p->make_model), "Remote Class on %s",
386 host);
387
5057ad3b 388 SetPrinterAttrs(p);
c7fa9d06 389 }
390 }
391 else
392 {
d6de4648 393 /*
c7fa9d06 394 * Remote destination is a printer...
d6de4648 395 */
396
c7fa9d06 397 if (strncmp(resource, "/printers/", 10) == 0)
970017a4 398 snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
c7fa9d06 399 else
400 return;
401
402 if ((p = FindPrinter(name)) == NULL)
403 {
404 /*
405 * Printer doesn't exist; add it...
406 */
407
408 p = AddPrinter(name);
409
410 /*
5057ad3b 411 * Force the URI to point to the real server...
c7fa9d06 412 */
413
5057ad3b 414 p->type = type;
c7fa9d06 415 strcpy(p->uri, uri);
5374d18c 416 strcpy(p->more_info, uri);
c7fa9d06 417 strcpy(p->device_uri, uri);
67a6c918 418 strcpy(p->hostname, host);
a2c6b8b1 419
420 strcpy(p->location, "Location Unknown");
421 strcpy(p->info, "No Information Available");
422 snprintf(p->make_model, sizeof(p->make_model), "Remote Printer on %s",
423 host);
424
5057ad3b 425 SetPrinterAttrs(p);
c7fa9d06 426 }
d6de4648 427 }
428
429 /*
430 * Update the state...
431 */
432
f925c8de 433 p->type = type;
d6de4648 434 p->state = state;
0948b55b 435 p->accepting = state != IPP_PRINTER_STOPPED;
d6de4648 436 p->browse_time = time(NULL);
8b43895a 437
a2c6b8b1 438 if (location[0])
439 strcpy(p->location, location);
440 if (info[0])
441 strcpy(p->info, info);
442 if (make_model[0])
443 strcpy(p->make_model, make_model);
444
29a78848 445 /*
446 * If the remote printer is idle, check for local jobs that might need to
447 * go to it...
448 */
449
450 if (p->state == IPP_PRINTER_IDLE)
451 CheckJobs();
452
fb00e262 453 /*
4621b86f 454 * See if we have a default printer... If not, make the first printer the
455 * default.
fb00e262 456 */
457
458 if (DefaultPrinter == NULL && Printers != NULL)
459 DefaultPrinter = Printers;
460
8b43895a 461 /*
462 * Do auto-classing if needed...
463 */
464
465 if (ImplicitClasses)
466 {
467 /*
468 * Loop through all available printers and create classes as needed...
469 */
470
d21a7597 471 for (p = Printers, len = 0, offset = 0, first = NULL;
472 p != NULL;
473 p = p->next)
8b43895a 474 {
475 /*
476 * Skip classes...
477 */
478
479 if (p->type & CUPS_PRINTER_CLASS)
480 {
481 len = 0;
482 continue;
483 }
484
485 /*
486 * If len == 0, get the length of this printer name up to the "@"
487 * sign (if any).
488 */
489
490 if (len > 0 &&
eef5ad1b 491 strncasecmp(p->name, name + offset, len) == 0 &&
8b43895a 492 (p->name[len] == '\0' || p->name[len] == '@'))
493 {
494 /*
495 * We have more than one printer with the same name; see if
496 * we have a class, and if this printer is a member...
497 */
498
a2c6b8b1 499 if ((pclass = FindPrinter(name)) == NULL)
18d7d592 500 {
4139b718 501 /*
502 * Need to add the class...
503 */
504
a2c6b8b1 505 pclass = AddPrinter(name);
4139b718 506 pclass->type |= CUPS_PRINTER_IMPLICIT;
507 pclass->accepting = 1;
508 pclass->state = IPP_PRINTER_IDLE;
509
510 SetPrinterAttrs(pclass);
20da3efb 511
512 DEBUG_printf(("Added new class \"%s\", type = %x\n", name,
513 pclass->type));
18d7d592 514 }
8b43895a 515
516 if (first != NULL)
517 {
518 for (i = 0; i < pclass->num_printers; i ++)
519 if (pclass->printers[i] == first)
520 break;
521
522 if (i >= pclass->num_printers)
523 AddPrinterToClass(pclass, first);
524
525 first = NULL;
526 }
527
528 for (i = 0; i < pclass->num_printers; i ++)
529 if (pclass->printers[i] == p)
530 break;
531
532 if (i >= pclass->num_printers)
533 AddPrinterToClass(pclass, p);
534 }
535 else
536 {
537 /*
538 * First time around; just get name length and mark it as first
539 * in the list...
540 */
541
542 if ((hptr = strchr(p->name, '@')) != NULL)
543 len = hptr - p->name;
544 else
545 len = strlen(p->name);
546
782359ca 547 strncpy(name, p->name, len);
548 name[len] = '\0';
eef5ad1b 549 offset = 0;
782359ca 550
a2c6b8b1 551 if ((pclass = FindPrinter(name)) != NULL &&
552 !(pclass->type & CUPS_PRINTER_IMPLICIT))
782359ca 553 {
554 /*
555 * Can't use same name as printer; add "Any" to the front of the
556 * name...
557 */
558
559 strcpy(name, "Any");
560 strncpy(name + 3, p->name, len);
561 name[len + 3] = '\0';
eef5ad1b 562 offset = 3;
782359ca 563 }
564
8b43895a 565 first = p;
566 }
567 }
568 }
fd8b1cf8 569}
570
571
d6de4648 572/*
573 * 'SendBrowseList()' - Send new browsing information.
574 */
575
fd8b1cf8 576void
577SendBrowseList(void)
578{
d6de4648 579 int i; /* Looping var */
580 printer_t *p, /* Current printer */
581 *np; /* Next printer */
f9d6449d 582 time_t ut, /* Minimum update time */
583 to; /* Timeout time */
d6de4648 584 int bytes; /* Length of packet */
a2c6b8b1 585 char packet[1453];
d6de4648 586 /* Browse data packet */
587
588
03081fd2 589 if (!Browsing || BrowseInterval == 0)
f63a2256 590 return;
591
d6de4648 592 /*
593 * Compute the update time...
594 */
595
f9d6449d 596 ut = time(NULL) - BrowseInterval;
597 to = time(NULL) - BrowseTimeout;
d6de4648 598
599 /*
600 * Loop through all of the printers and send local updates as needed...
601 */
602
603 for (p = Printers; p != NULL; p = np)
604 {
605 np = p->next;
606
607 if (p->type & CUPS_PRINTER_REMOTE)
608 {
609 /*
610 * See if this printer needs to be timed out...
611 */
612
f9d6449d 613 if (p->browse_time < to)
e63d9801 614 {
5ea8888e 615 LogMessage(L_INFO, "Remote destination \"%s\" has timed out; deleting it...",
d62e9bdd 616 p->name);
d6de4648 617 DeletePrinter(p);
e63d9801 618 }
d6de4648 619 }
18d7d592 620 else if (p->browse_time < ut && !(p->type & CUPS_PRINTER_IMPLICIT))
d6de4648 621 {
622 /*
623 * Need to send an update...
624 */
625
626 p->browse_time = time(NULL);
627
a2c6b8b1 628 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"\n",
629 p->type | CUPS_PRINTER_REMOTE, p->state, p->uri,
630 p->location, p->info, p->make_model);
631
d6de4648 632 bytes = strlen(packet);
8828fd5f 633 DEBUG_printf(("SendBrowseList: (%d bytes) %s", bytes, packet));
d6de4648 634
635 /*
636 * Send a packet to each browse address...
637 */
638
639 for (i = 0; i < NumBrowsers; i ++)
16b0a852 640 if (sendto(BrowseSocket, packet, bytes, 0,
641 (struct sockaddr *)Browsers + i, sizeof(Browsers[0])) <= 0)
f63a2256 642 {
5ea8888e 643 LogMessage(L_ERROR, "SendBrowseList: sendto failed for browser %d - %s.",
fd3ece61 644 i + 1, strerror(errno));
f63a2256 645 LogMessage(L_ERROR, "Browsing turned off.");
646
647 StopBrowsing();
648 Browsing = 0;
649 return;
650 }
d6de4648 651 }
652 }
fd8b1cf8 653}
a129ddbd 654
655
656/*
03081fd2 657 * 'StartPolling()' - Start polling servers as needed.
658 */
659
660void
661StartPolling(void)
662{
e5ebb675 663 int i; /* Looping var */
664 dirsvc_poll_t *poll; /* Current polling server */
665 int pid; /* New process ID */
666 char sport[10]; /* Server port */
667 char bport[10]; /* Browser port */
668 char interval[10]; /* Poll interval */
669
670
671 sprintf(bport, "%d", BrowsePort);
672 sprintf(interval, "%d", BrowseInterval);
673
674 for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
675 {
676 sprintf(sport, "%d", poll->port);
677
678 if ((pid = fork()) == 0)
679 {
680 /*
681 * Child...
682 */
683
684 setgid(Group);
685 setuid(User);
686
687 execl(CUPS_SERVERBIN "/daemon/cups-polld", "cups-polld", poll->hostname,
688 sport, interval, bport, NULL);
689 exit(errno);
690 }
691 else if (pid < 0)
692 {
693 LogMessage(L_ERROR, "StartPolling: Unable to fork polling daemon - %s",
694 strerror(errno));
695 poll->pid = 0;
696 break;
697 }
698 else
699 {
700 poll->pid = pid;
701 LogMessage(L_DEBUG, "StartPolling: Started polling daemon for %s:%d, pid = %d",
702 poll->hostname, poll->port, pid);
703 }
704 }
03081fd2 705}
706
707
708/*
709 * 'StopPolling()' - Stop polling servers as needed.
710 */
711
712void
713StopPolling(void)
714{
e5ebb675 715 int i; /* Looping var */
716 dirsvc_poll_t *poll; /* Current polling server */
717
718
719 for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
720 if (poll->pid)
721 kill(poll->pid, SIGTERM);
03081fd2 722}
723
724
725/*
5374d18c 726 * End of "$Id: dirsvc.c,v 1.53 2000/04/19 15:18:55 mike Exp $".
a129ddbd 727 */