]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/dirsvc.c
2 * "$Id: dirsvc.c,v 1.73.2.3 2001/12/26 16:52:52 mike Exp $"
4 * Directory services routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2001 by Easy Software Products, all rights reserved.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * ProcessBrowseData() - Process new browse data.
27 * SendBrowseList() - Send new browsing information as necessary.
28 * SendCUPSBrowse() - Send new browsing information using the CUPS protocol.
29 * StartBrowsing() - Start sending and receiving broadcast information.
30 * StartPolling() - Start polling servers as needed.
31 * StopBrowsing() - Stop sending and receiving broadcast information.
32 * StopPolling() - Stop polling servers as needed.
33 * UpdateCUPSBrowse() - Update the browse lists using the CUPS protocol.
34 * RegReportCallback() - Empty SLPRegReport.
35 * SendSLPBrowse() - Register the specified printer with SLP.
36 * SLPDeregPrinter() - SLPDereg() the specified printer
37 * GetSlpAttrVal() - Get an attribute from an SLP registration.
38 * AttrCallback() - SLP attribute callback
39 * SrvUrlCallback() - SLP service url callback
40 * UpdateSLPBrowse() - Get browsing information via SLP.
44 * Include necessary headers...
52 * 'ProcessBrowseData()' - Process new browse data.
56 ProcessBrowseData(const char *uri
, /* I - URI of printer/class */
57 cups_ptype_t type
, /* I - Printer type */
58 ipp_pstate_t state
, /* I - Printer state */
59 const char *location
,/* I - Printer location */
60 const char *info
, /* I - Printer information */
61 const char *make_model
) /* I - Printer make and model */
63 int i
; /* Looping var */
64 int update
; /* Update printer attributes? */
65 char method
[HTTP_MAX_URI
], /* Method portion of URI */
66 username
[HTTP_MAX_URI
], /* Username portion of URI */
67 host
[HTTP_MAX_URI
], /* Host portion of URI */
68 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
69 int port
; /* Port portion of URI */
70 char name
[IPP_MAX_NAME
], /* Name of printer */
71 *hptr
, /* Pointer into hostname */
72 *sptr
; /* Pointer into ServerName */
73 char local_make_model
[IPP_MAX_NAME
];
74 /* Local make and model */
75 printer_t
*p
, /* Printer information */
76 *pclass
, /* Printer class */
77 *first
, /* First printer in class */
78 *next
; /* Next printer in list */
79 int offset
, /* Offset of name */
80 len
; /* Length of name */
84 * Pull the URI apart to see if this is a local or remote printer...
87 httpSeparate(uri
, method
, username
, host
, &port
, resource
);
90 * OK, this isn't a local printer; see if we already have it listed in
91 * the Printers list, and add it if not...
95 hptr
= strchr(host
, '.');
96 sptr
= strchr(ServerName
, '.');
98 if (sptr
!= NULL
&& hptr
!= NULL
)
101 * Strip the common domain name components...
106 if (strcasecmp(hptr
, sptr
) == 0)
112 hptr
= strchr(hptr
+ 1, '.');
116 if (type
& CUPS_PRINTER_CLASS
)
119 * Remote destination is a class...
122 if (strncmp(resource
, "/classes/", 9) == 0)
123 snprintf(name
, sizeof(name
), "%s@%s", resource
+ 9, host
);
127 if ((p
= FindClass(name
)) == NULL
&& BrowseShortNames
)
129 if ((p
= FindClass(resource
+ 9)) != NULL
)
131 if (strcasecmp(p
->hostname
, host
) != 0 && p
->hostname
[0])
134 * Nope, this isn't the same host; if the hostname isn't the local host,
135 * add it to the other class and then find a class using the full host
139 if (p
->type
& CUPS_PRINTER_REMOTE
)
141 /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
142 strncat(p
->name
, "@", sizeof(p
->name
) - 1);
143 strncat(p
->name
, p
->hostname
, sizeof(p
->name
) - 1);
150 else if (!p
->hostname
[0])
152 /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
153 strncpy(p
->hostname
, host
, sizeof(p
->hostname
) - 1);
154 strncpy(p
->uri
, uri
, sizeof(p
->uri
) - 1);
155 strncpy(p
->device_uri
, uri
, sizeof(p
->device_uri
) - 1);
161 strncpy(name
, resource
+ 9, sizeof(name
) - 1);
162 name
[sizeof(name
) - 1] = '\0';
165 else if (p
!= NULL
&& !p
->hostname
[0])
167 /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
168 strncpy(p
->hostname
, host
, sizeof(p
->hostname
) - 1);
169 strncpy(p
->uri
, uri
, sizeof(p
->uri
) - 1);
170 strncpy(p
->device_uri
, uri
, sizeof(p
->device_uri
) - 1);
177 * Class doesn't exist; add it...
182 LogMessage(L_INFO
, "Added remote class \"%s\"...", name
);
185 * Force the URI to point to the real server...
189 /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
190 strncpy(p
->uri
, uri
, sizeof(p
->uri
) - 1);
191 strncpy(p
->device_uri
, uri
, sizeof(p
->device_uri
) - 1);
192 strncpy(p
->hostname
, host
, sizeof(p
->hostname
) - 1);
200 * Remote destination is a printer...
203 if (strncmp(resource
, "/printers/", 10) == 0)
204 snprintf(name
, sizeof(name
), "%s@%s", resource
+ 10, host
);
208 if ((p
= FindPrinter(name
)) == NULL
&& BrowseShortNames
)
210 if ((p
= FindPrinter(resource
+ 10)) != NULL
)
212 if (strcasecmp(p
->hostname
, host
) != 0 && p
->hostname
[0])
215 * Nope, this isn't the same host; if the hostname isn't the local host,
216 * add it to the other printer and then find a printer using the full host
220 if (p
->type
& CUPS_PRINTER_REMOTE
)
222 /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
223 strncat(p
->name
, "@", sizeof(p
->name
) - 1);
224 strncat(p
->name
, p
->hostname
, sizeof(p
->name
) - 1);
231 else if (!p
->hostname
[0])
233 /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
234 strncpy(p
->hostname
, host
, sizeof(p
->hostname
) - 1);
235 strncpy(p
->uri
, uri
, sizeof(p
->uri
) - 1);
236 strncpy(p
->device_uri
, uri
, sizeof(p
->device_uri
) - 1);
242 strncpy(name
, resource
+ 10, sizeof(name
) - 1);
243 name
[sizeof(name
) - 1] = '\0';
246 else if (p
!= NULL
&& !p
->hostname
[0])
248 /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
249 strncpy(p
->hostname
, host
, sizeof(p
->hostname
) - 1);
250 strncpy(p
->uri
, uri
, sizeof(p
->uri
) - 1);
251 strncpy(p
->device_uri
, uri
, sizeof(p
->device_uri
) - 1);
258 * Printer doesn't exist; add it...
261 p
= AddPrinter(name
);
263 LogMessage(L_INFO
, "Added remote printer \"%s\"...", name
);
266 * Force the URI to point to the real server...
270 /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
271 strncpy(p
->hostname
, host
, sizeof(p
->hostname
) - 1);
272 strncpy(p
->uri
, uri
, sizeof(p
->uri
) - 1);
273 strncpy(p
->device_uri
, uri
, sizeof(p
->device_uri
) - 1);
280 * Update the state...
284 p
->accepting
= state
!= IPP_PRINTER_STOPPED
;
285 p
->browse_time
= time(NULL
);
293 if (strcmp(p
->location
, location
))
295 /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
296 strncpy(p
->location
, location
, sizeof(p
->location
) - 1);
300 if (strcmp(p
->info
, info
))
302 /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
303 strncpy(p
->info
, info
, sizeof(p
->info
) - 1);
309 if (type
& CUPS_PRINTER_CLASS
)
310 snprintf(local_make_model
, sizeof(local_make_model
),
311 "Remote Class on %s", host
);
313 snprintf(local_make_model
, sizeof(local_make_model
),
314 "Remote Printer on %s", host
);
317 snprintf(local_make_model
, sizeof(local_make_model
),
318 "%s on %s", make_model
, host
);
320 if (strcmp(p
->make_model
, local_make_model
))
322 /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
323 strncpy(p
->make_model
, local_make_model
, sizeof(p
->make_model
) - 1);
331 * See if we have a default printer... If not, make the first printer the
335 if (DefaultPrinter
== NULL
&& Printers
!= NULL
)
336 DefaultPrinter
= Printers
;
339 * Do auto-classing if needed...
345 * Loop through all available printers and create classes as needed...
348 for (p
= Printers
, len
= 0, offset
= 0, first
= NULL
;
353 * Get next printer in list...
362 if (p
->type
& (CUPS_PRINTER_IMPLICIT
| CUPS_PRINTER_CLASS
))
369 * If len == 0, get the length of this printer name up to the "@"
374 strncasecmp(p
->name
, name
+ offset
, len
) == 0 &&
375 (p
->name
[len
] == '\0' || p
->name
[len
] == '@'))
378 * We have more than one printer with the same name; see if
379 * we have a class, and if this printer is a member...
382 if ((pclass
= FindPrinter(name
)) == NULL
)
385 * Need to add the class...
388 pclass
= AddPrinter(name
);
389 pclass
->type
|= CUPS_PRINTER_IMPLICIT
;
390 pclass
->accepting
= 1;
391 pclass
->state
= IPP_PRINTER_IDLE
;
393 SetPrinterAttrs(pclass
);
395 LogMessage(L_INFO
, "Added implicit class \"%s\"...", name
);
400 for (i
= 0; i
< pclass
->num_printers
; i
++)
401 if (pclass
->printers
[i
] == first
)
404 if (i
>= pclass
->num_printers
)
405 AddPrinterToClass(pclass
, first
);
410 for (i
= 0; i
< pclass
->num_printers
; i
++)
411 if (pclass
->printers
[i
] == p
)
414 if (i
>= pclass
->num_printers
)
415 AddPrinterToClass(pclass
, p
);
420 * First time around; just get name length and mark it as first
424 if ((hptr
= strchr(p
->name
, '@')) != NULL
)
425 len
= hptr
- p
->name
;
427 len
= strlen(p
->name
);
429 strncpy(name
, p
->name
, len
);
433 if ((pclass
= FindPrinter(name
)) != NULL
&&
434 !(pclass
->type
& CUPS_PRINTER_IMPLICIT
))
437 * Can't use same name as a local printer; add "Any" to the
438 * front of the name, unless we have explicitly disabled
439 * the "ImplicitAnyClasses"...
442 if (ImplicitAnyClasses
)
445 * Add "Any" to the class name...
449 strncpy(name
+ 3, p
->name
, len
);
450 name
[len
+ 3] = '\0';
456 * Don't create an implicit class if we have a local printer
457 * with the same name...
473 * 'SendBrowseList()' - Send new browsing information as necessary.
479 printer_t
*p
, /* Current printer */
480 *np
; /* Next printer */
481 time_t ut
, /* Minimum update time */
482 to
; /* Timeout time */
485 if (!Browsing
|| !(BrowseProtocols
& BROWSE_CUPS
))
489 * Compute the update and timeout times...
492 ut
= time(NULL
) - BrowseInterval
;
493 to
= time(NULL
) - BrowseTimeout
;
496 * Loop through all of the printers and send local updates as needed...
499 for (p
= Printers
; p
!= NULL
; p
= np
)
503 if (p
->type
& CUPS_PRINTER_REMOTE
)
506 * See if this printer needs to be timed out...
509 if (p
->browse_time
< to
)
511 LogMessage(L_INFO
, "Remote destination \"%s\" has timed out; deleting it...",
516 else if (p
->browse_time
< ut
&& BrowseInterval
> 0 &&
517 !(p
->type
& CUPS_PRINTER_IMPLICIT
))
520 * Need to send an update...
523 p
->browse_time
= time(NULL
);
525 if (BrowseProtocols
& BROWSE_CUPS
)
529 if (BrowseProtocols
& BROWSE_SLP
)
531 #endif /* HAVE_LIBSLP */
538 * 'SendCUPSBrowse()' - Send new browsing information using the CUPS protocol.
542 SendCUPSBrowse(printer_t
*p
) /* I - Printer to send */
544 int i
; /* Looping var */
545 int bytes
; /* Length of packet */
547 /* Browse data packet */
550 snprintf(packet
, sizeof(packet
), "%x %x %s \"%s\" \"%s\" \"%s\"\n",
551 p
->type
| CUPS_PRINTER_REMOTE
, p
->state
, p
->uri
,
552 p
->location
, p
->info
, p
->make_model
);
554 bytes
= strlen(packet
);
555 LogMessage(L_DEBUG2
, "SendBrowseList: (%d bytes) %s", bytes
, packet
);
558 * Send a packet to each browse address...
561 for (i
= 0; i
< NumBrowsers
; i
++)
562 if (sendto(BrowseSocket
, packet
, bytes
, 0,
563 (struct sockaddr
*)Browsers
+ i
, sizeof(Browsers
[0])) <= 0)
565 LogMessage(L_ERROR
, "SendBrowseList: sendto failed for browser %d - %s.",
566 i
+ 1, strerror(errno
));
567 LogMessage(L_ERROR
, "Browsing turned off.");
577 * 'StartBrowsing()' - Start sending and receiving broadcast information.
583 int val
; /* Socket option value */
584 struct sockaddr_in addr
; /* Broadcast address */
590 if (BrowseProtocols
& BROWSE_CUPS
)
593 * Create the broadcast socket...
596 if ((BrowseSocket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
598 LogMessage(L_ERROR
, "StartBrowsing: Unable to create broadcast socket - %s.",
605 * Set the "broadcast" flag...
609 if (setsockopt(BrowseSocket
, SOL_SOCKET
, SO_BROADCAST
, &val
, sizeof(val
)))
611 LogMessage(L_ERROR
, "StartBrowsing: Unable to set broadcast mode - %s.",
614 #if defined(WIN32) || defined(__EMX__)
615 closesocket(BrowseSocket
);
618 #endif /* WIN32 || __EMX__ */
626 * Bind the socket to browse port...
629 memset(&addr
, 0, sizeof(addr
));
630 addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
631 addr
.sin_family
= AF_INET
;
632 addr
.sin_port
= htons(BrowsePort
);
634 if (bind(BrowseSocket
, (struct sockaddr
*)&addr
, sizeof(addr
)))
636 LogMessage(L_ERROR
, "StartBrowsing: Unable to bind broadcast socket - %s.",
639 #if defined(WIN32) || defined(__EMX__)
640 closesocket(BrowseSocket
);
643 #endif /* WIN32 || __EMX__ */
651 * Finally, add the socket to the input selection set...
654 LogMessage(L_DEBUG2
, "StartBrowsing: Adding fd %d to InputSet...",
657 FD_SET(BrowseSocket
, &InputSet
);
661 if (BrowseProtocols
& BROWSE_SLP
)
667 if (SLPOpen("en", SLP_FALSE
, &BrowseSLPHandle
) != SLP_OK
)
669 LogMessage(L_ERROR
, "Unable to open an SLP handle; disabling SLP browsing!");
670 BrowseProtocols
&= ~BROWSE_SLP
;
673 BrowseSLPRefresh
= 0;
679 * 'StartPolling()' - Start polling servers as needed.
685 int i
; /* Looping var */
686 dirsvc_poll_t
*poll
; /* Current polling server */
687 int pid
; /* New process ID */
688 char sport
[10]; /* Server port */
689 char bport
[10]; /* Browser port */
690 char interval
[10]; /* Poll interval */
693 sprintf(bport
, "%d", BrowsePort
);
696 sprintf(interval
, "%d", BrowseInterval
);
698 strcpy(interval
, "30");
700 for (i
= 0, poll
= Polled
; i
< NumPolled
; i
++, poll
++)
702 sprintf(sport
, "%d", poll
->port
);
704 if ((pid
= fork()) == 0)
713 * Running as root, so change to non-priviledged user...
724 * Reset group membership to just the main one we belong to.
730 * Execute the polling daemon...
733 execl(CUPS_SERVERBIN
"/daemon/cups-polld", "cups-polld", poll
->hostname
,
734 sport
, interval
, bport
, NULL
);
739 LogMessage(L_ERROR
, "StartPolling: Unable to fork polling daemon - %s",
747 LogMessage(L_DEBUG
, "StartPolling: Started polling daemon for %s:%d, pid = %d",
748 poll
->hostname
, poll
->port
, pid
);
756 * 'StopBrowsing()' - Stop sending and receiving broadcast information.
765 if (BrowseProtocols
& BROWSE_CUPS
)
768 * Close the socket and remove it from the input selection set.
771 if (BrowseSocket
>= 0)
773 #if defined(WIN32) || defined(__EMX__)
774 closesocket(BrowseSocket
);
777 #endif /* WIN32 || __EMX__ */
779 LogMessage(L_DEBUG2
, "StopBrowsing: Removing fd %d from InputSet...",
782 FD_CLR(BrowseSocket
, &InputSet
);
788 if (BrowseProtocols
& BROWSE_SLP
)
791 * Close SLP handle...
794 SLPClose(BrowseSLPHandle
);
796 #endif /* HAVE_LIBSLP */
801 * 'StopPolling()' - Stop polling servers as needed.
807 int i
; /* Looping var */
808 dirsvc_poll_t
*poll
; /* Current polling server */
811 for (i
= 0, poll
= Polled
; i
< NumPolled
; i
++, poll
++)
813 kill(poll
->pid
, SIGTERM
);
818 * 'UpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol.
822 UpdateCUPSBrowse(void)
824 int i
; /* Looping var */
825 int auth
; /* Authorization status */
826 int len
; /* Length of name string */
827 int bytes
; /* Number of bytes left */
828 char packet
[1540], /* Broadcast packet */
829 *pptr
; /* Pointer into packet */
830 http_addr_t srcaddr
; /* Source address */
831 char srcname
[1024]; /* Source hostname */
832 unsigned address
[4], /* Source address */
833 temp
; /* Temporary address var (host order) */
834 cups_ptype_t type
; /* Printer type */
835 ipp_pstate_t state
; /* Printer state */
836 char uri
[HTTP_MAX_URI
], /* Printer URI */
837 method
[HTTP_MAX_URI
], /* Method portion of URI */
838 username
[HTTP_MAX_URI
], /* Username portion of URI */
839 host
[HTTP_MAX_URI
], /* Host portion of URI */
840 resource
[HTTP_MAX_URI
], /* Resource portion of URI */
841 info
[IPP_MAX_NAME
], /* Information string */
842 location
[IPP_MAX_NAME
], /* Location string */
843 make_model
[IPP_MAX_NAME
];/* Make and model string */
844 int port
; /* Port portion of URI */
848 * Read a packet from the browse socket...
851 len
= sizeof(srcaddr
);
852 if ((bytes
= recvfrom(BrowseSocket
, packet
, sizeof(packet
), 0,
853 (struct sockaddr
*)&srcaddr
, &len
)) <= 0)
856 * "Connection refused" is returned under Linux if the destination port
857 * or address is unreachable from a previous sendto(); check for the
858 * error here and ignore it for now...
861 if (errno
!= ECONNREFUSED
)
863 LogMessage(L_ERROR
, "Browse recv failed - %s.", strerror(errno
));
864 LogMessage(L_ERROR
, "Browsing turned off.");
873 packet
[bytes
] = '\0';
876 * Figure out where it came from...
880 if (srcaddr
.addr
.sa_family
== AF_INET6
)
882 address
[0] = ntohl(srcaddr
.ipv6
.sin6_addr
.s6_addr32
[0]);
883 address
[1] = ntohl(srcaddr
.ipv6
.sin6_addr
.s6_addr32
[1]);
884 address
[2] = ntohl(srcaddr
.ipv6
.sin6_addr
.s6_addr32
[2]);
885 address
[3] = ntohl(srcaddr
.ipv6
.sin6_addr
.s6_addr32
[3]);
888 #endif /* AF_INET6 */
890 temp
= ntohl(srcaddr
.ipv4
.sin_addr
.s_addr
);
892 address
[3] = temp
& 255;
894 address
[2] = temp
& 255;
896 address
[1] = temp
& 255;
898 address
[0] = temp
& 255;
902 httpAddrLookup(&srcaddr
, srcname
, sizeof(srcname
));
904 httpAddrString(&srcaddr
, srcname
, sizeof(srcname
));
906 len
= strlen(srcname
);
912 if (BrowseACL
&& (BrowseACL
->num_allow
|| BrowseACL
->num_deny
))
914 if (httpAddrLocalhost(&srcaddr
) || strcasecmp(srcname
, "localhost") == 0)
917 * Access from localhost (127.0.0.1) is always allowed...
925 * Do authorization checks on the domain/address...
928 switch (BrowseACL
->order_type
)
931 auth
= AUTH_DENY
; /* anti-compiler-warning-code */
934 case AUTH_ALLOW
: /* Order Deny,Allow */
937 if (CheckAuth(address
, srcname
, len
,
938 BrowseACL
->num_deny
, BrowseACL
->deny
))
941 if (CheckAuth(address
, srcname
, len
,
942 BrowseACL
->num_allow
, BrowseACL
->allow
))
946 case AUTH_DENY
: /* Order Allow,Deny */
949 if (CheckAuth(address
, srcname
, len
,
950 BrowseACL
->num_allow
, BrowseACL
->allow
))
953 if (CheckAuth(address
, srcname
, len
,
954 BrowseACL
->num_deny
, BrowseACL
->deny
))
963 if (auth
== AUTH_DENY
)
965 LogMessage(L_DEBUG
, "UpdateBrowseList: Refused %d bytes from %s", bytes
,
970 LogMessage(L_DEBUG2
, "UpdateBrowseList: (%d bytes from %s) %s", bytes
, srcname
,
977 if (sscanf(packet
, "%x%x%1023s", (unsigned *)&type
, (unsigned *)&state
,
980 LogMessage(L_WARN
, "UpdateBrowseList: Garbled browse packet - %s",
985 strcpy(location
, "Location Unknown");
986 strcpy(info
, "No Information Available");
987 make_model
[0] = '\0';
989 if ((pptr
= strchr(packet
, '\"')) != NULL
)
992 * Have extended information; can't use sscanf for it because not all
993 * sscanf's allow empty strings with %[^\"]...
997 i
< (sizeof(location
) - 1) && *pptr
&& *pptr
!= '\"';
1007 while (*pptr
&& isspace(*pptr
))
1012 for (i
= 0, pptr
++;
1013 i
< (sizeof(info
) - 1) && *pptr
&& *pptr
!= '\"';
1023 while (*pptr
&& isspace(*pptr
))
1028 for (i
= 0, pptr
++;
1029 i
< (sizeof(make_model
) - 1) && *pptr
&& *pptr
!= '\"';
1031 make_model
[i
] = *pptr
;
1034 make_model
[i
] = '\0';
1040 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
1041 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
1042 type
, state
, uri
, location
, info
, make_model
));
1045 * Pull the URI apart to see if this is a local or remote printer...
1048 httpSeparate(uri
, method
, username
, host
, &port
, resource
);
1050 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host
, ServerName
));
1052 if (strcasecmp(host
, ServerName
) == 0)
1059 for (i
= 0; i
< NumRelays
; i
++)
1060 if (CheckAuth(address
, srcname
, len
, 1, &(Relays
[i
].from
)))
1061 if (sendto(BrowseSocket
, packet
, bytes
, 0,
1062 (struct sockaddr
*)&(Relays
[i
].to
),
1063 sizeof(http_addr_t
)) <= 0)
1065 LogMessage(L_ERROR
, "UpdateBrowseList: sendto failed for relay %d - %s.",
1066 i
+ 1, strerror(errno
));
1071 * Process the browse data...
1074 ProcessBrowseData(uri
, type
, state
, location
, info
, make_model
);
1078 /***********************************************************************
1079 **** SLP Support Code *************************************************
1080 ***********************************************************************/
1084 * SLP service name for CUPS...
1087 # define SLP_CUPS_SRVTYPE "service:printer"
1088 # define SLP_CUPS_SRVLEN 15
1090 typedef struct _slpsrvurl
1092 struct _slpsrvurl
*next
;
1093 char url
[HTTP_MAX_URI
];
1098 * 'RegReportCallback()' - Empty SLPRegReport.
1102 RegReportCallback(SLPHandle hslp
,
1115 * 'SendSLPBrowse()' - Register the specified printer with SLP.
1119 SendSLPBrowse(printer_t
*p
) /* I - Printer to register */
1121 char srvurl
[HTTP_MAX_URI
], /* Printer service URI */
1122 attrs
[8192], /* Printer attributes */
1123 finishings
[1024], /* Finishings to support */
1124 make_model
[IPP_MAX_NAME
* 2],
1125 /* Make and model, quoted */
1126 location
[IPP_MAX_NAME
* 2],
1127 /* Location, quoted */
1128 info
[IPP_MAX_NAME
* 2],
1130 *src
, /* Pointer to original string */
1131 *dst
; /* Pointer to destination string */
1132 ipp_attribute_t
*authentication
; /* uri-authentication-supported value */
1133 SLPError error
; /* SLP error, if any */
1136 LogMessage(L_DEBUG
, "SendSLPBrowse(%p = \"%s\")", p
, p
->name
);
1139 * Make the SLP service URL that conforms to the IANA
1140 * 'printer:' template.
1143 snprintf(srvurl
, sizeof(srvurl
), SLP_CUPS_SRVTYPE
":%s", p
->uri
);
1145 LogMessage(L_DEBUG2
, "Service URL = \"%s\"", srvurl
);
1148 * Figure out the finishings string...
1151 if (p
->type
& CUPS_PRINTER_STAPLE
)
1152 strcpy(finishings
, "staple");
1154 finishings
[0] = '\0';
1156 if (p
->type
& CUPS_PRINTER_BIND
)
1159 strncat(finishings
, ",bind", sizeof(finishings
) - 1);
1161 strcpy(finishings
, "bind");
1164 if (p
->type
& CUPS_PRINTER_PUNCH
)
1167 strncat(finishings
, ",punch", sizeof(finishings
) - 1);
1169 strcpy(finishings
, "punch");
1172 if (p
->type
& CUPS_PRINTER_COVER
)
1175 strncat(finishings
, ",cover", sizeof(finishings
) - 1);
1177 strcpy(finishings
, "cover");
1180 if (p
->type
& CUPS_PRINTER_SORT
)
1183 strncat(finishings
, ",sort", sizeof(finishings
) - 1);
1185 strcpy(finishings
, "sort");
1189 strcpy(finishings
, "none");
1191 finishings
[sizeof(finishings
) - 1] = '\0';
1194 * Quote any commas in the make and model, location, and info strings
1195 * (local strings are twice the size of the ones in the printer_t
1196 * structure, so no buffer overflow is possible...)
1199 for (src
= p
->make_model
, dst
= make_model
; *src
;)
1201 if (*src
== ',' || *src
== '\\' || *src
== ')')
1210 strcpy(make_model
, "Unknown");
1212 for (src
= p
->location
, dst
= location
; *src
;)
1214 if (*src
== ',' || *src
== '\\' || *src
== ')')
1223 strcpy(location
, "Unknown");
1225 for (src
= p
->info
, dst
= info
; *src
;)
1227 if (*src
== ',' || *src
== '\\' || *src
== ')')
1236 strcpy(info
, "Unknown");
1239 * Get the authentication value...
1242 authentication
= ippFindAttribute(p
->attrs
, "uri-authentication-supported",
1246 * Make the SLP attribute string list that conforms to
1247 * the IANA 'printer:' template.
1250 snprintf(attrs
, sizeof(attrs
),
1251 "(printer-uri-supported=%s),"
1252 "(uri-authentication-supported=%s>),"
1254 "(uri-security-supported=tls>),"
1256 "(uri-security-supported=none>),"
1257 #endif /* HAVE_LIBSSL */
1258 "(printer-name=%s),"
1259 "(printer-location=%s),"
1260 "(printer-info=%s),"
1261 "(printer-more-info=%s),"
1262 "(printer-make-and-model=%s),"
1263 "(charset-supported=utf-8),"
1264 "(natural-language-configured=%s),"
1265 "(natural-language-supported=de,en,es,fr,it),"
1266 "(color-supported=%s),"
1267 "(finishings-supported=%s),"
1268 "(sides-supported=one-sided%s),"
1269 "(multiple-document-jobs-supported=true)"
1270 "(ipp-versions-supported=1.0,1.1)",
1271 p
->uri
, authentication
->values
[0].string
.text
, p
->name
, location
,
1272 info
, p
->uri
, make_model
, DefaultLanguage
,
1273 p
->type
& CUPS_PRINTER_COLOR
? "true" : "false",
1275 p
->type
& CUPS_PRINTER_DUPLEX
?
1276 ",two-sided-long-edge,two-sided-short-edge" : "");
1278 LogMessage(L_DEBUG2
, "Attributes = \"%s\"", attrs
);
1281 * Register the printer with the SLP server...
1284 error
= SLPReg(BrowseSLPHandle
, srvurl
, BrowseTimeout
,
1285 SLP_CUPS_SRVTYPE
, attrs
, SLP_TRUE
, RegReportCallback
, 0);
1287 if (error
!= SLP_OK
)
1288 LogMessage(L_ERROR
, "SLPReg of \"%s\" failed with status %d!", p
->name
,
1294 * 'SLPDeregPrinter()' - SLPDereg() the specified printer
1298 SLPDeregPrinter(printer_t
*p
)
1300 char srvurl
[HTTP_MAX_URI
]; /* Printer service URI */
1303 if((p
->type
& CUPS_PRINTER_REMOTE
) == 0)
1306 * Make the SLP service URL that conforms to the IANA
1307 * 'printer:' template.
1310 snprintf(srvurl
, sizeof(srvurl
), SLP_CUPS_SRVTYPE
":%s", p
->uri
);
1313 * Deregister the printer...
1316 SLPDereg(BrowseSLPHandle
, srvurl
, RegReportCallback
, 0);
1322 * 'GetSlpAttrVal()' - Get an attribute from an SLP registration.
1325 int /* O - 0 on success */
1326 GetSlpAttrVal(const char *attrlist
, /* I - Attribute list string */
1327 const char *tag
, /* I - Name of attribute */
1328 char *valbuf
, /* O - Value */
1329 int valbuflen
) /* I - Max length of value */
1331 char *ptr1
, /* Pointer into string */
1337 if ((ptr1
= strstr(attrlist
, tag
)) != NULL
)
1339 ptr1
+= strlen(tag
);
1341 if ((ptr2
= strchr(ptr1
,')')) != NULL
)
1343 if (valbuflen
> (ptr2
- ptr1
))
1349 strncpy(valbuf
, ptr1
, ptr2
- ptr1
);
1350 valbuf
[ptr2
- ptr1
] = '\0';
1353 * Dequote the value...
1356 for (ptr1
= valbuf
; *ptr1
; ptr1
++)
1357 if (*ptr1
== '\\' && ptr1
[1])
1358 strcpy(ptr1
, ptr1
+ 1);
1370 * 'AttrCallback()' - SLP attribute callback
1374 AttrCallback(SLPHandle hslp
,
1375 const char *attrlist
,
1379 char tmp
[IPP_MAX_NAME
];
1380 printer_t
*p
= (printer_t
*)cookie
;
1384 * Let the compiler know we won't be using these...
1390 * Bail if there was an error
1393 if (errcode
!= SLP_OK
)
1397 * Parse the attrlist to obtain things needed to build CUPS browse packet
1400 memset(p
, 0, sizeof(printer_t
));
1402 p
->type
= CUPS_PRINTER_REMOTE
;
1404 if (GetSlpAttrVal(attrlist
, "(printer-location=", p
->location
,
1405 sizeof(p
->location
)))
1407 if (GetSlpAttrVal(attrlist
, "(printer-make-and-model=", p
->make_model
,
1408 sizeof(p
->make_model
)))
1411 if (GetSlpAttrVal(attrlist
, "(color-supported=", tmp
, sizeof(tmp
)))
1413 if (strcasecmp(tmp
, "true") == 0)
1414 p
->type
|= CUPS_PRINTER_COLOR
;
1416 if (GetSlpAttrVal(attrlist
, "(finishings-supported=", tmp
, sizeof(tmp
)))
1418 if (strstr(tmp
, "staple"))
1419 p
->type
|= CUPS_PRINTER_STAPLE
;
1420 if (strstr(tmp
, "bind"))
1421 p
->type
|= CUPS_PRINTER_BIND
;
1422 if (strstr(tmp
, "punch"))
1423 p
->type
|= CUPS_PRINTER_PUNCH
;
1425 if (GetSlpAttrVal(attrlist
, "(sides-supported=", tmp
, sizeof(tmp
)))
1427 if (strstr(tmp
,"two-sided"))
1428 p
->type
|= CUPS_PRINTER_DUPLEX
;
1435 * 'SrvUrlCallback()' - SLP service url callback
1438 SLPBoolean
/* O - TRUE = OK, FALSE = error */
1439 SrvUrlCallback(SLPHandle hslp
, /* I - SLP handle */
1440 const char *srvurl
, /* I - URL of service */
1441 unsigned short lifetime
, /* I - Life of service */
1442 SLPError errcode
, /* I - Existing error code */
1443 void *cookie
) /* I - Pointer to service list */
1445 slpsrvurl_t
*s
, /* New service entry */
1446 **head
; /* Pointer to head of entry */
1450 * Let the compiler know we won't be using these vars...
1457 * Bail if there was an error
1460 if (errcode
!= SLP_OK
)
1464 * Grab the head of the list...
1467 head
= (slpsrvurl_t
**)cookie
;
1470 * Allocate a *temporary* slpsrvurl_t to hold this entry.
1473 if ((s
= (slpsrvurl_t
*)calloc(1, sizeof(slpsrvurl_t
))) == NULL
)
1477 * Copy the SLP service URL...
1480 strncpy(s
->url
, srvurl
, sizeof(s
->url
));
1483 * Link the SLP service URL into the head of the list
1496 * 'UpdateSLPBrowse()' - Get browsing information via SLP.
1500 UpdateSLPBrowse(void)
1502 slpsrvurl_t
*s
, /* Temporary list of service URLs */
1503 *next
; /* Next service in list */
1504 printer_t p
; /* Printer information */
1505 const char *uri
; /* Pointer to printer URI */
1506 char method
[HTTP_MAX_URI
], /* Method portion of URI */
1507 username
[HTTP_MAX_URI
], /* Username portion of URI */
1508 host
[HTTP_MAX_URI
], /* Host portion of URI */
1509 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
1510 int port
; /* Port portion of URI */
1513 LogMessage(L_DEBUG
, "UpdateSLPBrowse() Start...");
1516 * Reset the refresh time...
1519 BrowseSLPRefresh
= time(NULL
) + BrowseTimeout
- BrowseInterval
;
1522 * Poll for remote printers using SLP...
1527 SLPFindSrvs(BrowseSLPHandle
, SLP_CUPS_SRVTYPE
, "", "",
1528 SrvUrlCallback
, &s
);
1531 * Loop through the list of available printers...
1537 * Load a printer_t structure with the SLP service attributes...
1540 SLPFindAttrs(BrowseSLPHandle
, s
->url
, "", "", AttrCallback
, &p
);
1543 * Process this printer entry...
1546 uri
= s
->url
+ SLP_CUPS_SRVLEN
+ 1;
1548 if (strncmp(uri
, "http://", 7) == 0 ||
1549 strncmp(uri
, "ipp://", 6) == 0)
1552 * Pull the URI apart to see if this is a local or remote printer...
1555 httpSeparate(uri
, method
, username
, host
, &port
, resource
);
1557 if (strcasecmp(host
, ServerName
) == 0)
1561 * OK, at least an IPP printer, see if it is a CUPS printer or
1565 if (strstr(uri
, "/printers/") != NULL
)
1566 ProcessBrowseData(uri
, p
.type
, IPP_PRINTER_IDLE
, p
.location
,
1567 p
.info
, p
.make_model
);
1568 else if (strstr(uri
, "/classes/") != NULL
)
1569 ProcessBrowseData(uri
, p
.type
| CUPS_PRINTER_CLASS
, IPP_PRINTER_IDLE
,
1570 p
.location
, p
.info
, p
.make_model
);
1574 * Save the "next" pointer and free this listing...
1581 LogMessage(L_DEBUG
, "UpdateSLPBrowse() End...");
1583 #endif /* HAVE_LIBSLP */
1587 * End of "$Id: dirsvc.c,v 1.73.2.3 2001/12/26 16:52:52 mike Exp $".