/*
- * "$Id: dirsvc.c 6205 2007-01-22 22:04:43Z mike $"
+ * "$Id: dirsvc.c 7676 2008-06-18 23:42:37Z mike $"
*
* Directory services routines for the Common UNIX Printing System (CUPS).
*
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* Contents:
*
- * cupsdLoadRemoteCache() - Load the remote printer cache.
- * cupsdSaveRemoteCache() - Save the remote printer cache.
- * cupsdSendBrowseDelete() - Send a "browse delete" message for a
- * printer.
- * cupsdSendBrowseList() - Send new browsing information as necessary.
- * cupsdStartBrowsing() - Start sending and receiving broadcast
- * information.
- * cupsdStartPolling() - Start polling servers as needed.
- * cupsdStopBrowsing() - Stop sending and receiving broadcast
- * information.
- * cupsdStopPolling() - Stop polling servers as needed.
- * cupsdUpdateCUPSBrowse() - Update the browse lists using the CUPS
- * protocol.
- * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
- * cupsdUpdatePolling() - Read status messages from the poll daemons.
- * cupsdUpdateSLPBrowse() - Get browsing information via SLP.
- * dequote() - Remote quotes from a string.
- * process_browse_data() - Process new browse data.
- * process_implicit_classes() - Create/update implicit classes as needed.
- * send_cups_browse() - Send new browsing information using the
- * CUPS protocol.
- * send_ldap_browse() - Send LDAP printer registrations.
- * send_slp_browse() - Register the specified printer with SLP.
- * slp_attr_callback() - SLP attribute callback
- * slp_dereg_printer() - SLPDereg() the specified printer
- * slp_get_attr() - Get an attribute from an SLP registration.
- * slp_reg_callback() - Empty SLPRegReport.
- * slp_url_callback() - SLP service url callback
+ * cupsdDeregisterPrinter() - Stop sending broadcast information for a local
+ * printer and remove any pending references to
+ * remote printers.
+ * cupsdLoadRemoteCache() - Load the remote printer cache.
+ * cupsdRegisterPrinter() - Start sending broadcast information for a
+ * printer or update the broadcast contents.
+ * cupsdRestartPolling() - Restart polling servers as needed.
+ * cupsdSaveRemoteCache() - Save the remote printer cache.
+ * cupsdSendBrowseList() - Send new browsing information as necessary.
+ * cupsdStartBrowsing() - Start sending and receiving broadcast
+ * information.
+ * cupsdStartPolling() - Start polling servers as needed.
+ * cupsdStopBrowsing() - Stop sending and receiving broadcast
+ * information.
+ * cupsdStopPolling() - Stop polling servers as needed.
+ * cupsdUpdateDNSSDName() - Update the computer name we use for
+ * browsing...
+ * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
+ * cupsdUpdateSLPBrowse() - Get browsing information via SLP.
+ * dequote() - Remote quotes from a string.
+ * dnssdBuildTxtRecord() - Build a TXT record from printer info.
+ * dnssdComparePrinters() - Compare the registered names of two printers.
+ * dnssdDeregisterPrinter() - Stop sending broadcast information for a
+ * printer.
+ * dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT
+ * record format.
+ * dnssdRegisterCallback() - DNSServiceRegister callback.
+ * dnssdRegisterPrinter() - Start sending broadcast information for a
+ * printer or update the broadcast contents.
+ * dnssdUpdate() - Handle DNS-SD queries.
+ * get_hostconfig() - Get an /etc/hostconfig service setting.
+ * is_local_queue() - Determine whether the URI points at a local
+ * queue.
+ * process_browse_data() - Process new browse data.
+ * process_implicit_classes() - Create/update implicit classes as needed.
+ * send_cups_browse() - Send new browsing information using the CUPS
+ * protocol.
+ * send_ldap_browse() - Send LDAP printer registrations.
+ * send_slp_browse() - Register the specified printer with SLP.
+ * slp_attr_callback() - SLP attribute callback
+ * slp_dereg_printer() - SLPDereg() the specified printer
+ * slp_get_attr() - Get an attribute from an SLP registration.
+ * slp_reg_callback() - Empty SLPRegReport.
+ * slp_url_callback() - SLP service url callback
+ * update_cups_browse() - Update the browse lists using the CUPS
+ * protocol.
+ * update_lpd() - Update the LPD configuration as needed.
+ * update_polling() - Read status messages from the poll daemons.
+ * update_smb() - Update the SMB configuration as needed.
*/
/*
#include "cupsd.h"
#include <grp.h>
+#ifdef HAVE_DNSSD
+# include <dns_sd.h>
+# ifdef __APPLE__
+# include <nameser.h>
+# ifdef HAVE_COREFOUNDATION
+# include <CoreFoundation/CoreFoundation.h>
+# endif /* HAVE_COREFOUNDATION */
+# ifdef HAVE_SYSTEMCONFIGURATION
+# include <SystemConfiguration/SystemConfiguration.h>
+# endif /* HAVE_SYSTEMCONFIGURATION */
+# endif /* __APPLE__ */
+#endif /* HAVE_DNSSD */
+
/*
* Local functions...
*/
static char *dequote(char *d, const char *s, int dlen);
+#ifdef __APPLE__
+static int get_hostconfig(const char *name);
+#endif /* __APPLE__ */
static int is_local_queue(const char *uri, char *host, int hostlen,
char *resource, int resourcelen);
static void process_browse_data(const char *uri, const char *host,
#ifdef HAVE_LIBSLP
static void send_slp_browse(cupsd_printer_t *p);
#endif /* HAVE_LIBSLP */
+static void update_cups_browse(void);
+static void update_lpd(int onoff);
+static void update_polling(void);
+static void update_smb(int onoff);
+
+
+#ifdef HAVE_DNSSD
+static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,
+ int for_lpd);
+static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b);
+static void dnssdDeregisterPrinter(cupsd_printer_t *p);
+static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2],
+ int count);
+static void dnssdRegisterCallback(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ DNSServiceErrorType errorCode,
+ const char *name, const char *regtype,
+ const char *domain, void *context);
+static void dnssdRegisterPrinter(cupsd_printer_t *p);
+static void dnssdUpdate(void);
+#endif /* HAVE_DNSSD */
#ifdef HAVE_OPENLDAP
static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
#endif /* HAVE_LIBSLP */
+/*
+ * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
+ * local printer and remove any pending
+ * references to remote printers.
+ */
+
+void
+cupsdDeregisterPrinter(
+ cupsd_printer_t *p, /* I - Printer to register */
+ int removeit) /* I - Printer being permanently removed */
+{
+ /*
+ * Only deregister if browsing is enabled and it's a local printer...
+ */
+
+ if (!Browsing || !p->shared ||
+ (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
+ return;
+
+ /*
+ * Announce the deletion...
+ */
+
+ if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
+ {
+ cups_ptype_t savedtype = p->type; /* Saved printer type */
+
+ p->type |= CUPS_PRINTER_DELETE;
+
+ send_cups_browse(p);
+
+ p->type = savedtype;
+ }
+
+#ifdef HAVE_LIBSLP
+ if (BrowseLocalProtocols & BROWSE_SLP)
+ slp_dereg_printer(p);
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_DNSSD
+ if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
+ dnssdDeregisterPrinter(p);
+#endif /* HAVE_DNSSD */
+}
+
+
/*
* 'cupsdLoadRemoteCache()' - Load the remote printer cache.
*/
/*
- * Don't load the cache if the CUPS remote protocol is disabled...
+ * Don't load the cache if the remote protocols are disabled...
*/
- if (!Browsing || !(BrowseRemoteProtocols & BROWSE_CUPS))
+ if (!Browsing)
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"cupsdLoadRemoteCache: Not loading remote cache.");
p->accepting = 1;
p->state = IPP_PRINTER_IDLE;
- p->type |= CUPS_PRINTER_REMOTE;
+ p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
p->browse_time = now;
p->browse_expire = now + BrowseTimeout;
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!strcasecmp(line, "<Class") ||
p->accepting = 1;
p->state = IPP_PRINTER_IDLE;
- p->type |= CUPS_PRINTER_REMOTE;
+ p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
p->browse_time = now;
p->browse_expire = now + BrowseTimeout;
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!strcasecmp(line, "</Printer>") ||
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!p)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
else if (!strcasecmp(line, "Info"))
{
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!strcasecmp(line, "Option") && value)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!strcasecmp(line, "StateMessage"))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!strcasecmp(line, "Type"))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!strcasecmp(line, "BrowseTime"))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!strcasecmp(line, "JobSheets"))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!strcasecmp(line, "AllowUser"))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!strcasecmp(line, "DenyUser"))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else
}
+/*
+ * 'cupsdRegisterPrinter()' - Start sending broadcast information for a
+ * printer or update the broadcast contents.
+ */
+
+void
+cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
+{
+ if (!Browsing || !BrowseLocalProtocols ||
+ (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
+ return;
+
+#ifdef HAVE_LIBSLP
+/* if (BrowseLocalProtocols & BROWSE_SLP)
+ slpRegisterPrinter(p); */
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_DNSSD
+ if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
+ dnssdRegisterPrinter(p);
+#endif /* HAVE_DNSSD */
+}
+
+
/*
* 'cupsdRestartPolling()' - Restart polling servers as needed.
*/
return;
}
else
- cupsdLogMessage(CUPSD_LOG_INFO, "Saving remote.cache...");
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Saving remote.cache...");
/*
* Restrict access to the file...
* Skip local destinations...
*/
- if (!(printer->type & CUPS_PRINTER_REMOTE))
+ if (!(printer->type & CUPS_PRINTER_DISCOVERED))
continue;
/*
}
-/*
- * 'cupsdSendBrowseDelete()' - Send a "browse delete" message for a printer.
- */
-
-void
-cupsdSendBrowseDelete(
- cupsd_printer_t *p) /* I - Printer to delete */
-{
- /*
- * Only announce if browsing is enabled and this is a local queue...
- */
-
- if (!Browsing || !p->shared ||
- (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
- return;
-
- /*
- * First mark the printer for deletion...
- */
-
- p->type |= CUPS_PRINTER_DELETE;
-
- /*
- * Announce the deletion...
- */
-
- if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
- send_cups_browse(p);
-#ifdef HAVE_LIBSLP
- if ((BrowseLocalProtocols & BROWSE_SLP) && BrowseSLPHandle)
- slp_dereg_printer(p);
-#endif /* HAVE_LIBSLP */
-}
-
-
/*
* 'cupsdSendBrowseList()' - Send new browsing information as necessary.
*/
p->browse_time = time(NULL);
- if (BrowseLocalProtocols & BROWSE_CUPS)
+ if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
send_cups_browse(p);
#ifdef HAVE_LIBSLP
* If this is a remote queue, see if it needs to be timed out...
*/
- if (p->type & CUPS_PRINTER_REMOTE)
+ if (p->type & CUPS_PRINTER_DISCOVERED)
{
if (p->browse_expire < to)
{
cupsArraySave(Printers);
cupsdDeletePrinter(p, 1);
cupsArrayRestore(Printers);
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
}
}
}
{
int val; /* Socket option value */
struct sockaddr_in addr; /* Broadcast address */
+ cupsd_printer_t *p; /* Current printer */
BrowseNext = NULL;
if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to create broadcast "
- "socket - %s.", strerror(errno));
+ "Unable to create broadcast socket - %s.",
+ strerror(errno));
BrowseLocalProtocols &= ~BROWSE_CUPS;
BrowseRemoteProtocols &= ~BROWSE_CUPS;
return;
if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to bind broadcast "
- "socket - %s.", strerror(errno));
+ "Unable to bind broadcast socket - %s.",
+ strerror(errno));
#ifdef WIN32
closesocket(BrowseSocket);
val = 1;
if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to set broadcast mode - %s.",
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
strerror(errno));
#ifdef WIN32
* We only listen if we want remote printers...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStartBrowsing: Adding fd %d to InputSet...",
- BrowseSocket);
-
- FD_SET(BrowseSocket, InputSet);
+ cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
+ NULL, NULL);
}
}
else
BrowseSocket = -1;
+#ifdef HAVE_DNSSD
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
+ {
+ DNSServiceErrorType error; /* Error from service creation */
+ cupsd_listener_t *lis; /* Current listening socket */
+
+
+ /*
+ * First create a "master" connection for all registrations...
+ */
+
+ if ((error = DNSServiceCreateConnection(&DNSSDRef))
+ != kDNSServiceErr_NoError)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create master DNS-SD reference: %d", error);
+ else
+ {
+ /*
+ * Add the master connection to the select list...
+ */
+
+ cupsdAddSelect(DNSServiceRefSockFD(DNSSDRef),
+ (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
+
+ /*
+ * Then get the port we use for registrations. If we are not listening
+ * on any non-local ports, there is no sense sharing local printers via
+ * Bonjour...
+ */
+
+ DNSSDPort = 0;
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ {
+ if (httpAddrLocalhost(&(lis->address)))
+ continue;
+
+ if (lis->address.addr.sa_family == AF_INET)
+ {
+ DNSSDPort = ntohs(lis->address.ipv4.sin_port);
+ break;
+ }
+ else if (lis->address.addr.sa_family == AF_INET6)
+ {
+ DNSSDPort = ntohs(lis->address.ipv6.sin6_port);
+ break;
+ }
+ }
+
+ /*
+ * Create an array to track the printers we share...
+ */
+
+ if (BrowseRemoteProtocols & BROWSE_DNSSD)
+ DNSSDPrinters = cupsArrayNew((cups_array_func_t)dnssdComparePrinters,
+ NULL);
+
+ /*
+ * Set the computer name and register the web interface...
+ */
+
+ cupsdUpdateDNSSDName();
+ }
+ }
+#endif /* HAVE_DNSSD */
+
#ifdef HAVE_LIBSLP
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
{
struct berval bv = {0, ""}; /* SASL bind value */
+ /*
+ * Set the certificate file to use for encrypted LDAP sessions...
+ */
+
+ if (BrowseLDAPCACertFile)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdStartBrowsing: Setting CA certificate file \"%s\"",
+ BrowseLDAPCACertFile);
+
+ if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+ (void *)BrowseLDAPCACertFile))
+ != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to set CA certificate file for LDAP "
+ "connections: %d - %s", rc, ldap_err2string(rc));
+ }
+
/*
* LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
*/
BrowseLDAPRefresh = 0;
}
#endif /* HAVE_OPENLDAP */
+
+ /*
+ * Enable LPD and SMB printer sharing as needed through external programs...
+ */
+
+ if (BrowseLocalProtocols & BROWSE_LPD)
+ update_lpd(1);
+
+ if (BrowseLocalProtocols & BROWSE_SMB)
+ update_smb(1);
+
+ /*
+ * Register the individual printers
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
+ cupsdRegisterPrinter(p);
}
argv[1] = pollp->hostname;
- if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1,
- 0, &(pollp->pid)) < 0)
+ if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
+ 0, DefaultProfile, &(pollp->pid)) < 0)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"cupsdStartPolling: Unable to fork polling daemon - %s",
* Finally, add the pipe to the input selection set...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStartPolling: Adding fd %d to InputSet...", PollPipe);
-
- FD_SET(PollPipe, InputSet);
+ cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
}
void
cupsdStopBrowsing(void)
{
+ cupsd_printer_t *p; /* Current printer */
+
+
if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
return;
+ /*
+ * De-register the individual printers
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
+ cupsdDeregisterPrinter(p, 1);
+
+ /*
+ * Shut down browsing sockets...
+ */
+
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
BrowseSocket >= 0)
{
close(BrowseSocket);
#endif /* WIN32 */
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStopBrowsing: Removing fd %d from InputSet...",
- BrowseSocket);
-
- FD_CLR(BrowseSocket, InputSet);
+ cupsdRemoveSelect(BrowseSocket);
BrowseSocket = -1;
}
+#ifdef HAVE_DNSSD
+ if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
+ {
+ if (WebIFRef)
+ {
+ DNSServiceRefDeallocate(WebIFRef);
+ WebIFRef = NULL;
+ }
+
+ if (RemoteRef)
+ {
+ DNSServiceRefDeallocate(RemoteRef);
+ RemoteRef = NULL;
+ }
+
+ cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef));
+
+ DNSServiceRefDeallocate(DNSSDRef);
+ DNSSDRef = NULL;
+
+ cupsArrayDelete(DNSSDPrinters);
+ DNSSDPrinters = NULL;
+
+ DNSSDPort = 0;
+ }
+#endif /* HAVE_DNSSD */
+
#ifdef HAVE_LIBSLP
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
BrowseSLPHandle)
BrowseLDAPHandle = NULL;
}
#endif /* HAVE_OPENLDAP */
+
+ /*
+ * Disable LPD and SMB printer sharing as needed through external programs...
+ */
+
+ if (BrowseLocalProtocols & BROWSE_LPD)
+ update_lpd(0);
+
+ if (BrowseLocalProtocols & BROWSE_SMB)
+ update_smb(0);
}
cupsdStatBufDelete(PollStatusBuffer);
close(PollPipe);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStopPolling: removing fd %d from InputSet.", PollPipe);
- FD_CLR(PollPipe, InputSet);
+ cupsdRemoveSelect(PollPipe);
PollPipe = -1;
PollStatusBuffer = NULL;
}
+#ifdef HAVE_DNSSD
/*
- * 'cupsdUpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol.
+ * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
*/
void
-cupsdUpdateCUPSBrowse(void)
+cupsdUpdateDNSSDName(void)
{
- int i; /* Looping var */
- int auth; /* Authorization status */
- int len; /* Length of name string */
- int bytes; /* Number of bytes left */
- char packet[1541], /* Broadcast packet */
- *pptr; /* Pointer into packet */
- socklen_t srclen; /* Length of source address */
- http_addr_t srcaddr; /* Source address */
- char srcname[1024]; /* Source hostname */
- unsigned address[4]; /* Source address */
- unsigned type; /* Printer type */
- unsigned state; /* Printer state */
- char uri[HTTP_MAX_URI], /* Printer URI */
- host[HTTP_MAX_URI], /* Host portion of URI */
- resource[HTTP_MAX_URI], /* Resource portion of URI */
- info[IPP_MAX_NAME], /* Information string */
- location[IPP_MAX_NAME], /* Location string */
- make_model[IPP_MAX_NAME];/* Make and model string */
- int num_attrs; /* Number of attributes */
- cups_option_t *attrs; /* Attributes */
+ DNSServiceErrorType error; /* Error from service creation */
+ char webif[1024]; /* Web interface share name */
+#ifdef HAVE_COREFOUNDATION_H
+ CFStringRef nameRef; /* Computer name CFString */
+ char nameBuffer[1024]; /* C-string buffer */
+ CFStringEncoding nameEncoding; /* Computer name encoding */
+#endif /* HAVE_COREFOUNDATION_H */
/*
- * Read a packet from the browse socket...
+ * Only share the web interface and printers when non-local listening is
+ * enabled...
*/
- srclen = sizeof(srcaddr);
- if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
- (struct sockaddr *)&srcaddr, &srclen)) < 0)
- {
- /*
- * "Connection refused" is returned under Linux if the destination port
- * or address is unreachable from a previous sendto(); check for the
- * error here and ignore it for now...
- */
+ if (!DNSSDPort)
+ return;
- if (errno != ECONNREFUSED && errno != EAGAIN)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
- strerror(errno));
- cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
+ /*
+ * Get the computer name as a c-string...
+ */
- cupsdStopBrowsing();
- Browsing = 0;
- }
+#ifdef HAVE_COREFOUNDATION_H
+ cupsdClearString(&DNSSDName);
- return;
+ if ((nameRef = SCDynamicStoreCopyComputerName(NULL,
+ &nameEncoding)) != NULL)
+ {
+ if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
+ kCFStringEncodingUTF8))
+ cupsdSetString(&DNSSDName, nameBuffer);
+
+ CFRelease(nameRef);
}
- packet[bytes] = '\0';
+#else
+ cupsdSetString(&DNSSDName, ServerName);
+#endif /* HAVE_COREFOUNDATION_H */
/*
- * If we're about to sleep, ignore incoming browse packets.
+ * Then (re)register the web interface...
*/
- if (Sleeping)
- return;
-
- /*
- * Figure out where it came from...
- */
-
-#ifdef AF_INET6
- if (srcaddr.addr.sa_family == AF_INET6)
- {
- address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
- address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
- address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
- address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
- }
- else
-#endif /* AF_INET6 */
- {
- address[0] = 0;
- address[1] = 0;
- address[2] = 0;
- address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
- }
-
- if (HostNameLookups)
- httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
- else
- httpAddrString(&srcaddr, srcname, sizeof(srcname));
-
- len = strlen(srcname);
-
- /*
- * Do ACL stuff...
- */
-
- if (BrowseACL)
- {
- if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
- {
- /*
- * Access from localhost (127.0.0.1) is always allowed...
- */
-
- auth = AUTH_ALLOW;
- }
- else
- {
- /*
- * Do authorization checks on the domain/address...
- */
-
- switch (BrowseACL->order_type)
- {
- default :
- auth = AUTH_DENY; /* anti-compiler-warning-code */
- break;
-
- case AUTH_ALLOW : /* Order Deny,Allow */
- auth = AUTH_ALLOW;
-
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_deny, BrowseACL->deny))
- auth = AUTH_DENY;
-
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_allow, BrowseACL->allow))
- auth = AUTH_ALLOW;
- break;
-
- case AUTH_DENY : /* Order Allow,Deny */
- auth = AUTH_DENY;
-
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_allow, BrowseACL->allow))
- auth = AUTH_ALLOW;
-
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_deny, BrowseACL->deny))
- auth = AUTH_DENY;
- break;
- }
- }
- }
- else
- auth = AUTH_ALLOW;
-
- if (auth == AUTH_DENY)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "cupsdUpdateCUPSBrowse: Refused %d bytes from %s", bytes,
- srcname);
- return;
- }
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdUpdateCUPSBrowse: (%d bytes from %s) %s", bytes,
- srcname, packet);
-
- /*
- * Parse packet...
- */
-
- if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
- {
- cupsdLogMessage(CUPSD_LOG_WARN,
- "cupsdUpdateCUPSBrowse: Garbled browse packet - %s", packet);
- return;
- }
-
- strcpy(location, "Location Unknown");
- strcpy(info, "No Information Available");
- make_model[0] = '\0';
- num_attrs = 0;
- attrs = NULL;
-
- if ((pptr = strchr(packet, '\"')) != NULL)
- {
- /*
- * Have extended information; can't use sscanf for it because not all
- * sscanf's allow empty strings with %[^\"]...
- */
-
- for (i = 0, pptr ++;
- i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
- i ++, pptr ++)
- location[i] = *pptr;
-
- if (i)
- location[i] = '\0';
-
- if (*pptr == '\"')
- pptr ++;
-
- while (*pptr && isspace(*pptr & 255))
- pptr ++;
-
- if (*pptr == '\"')
- {
- for (i = 0, pptr ++;
- i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
- i ++, pptr ++)
- info[i] = *pptr;
-
- info[i] = '\0';
-
- if (*pptr == '\"')
- pptr ++;
-
- while (*pptr && isspace(*pptr & 255))
- pptr ++;
-
- if (*pptr == '\"')
- {
- for (i = 0, pptr ++;
- i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
- i ++, pptr ++)
- make_model[i] = *pptr;
-
- if (*pptr == '\"')
- pptr ++;
-
- make_model[i] = '\0';
-
- if (*pptr)
- num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
- }
- }
- }
-
- DEBUG_puts(packet);
- DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
- "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
- type, state, uri, location, info, make_model));
-
- /*
- * Pull the URI apart to see if this is a local or remote printer...
- */
-
- if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
- {
- cupsFreeOptions(num_attrs, attrs);
- return;
- }
-
- /*
- * Do relaying...
- */
-
- for (i = 0; i < NumRelays; i ++)
- if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
- if (sendto(BrowseSocket, packet, bytes, 0,
- (struct sockaddr *)&(Relays[i].to),
- httpAddrLength(&(Relays[i].to))) <= 0)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdUpdateCUPSBrowse: sendto failed for relay %d - %s.",
- i + 1, strerror(errno));
- cupsFreeOptions(num_attrs, attrs);
- return;
- }
-
- /*
- * Process the browse data...
- */
-
- process_browse_data(uri, host, resource, (cups_ptype_t)type,
- (ipp_pstate_t)state, location, info, make_model,
- num_attrs, attrs);
-}
+ if (DNSSDName)
+ snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDName);
+ else
+ strlcpy(webif, "CUPS Web Interface", sizeof(webif));
+
+ if (WebIFRef)
+ DNSServiceRefDeallocate(WebIFRef);
+
+ WebIFRef = DNSSDRef;
+ if ((error = DNSServiceRegister(&WebIFRef,
+ kDNSServiceFlagsShareConnection,
+ 0, webif, "_http._tcp", NULL,
+ NULL, htons(DNSSDPort), 7,
+ "\006path=/", dnssdRegisterCallback,
+ NULL)) != kDNSServiceErr_NoError)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNS-SD web interface registration failed: %d", error);
+}
+#endif /* HAVE_DNSSD */
#ifdef HAVE_OPENLDAP
#endif /* HAVE_OPENLDAP */
-/*
- * 'cupsdUpdatePolling()' - Read status messages from the poll daemons.
- */
-
-void
-cupsdUpdatePolling(void)
-{
- char *ptr, /* Pointer to end of line in buffer */
- message[1024]; /* Pointer to message text */
- int loglevel; /* Log level for message */
-
-
- while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
- message, sizeof(message))) != NULL)
- if (!strchr(PollStatusBuffer->buffer, '\n'))
- break;
-
- if (ptr == NULL && !PollStatusBuffer->bufused)
- {
- /*
- * All polling processes have died; stop polling...
- */
-
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdUpdatePolling: all polling processes have exited!");
- cupsdStopPolling();
- }
-}
-
-
#ifdef HAVE_LIBSLP
/*
* 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
}
+#ifdef HAVE_DNSSD
/*
- * 'is_local_queue()' - Determine whether the URI points at a local queue.
+ * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
*/
-static int /* O - 1 = local, 0 = remote, -1 = bad URI */
-is_local_queue(const char *uri, /* I - Printer URI */
- char *host, /* O - Host string */
- int hostlen, /* I - Length of host buffer */
- char *resource, /* O - Resource string */
- int resourcelen) /* I - Length of resource buffer */
+static char * /* O - TXT record */
+dnssdBuildTxtRecord(
+ int *txt_len, /* O - TXT record length */
+ cupsd_printer_t *p, /* I - Printer information */
+ int for_lpd) /* I - 1 = LPD, 0 = IPP */
{
- char scheme[32], /* Scheme portion of URI */
- username[HTTP_MAX_URI]; /* Username portion of URI */
- int port; /* Port portion of URI */
- cupsd_netif_t *iface; /* Network interface */
+ int i, j; /* Looping vars */
+ char type_str[32], /* Type to string buffer */
+ state_str[32], /* State to string buffer */
+ rp_str[1024], /* Queue name string buffer */
+ air_str[1024], /* auth-info-required string buffer */
+ *keyvalue[32][2]; /* Table of key/value pairs */
/*
- * Pull the URI apart to see if this is a local or remote printer...
+ * Load up the key value pairs...
*/
- if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
- username, sizeof(username), host, hostlen, &port,
- resource, resourcelen) < HTTP_URI_OK)
- return (-1);
+ i = 0;
- DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
+ keyvalue[i ][0] = "txtvers";
+ keyvalue[i++][1] = "1";
- /*
- * Check for local server addresses...
- */
+ keyvalue[i ][0] = "qtotal";
+ keyvalue[i++][1] = "1";
- if (!strcasecmp(host, ServerName) && port == LocalPort)
- return (1);
+ keyvalue[i ][0] = "rp";
+ keyvalue[i++][1] = rp_str;
+ if (for_lpd)
+ strlcpy(rp_str, p->name, sizeof(rp_str));
+ else
+ snprintf(rp_str, sizeof(rp_str), "%s/%s",
+ (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
- cupsdNetIFUpdate();
+ keyvalue[i ][0] = "ty";
+ keyvalue[i++][1] = p->make_model;
- for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
- iface;
- iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
- if (!strcasecmp(host, iface->hostname) && port == iface->port)
- return (1);
+ if (p->location && *p->location != '\0')
+ {
+ keyvalue[i ][0] = "note";
+ keyvalue[i++][1] = p->location;
+ }
- /*
- * If we get here, the printer is remote...
- */
+ keyvalue[i ][0] = "priority";
+ keyvalue[i++][1] = for_lpd ? "100" : "0";
- return (0);
-}
+ keyvalue[i ][0] = "product";
+ keyvalue[i++][1] = p->product ? p->product : "Unknown";
+ snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
+ snprintf(state_str, sizeof(state_str), "%d", p->state);
-/*
- * 'process_browse_data()' - Process new browse data.
- */
+ keyvalue[i ][0] = "printer-state";
+ keyvalue[i++][1] = state_str;
-static void
-process_browse_data(
- const char *uri, /* I - URI of printer/class */
- const char *host, /* I - Hostname */
- const char *resource, /* I - Resource path */
- cups_ptype_t type, /* I - Printer type */
- ipp_pstate_t state, /* I - Printer state */
- const char *location, /* I - Printer location */
- const char *info, /* I - Printer information */
- const char *make_model, /* I - Printer make and model */
- int num_attrs, /* I - Number of attributes */
- cups_option_t *attrs) /* I - Attributes */
-{
- int i; /* Looping var */
- int update; /* Update printer attributes? */
- char finaluri[HTTP_MAX_URI], /* Final URI for printer */
- name[IPP_MAX_NAME], /* Name of printer */
- newname[IPP_MAX_NAME], /* New name of printer */
- *hptr, /* Pointer into hostname */
- *sptr; /* Pointer into ServerName */
- char local_make_model[IPP_MAX_NAME];
- /* Local make and model */
- cupsd_printer_t *p; /* Printer information */
- const char *ipp_options, /* ipp-options value */
- *lease_duration; /* lease-duration value */
+ keyvalue[i ][0] = "printer-type";
+ keyvalue[i++][1] = type_str;
+ keyvalue[i ][0] = "Transparent";
+ keyvalue[i++][1] = "T";
- /*
- * Determine if the URI contains any illegal characters in it...
- */
+ keyvalue[i ][0] = "Binary";
+ keyvalue[i++][1] = "T";
- if (strncmp(uri, "ipp://", 6) || !host[0] ||
- (strncmp(resource, "/printers/", 10) &&
- strncmp(resource, "/classes/", 9)))
+ if ((p->type & CUPS_PRINTER_FAX))
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "process_browse_data: Bad printer URI in browse data: %s",
- uri);
- return;
+ keyvalue[i ][0] = "Fax";
+ keyvalue[i++][1] = "T";
}
- if (strchr(resource, '?') ||
- (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
- (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
+ if ((p->type & CUPS_PRINTER_COLOR))
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "process_browse_data: Bad resource in browse data: %s",
- resource);
- return;
+ keyvalue[i ][0] = "Color";
+ keyvalue[i++][1] = "T";
}
- /*
- * OK, this isn't a local printer; add any remote options...
- */
+ if ((p->type & CUPS_PRINTER_DUPLEX))
+ {
+ keyvalue[i ][0] = "Duplex";
+ keyvalue[i++][1] = "T";
+ }
- ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
+ if ((p->type & CUPS_PRINTER_STAPLE))
+ {
+ keyvalue[i ][0] = "Staple";
+ keyvalue[i++][1] = "T";
+ }
- if (BrowseRemoteOptions)
+ if ((p->type & CUPS_PRINTER_COPIES))
{
- if (BrowseRemoteOptions[0] == '?')
- {
- /*
- * Override server-supplied options...
- */
+ keyvalue[i ][0] = "Copies";
+ keyvalue[i++][1] = "T";
+ }
- snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
- }
- else if (ipp_options)
- {
- /*
- * Combine the server and local options...
- */
+ if ((p->type & CUPS_PRINTER_COLLATE))
+ {
+ keyvalue[i ][0] = "Collate";
+ keyvalue[i++][1] = "T";
+ }
- snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
- BrowseRemoteOptions);
- }
- else
- {
- /*
- * Just use the local options...
- */
+ if ((p->type & CUPS_PRINTER_PUNCH))
+ {
+ keyvalue[i ][0] = "Punch";
+ keyvalue[i++][1] = "T";
+ }
- snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
- }
+ if ((p->type & CUPS_PRINTER_BIND))
+ {
+ keyvalue[i ][0] = "Bind";
+ keyvalue[i++][1] = "T";
+ }
- uri = finaluri;
+ if ((p->type & CUPS_PRINTER_SORT))
+ {
+ keyvalue[i ][0] = "Sort";
+ keyvalue[i++][1] = "T";
}
- else if (ipp_options)
+
+ keyvalue[i ][0] = "pdl";
+ keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
+
+ if (p->num_auth_info_required)
{
- /*
- * Just use the server-supplied options...
- */
+ char *air = air_str; /* Pointer into string */
- snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
- uri = finaluri;
+
+ for (j = 0; j < p->num_auth_info_required; j ++)
+ {
+ if (air >= (air_str + sizeof(air_str) - 2))
+ break;
+
+ if (j)
+ *air++ = ',';
+
+ strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str));
+ air += strlen(air);
+ }
+
+ keyvalue[i ][0] = "air";
+ keyvalue[i++][1] = air;
}
/*
- * See if we already have it listed in the Printers list, and add it if not...
+ * Then pack them into a proper txt record...
*/
- type |= CUPS_PRINTER_REMOTE;
- type &= ~CUPS_PRINTER_IMPLICIT;
- update = 0;
- hptr = strchr(host, '.');
- sptr = strchr(ServerName, '.');
+ return (dnssdPackTxtRecord(txt_len, keyvalue, i));
+}
- if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
- {
- /*
- * Strip the common domain name components...
- */
- while (hptr != NULL)
- {
- if (!strcasecmp(hptr, sptr))
- {
- *hptr = '\0';
- break;
- }
- else
- hptr = strchr(hptr + 1, '.');
- }
+/*
+ * 'dnssdComparePrinters()' - Compare the registered names of two printers.
+ */
+
+static int /* O - Result of comparison */
+dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */
+ cupsd_printer_t *b)/* I - Second printer */
+{
+ return (strcasecmp(a->reg_name, b->reg_name));
+}
+
+
+/*
+ * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
+ * printer.
+ */
+
+static void
+dnssdDeregisterPrinter(
+ cupsd_printer_t *p) /* I - Printer */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
+
+ /*
+ * Closing the socket deregisters the service
+ */
+
+ if (p->ipp_ref)
+ {
+ DNSServiceRefDeallocate(p->ipp_ref);
+ p->ipp_ref = NULL;
}
- if (type & CUPS_PRINTER_CLASS)
+ cupsArrayRemove(DNSSDPrinters, p);
+ cupsdClearString(&p->reg_name);
+
+ if (p->ipp_txt)
{
/*
- * Remote destination is a class...
+ * p->ipp_txt is malloc'd, not _cupsStrAlloc'd...
*/
- if (!strncmp(resource, "/classes/", 9))
- snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
- else
- return;
+ free(p->ipp_txt);
+ p->ipp_txt = NULL;
+ }
+}
- if (hptr && !*hptr)
- *hptr = '.'; /* Resource FQDN */
- if ((p = cupsdFindClass(name)) == NULL && BrowseShortNames)
- {
- if ((p = cupsdFindClass(resource + 9)) != NULL)
- {
- if (p->hostname && strcasecmp(p->hostname, host))
- {
- /*
- * Nope, this isn't the same host; if the hostname isn't the local host,
- * add it to the other class and then find a class using the full host
- * name...
- */
+/*
+ * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
+ * TXT record format.
+ */
- if (p->type & CUPS_PRINTER_REMOTE)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "Renamed remote class \"%s\" to \"%s@%s\"...",
- p->name, p->name, p->hostname);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
- "Class \'%s\' deleted by directory services.",
- p->name);
+static char * /* O - TXT record */
+dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
+ char *keyvalue[][2], /* I - Table of key value pairs */
+ int count) /* I - Items in table */
+{
+ int i; /* Looping var */
+ int length; /* Length of TXT record */
+ int length2; /* Length of value */
+ char *txtRecord; /* TXT record buffer */
+ char *cursor; /* Looping pointer */
- snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
- cupsdRenamePrinter(p, newname);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Class \'%s\' added by directory services.",
- p->name);
- }
+ /*
+ * Calculate the buffer size
+ */
- p = NULL;
- }
- else if (!p->hostname)
- {
- /*
- * Hostname not set, so this must be a cached remote printer
- * that was created for a pending print job...
- */
+ for (length = i = 0; i < count; i++)
+ length += 1 + strlen(keyvalue[i][0]) +
+ (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
- }
- }
- else
- {
- /*
- * Use the short name for this shared class.
- */
+ /*
+ * Allocate and fill it
+ */
- strlcpy(name, resource + 9, sizeof(name));
- }
- }
- else if (p && !p->hostname)
+ txtRecord = malloc(length);
+ if (txtRecord)
+ {
+ *txt_len = length;
+
+ for (cursor = txtRecord, i = 0; i < count; i++)
{
/*
- * Hostname not set, so this must be a cached remote printer
- * that was created for a pending print job...
+ * Drop in the p-string style length byte followed by the data
*/
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
+ length = strlen(keyvalue[i][0]);
+ length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
+
+ *cursor++ = (unsigned char)(length + length2);
+
+ memcpy(cursor, keyvalue[i][0], length);
+ cursor += length;
+
+ if (length2)
+ {
+ length2 --;
+ *cursor++ = '=';
+ memcpy(cursor, keyvalue[i][1], length2);
+ cursor += length2;
+ }
}
+ }
- if (!p)
- {
- /*
- * Class doesn't exist; add it...
- */
+ return (txtRecord);
+}
- p = cupsdAddClass(name);
- cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote class \"%s\"...", name);
+/*
+ * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
+ */
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Class \'%s\' added by directory services.", name);
+static void
+dnssdRegisterCallback(
+ DNSServiceRef sdRef, /* I - DNS Service reference */
+ DNSServiceFlags flags, /* I - Reserved for future use */
+ DNSServiceErrorType errorCode, /* I - Error code */
+ const char *name, /* I - Service name */
+ const char *regtype, /* I - Service type */
+ const char *domain, /* I - Domain. ".local" for now */
+ void *context) /* I - User-defined context */
+{
+ cupsd_printer_t *p = (cupsd_printer_t *)context;
+ /* Current printer */
- /*
- * Force the URI to point to the real server...
- */
- p->type = type & ~CUPS_PRINTER_REJECTING;
- p->accepting = 1;
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- cupsdSetString(&p->hostname, host);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s",
+ name, regtype, p ? p->name : "Web Interface");
- update = 1;
- }
+ if (errorCode)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNSServiceRegister failed with error %d", (int)errorCode);
+ return;
}
- else
+ else if (p && strcasecmp(name, p->reg_name))
{
- /*
- * Remote destination is a printer...
- */
-
- if (!strncmp(resource, "/printers/", 10))
- snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
- else
- return;
+ cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
+ name, p->name);
- if (hptr && !*hptr)
- *hptr = '.'; /* Resource FQDN */
+ cupsArrayRemove(DNSSDPrinters, p);
+ cupsdSetString(&p->reg_name, name);
+ cupsArrayAdd(DNSSDPrinters, p);
- if ((p = cupsdFindPrinter(name)) == NULL && BrowseShortNames)
- {
- if ((p = cupsdFindPrinter(resource + 10)) != NULL)
- {
- if (p->hostname && strcasecmp(p->hostname, host))
- {
- /*
- * Nope, this isn't the same host; if the hostname isn't the local host,
- * add it to the other printer and then find a printer using the full host
- * name...
- */
+ LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
+ }
+}
- if (p->type & CUPS_PRINTER_REMOTE)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "Renamed remote printer \"%s\" to \"%s@%s\"...",
- p->name, p->name, p->hostname);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
- "Printer \'%s\' deleted by directory services.",
- p->name);
- snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
- cupsdRenamePrinter(p, newname);
+/*
+ * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
+ * or update the broadcast contents.
+ */
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Printer \'%s\' added by directory services.",
- p->name);
- }
+static void
+dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
+{
+ DNSServiceErrorType se; /* dnssd errors */
+ char *ipp_txt, /* IPP TXT record buffer */
+ *printer_txt, /* LPD TXT record buffer */
+ name[1024], /* Service name */
+ *nameptr; /* Pointer into name */
+ int ipp_len, /* IPP TXT record length */
+ printer_len; /* LPD TXT record length */
+ char resource[1024]; /* Resource path for printer */
+ const char *regtype; /* Registration type */
+ const char *domain; /* Registration domain */
+ cupsd_location_t *location, /* Printer location */
+ *policy; /* Operation policy for Print-Job */
+ unsigned address[4]; /* INADDR_ANY address */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
+ !p->ipp_ref ? "new" : "update");
- p = NULL;
- }
- else if (!p->hostname)
- {
- /*
- * Hostname not set, so this must be a cached remote printer
- * that was created for a pending print job...
- */
+ /*
+ * If per-printer sharing was just disabled make sure we're not
+ * registered before returning.
+ */
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
- }
- }
- else
- {
- /*
- * Use the short name for this shared printer.
- */
+ if (!p->shared)
+ {
+ dnssdDeregisterPrinter(p);
+ return;
+ }
- strlcpy(name, resource + 10, sizeof(name));
- }
- }
- else if (p && !p->hostname)
- {
- /*
- * Hostname not set, so this must be a cached remote printer
- * that was created for a pending print job...
- */
+ /*
+ * The registered name takes the form of "<printer-info> @ <computer name>"...
+ */
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
- }
+ if (p->info && strlen(p->info) > 0)
+ {
+ if (DNSSDName)
+ snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDName);
+ else
+ strlcpy(name, p->info, sizeof(name));
+ }
+ else if (DNSSDName)
+ snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDName);
+ else
+ strlcpy(name, p->name, sizeof(name));
- if (!p)
- {
- /*
- * Printer doesn't exist; add it...
- */
+ /*
+ * If an existing printer was renamed, unregister it and start over...
+ */
- p = cupsdAddPrinter(name);
+ if (p->reg_name && strcmp(p->reg_name, name))
+ dnssdDeregisterPrinter(p);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Printer \'%s\' added by directory services.", name);
+ if (!p->reg_name)
+ {
+ cupsdSetString(&p->reg_name, name);
+ cupsArrayAdd(DNSSDPrinters, p);
+ }
- cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote printer \"%s\"...", name);
+ /*
+ * If 'Allow printing from the Internet' is enabled (i.e. from any address)
+ * let dnssd decide on the domain, otherwise restrict it to ".local".
+ */
- /*
- * Force the URI to point to the real server...
- */
+ if (p->type & CUPS_PRINTER_CLASS)
+ snprintf(resource, sizeof(resource), "/classes/%s", p->name);
+ else
+ snprintf(resource, sizeof(resource), "/printers/%s", p->name);
- p->type = type & ~CUPS_PRINTER_REJECTING;
- p->accepting = 1;
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
+ address[0] = address[1] = address[2] = address[3] = 0;
+ location = cupsdFindBest(resource, HTTP_POST);
+ policy = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
- update = 1;
- }
- }
+ if ((location && !cupsdCheckAccess(address, "", 0, location)) ||
+ (policy && !cupsdCheckAccess(address, "", 0, policy)))
+ domain = "local.";
+ else
+ domain = NULL;
/*
- * Update the state...
+ * Register IPP and (optionally) LPD...
*/
- p->state = state;
- p->browse_time = time(NULL);
+ ipp_len = 0; /* anti-compiler-warning-code */
+ ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
- if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
- attrs)) != NULL)
+ if (!p->ipp_ref)
{
/*
- * Grab the lease-duration for the browse data; anything less then 1
- * second or more than 1 week gets the default BrowseTimeout...
+ * Initial registration. Use the _fax subtype for fax queues...
*/
- i = atoi(lease_duration);
- if (i < 1 || i > 604800)
- i = BrowseTimeout;
+ regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" :
+ "_ipp._tcp,_cups";
- p->browse_expire = p->browse_time + i;
- }
- else
- p->browse_expire = p->browse_time + BrowseTimeout;
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Registering DNS-SD printer %s with name \"%s\", "
+ "type \"%s\", and domain \"%s\"", p->name, name, regtype,
+ domain ? domain : "(null)");
- if (type & CUPS_PRINTER_REJECTING)
- {
- type &= ~CUPS_PRINTER_REJECTING;
+ /*
+ * Register the queue, dropping characters as needed until we succeed...
+ */
- if (p->accepting)
+ nameptr = name + strlen(name);
+
+ do
{
- update = 1;
- p->accepting = 0;
+ p->ipp_ref = DNSSDRef;
+ if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection,
+ 0, name, regtype, domain, NULL,
+ htons(DNSSDPort), ipp_len, ipp_txt,
+ dnssdRegisterCallback,
+ p)) == kDNSServiceErr_BadParam)
+ {
+ /*
+ * Name is too long, drop trailing characters, taking into account
+ * UTF-8 encoding...
+ */
+
+ nameptr --;
+
+ while (nameptr > name && (*nameptr & 0xc0) == 0x80)
+ nameptr --;
+
+ if (nameptr > name)
+ *nameptr = '\0';
+ }
}
+ while (se == kDNSServiceErr_BadParam && nameptr > name);
+
+ if (se == kDNSServiceErr_NoError)
+ {
+ p->ipp_txt = ipp_txt;
+ p->ipp_len = ipp_len;
+ ipp_txt = NULL;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "DNS-SD IPP registration of \"%s\" failed: %d",
+ p->name, se);
}
- else if (!p->accepting)
+ else if (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len))
{
- update = 1;
- p->accepting = 1;
- }
+ /*
+ * Update the existing registration...
+ */
- if (p->type != type)
- {
- p->type = type;
- update = 1;
- }
+ /* A TTL of 0 means use record's original value (Radar 3176248) */
+ DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt, 0);
- if (location && (!p->location || strcmp(p->location, location)))
- {
- cupsdSetString(&p->location, location);
- update = 1;
- }
+ if (p->ipp_txt)
+ free(p->ipp_txt);
- if (info && (!p->info || strcmp(p->info, info)))
- {
- cupsdSetString(&p->info, info);
- update = 1;
+ p->ipp_txt = ipp_txt;
+ p->ipp_len = ipp_len;
+ ipp_txt = NULL;
}
- if (!make_model || !make_model[0])
- {
- if (type & CUPS_PRINTER_CLASS)
- snprintf(local_make_model, sizeof(local_make_model),
- "Remote Class on %s", host);
- else
- snprintf(local_make_model, sizeof(local_make_model),
- "Remote Printer on %s", host);
- }
- else
- snprintf(local_make_model, sizeof(local_make_model),
- "%s on %s", make_model, host);
+ if (ipp_txt)
+ free(ipp_txt);
- if (!p->make_model || strcmp(p->make_model, local_make_model))
+ if (BrowseLocalProtocols & BROWSE_LPD)
{
- cupsdSetString(&p->make_model, local_make_model);
- update = 1;
- }
+ printer_len = 0; /* anti-compiler-warning-code */
+ printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1);
- if (p->num_options)
- {
- if (!update && !(type & CUPS_PRINTER_DELETE))
+ if (!p->printer_ref)
{
/*
- * See if we need to update the attributes...
+ * Initial registration...
*/
- if (p->num_options != num_attrs)
- update = 1;
- else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Registering DNS-SD printer %s with name \"%s\", "
+ "type \"_printer._tcp\", and domain \"%s\"", p->name,
+ name, domain ? domain : "(null)");
+
+ p->printer_ref = DNSSDRef;
+ if ((se = DNSServiceRegister(&p->printer_ref,
+ kDNSServiceFlagsShareConnection,
+ 0, name, "_printer._tcp", domain, NULL,
+ htons(515), printer_len, printer_txt,
+ dnssdRegisterCallback,
+ p)) == kDNSServiceErr_NoError)
{
- for (i = 0; i < num_attrs; i ++)
- if (strcmp(attrs[i].name, p->options[i].name) ||
- (!attrs[i].value != !p->options[i].value) ||
- (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
- {
- update = 1;
- break;
- }
+ p->printer_txt = printer_txt;
+ p->printer_len = printer_len;
+ printer_txt = NULL;
}
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "DNS-SD LPD registration of \"%s\" failed: %d",
+ p->name, se);
}
+ else if (printer_len != p->printer_len ||
+ memcmp(printer_txt, p->printer_txt, printer_len))
+ {
+ /*
+ * Update the existing registration...
+ */
- /*
- * Free the old options...
- */
-
- cupsFreeOptions(p->num_options, p->options);
- }
+ /* A TTL of 0 means use record's original value (Radar 3176248) */
+ DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len,
+ printer_txt, 0);
- p->num_options = num_attrs;
- p->options = attrs;
+ if (p->printer_txt)
+ free(p->printer_txt);
- if (type & CUPS_PRINTER_DELETE)
- {
- cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
- "%s \'%s\' deleted by directory services.",
- (type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", p->name);
+ p->printer_txt = printer_txt;
+ p->printer_len = printer_len;
+ printer_txt = NULL;
+ }
- cupsdExpireSubscriptions(p, NULL);
-
- cupsdDeletePrinter(p, 1);
- cupsdUpdateImplicitClasses();
- }
- else if (update)
- {
- cupsdSetPrinterAttrs(p);
- cupsdUpdateImplicitClasses();
+ if (printer_txt)
+ free(printer_txt);
}
+}
- /*
- * See if we have a default printer... If not, make the first network
- * default printer the default.
- */
-
- if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
- {
- /*
- * Find the first network default printer and use it...
- */
-
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
- p;
- p = (cupsd_printer_t *)cupsArrayNext(Printers))
- if (p->type & CUPS_PRINTER_DEFAULT)
- {
- DefaultPrinter = p;
- break;
- }
- }
- /*
- * Do auto-classing if needed...
- */
+/*
+ * 'dnssdUpdate()' - Handle DNS-SD queries.
+ */
- process_implicit_classes();
+static void
+dnssdUpdate(void)
+{
+ DNSServiceErrorType sdErr; /* Service discovery error */
- /*
- * Update the printcap file...
- */
- cupsdWritePrintcap();
+ if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNS Service Discovery registration error %d!",
+ sdErr);
}
+#endif /* HAVE_DNSSD */
+#ifdef __APPLE__
/*
- * 'process_implicit_classes()' - Create/update implicit classes as needed.
+ * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
*/
-static void
-process_implicit_classes(void)
+static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
+get_hostconfig(const char *name) /* I - Name of service */
{
- int i; /* Looping var */
- int update; /* Update printer attributes? */
- char name[IPP_MAX_NAME], /* Name of printer */
- *hptr; /* Pointer into hostname */
- cupsd_printer_t *p, /* Printer information */
- *pclass, /* Printer class */
- *first; /* First printer in class */
- int offset, /* Offset of name */
- len; /* Length of name */
+ cups_file_t *fp; /* Hostconfig file */
+ char line[1024], /* Line from file */
+ *ptr; /* Pointer to value */
+ int state = 1; /* State of service */
- if (!ImplicitClasses || !Printers)
- return;
-
/*
- * Loop through all available printers and create classes as needed...
+ * Try opening the /etc/hostconfig file; if we can't open it, assume that
+ * the service is enabled/auto.
*/
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
- update = 0, pclass = NULL, first = NULL;
- p != NULL;
- p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
{
/*
- * Skip implicit classes...
+ * Read lines from the file until we find the service...
*/
- if (p->type & CUPS_PRINTER_IMPLICIT)
+ while (cupsFileGets(fp, line, sizeof(line)))
{
- len = 0;
- continue;
- }
+ if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
+ continue;
- /*
- * If len == 0, get the length of this printer name up to the "@"
- * sign (if any).
- */
+ *ptr++ = '\0';
- cupsArraySave(Printers);
-
- if (len > 0 &&
- !strncasecmp(p->name, name + offset, len) &&
- (p->name[len] == '\0' || p->name[len] == '@'))
- {
- /*
- * We have more than one printer with the same name; see if
- * we have a class, and if this printer is a member...
- */
-
- if (pclass && strcasecmp(pclass->name, name))
- {
- if (update)
- cupsdSetPrinterAttrs(pclass);
-
- update = 0;
- pclass = NULL;
- }
-
- if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
+ if (!strcasecmp(line, name))
{
/*
- * Need to add the class...
+ * Found the service, see if it is set to "-NO-"...
*/
- pclass = cupsdAddPrinter(name);
- cupsArrayAdd(ImplicitPrinters, pclass);
-
- pclass->type |= CUPS_PRINTER_IMPLICIT;
- pclass->accepting = 1;
- pclass->state = IPP_PRINTER_IDLE;
-
- cupsdSetString(&pclass->location, p->location);
- cupsdSetString(&pclass->info, p->info);
-
- update = 1;
-
- cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
- name);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Implicit class \'%s\' added by directory services.",
- name);
+ if (!strncasecmp(ptr, "-NO-", 4))
+ state = 0;
+ break;
}
+ }
- if (first != NULL)
- {
- for (i = 0; i < pclass->num_printers; i ++)
- if (pclass->printers[i] == first)
- break;
+ cupsFileClose(fp);
+ }
- if (i >= pclass->num_printers)
- {
- first->in_implicit_class = 1;
- cupsdAddPrinterToClass(pclass, first);
- }
+ return (state);
+}
+#endif /* __APPLE__ */
- first = NULL;
- }
- for (i = 0; i < pclass->num_printers; i ++)
- if (pclass->printers[i] == p)
- break;
+/*
+ * 'is_local_queue()' - Determine whether the URI points at a local queue.
+ */
- if (i >= pclass->num_printers)
- {
- p->in_implicit_class = 1;
- cupsdAddPrinterToClass(pclass, p);
- update = 1;
- }
- }
- else
- {
- /*
- * First time around; just get name length and mark it as first
- * in the list...
- */
+static int /* O - 1 = local, 0 = remote, -1 = bad URI */
+is_local_queue(const char *uri, /* I - Printer URI */
+ char *host, /* O - Host string */
+ int hostlen, /* I - Length of host buffer */
+ char *resource, /* O - Resource string */
+ int resourcelen) /* I - Length of resource buffer */
+{
+ char scheme[32], /* Scheme portion of URI */
+ username[HTTP_MAX_URI]; /* Username portion of URI */
+ int port; /* Port portion of URI */
+ cupsd_netif_t *iface; /* Network interface */
- if ((hptr = strchr(p->name, '@')) != NULL)
- len = hptr - p->name;
- else
- len = strlen(p->name);
- strncpy(name, p->name, len);
- name[len] = '\0';
- offset = 0;
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
- if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
- !(first->type & CUPS_PRINTER_IMPLICIT))
- {
- /*
- * Can't use same name as a local printer; add "Any" to the
- * front of the name, unless we have explicitly disabled
- * the "ImplicitAnyClasses"...
- */
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
+ username, sizeof(username), host, hostlen, &port,
+ resource, resourcelen) < HTTP_URI_OK)
+ return (-1);
- if (ImplicitAnyClasses && len < (sizeof(name) - 4))
- {
- /*
- * Add "Any" to the class name...
- */
+ DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
- strcpy(name, "Any");
- strncpy(name + 3, p->name, len);
- name[len + 3] = '\0';
- offset = 3;
- }
- else
- {
- /*
- * Don't create an implicit class if we have a local printer
- * with the same name...
- */
+ /*
+ * Check for local server addresses...
+ */
- len = 0;
- cupsArrayRestore(Printers);
- continue;
- }
- }
+ if (!strcasecmp(host, ServerName) && port == LocalPort)
+ return (1);
- first = p;
- }
+ cupsdNetIFUpdate();
- cupsArrayRestore(Printers);
- }
+ for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ iface;
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ if (!strcasecmp(host, iface->hostname) && port == iface->port)
+ return (1);
/*
- * Update the last printer class as needed...
+ * If we get here, the printer is remote...
*/
- if (pclass && update)
- cupsdSetPrinterAttrs(pclass);
+ return (0);
}
/*
- * 'send_cups_browse()' - Send new browsing information using the CUPS
- * protocol.
+ * 'process_browse_data()' - Process new browse data.
*/
static void
-send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */
+process_browse_data(
+ const char *uri, /* I - URI of printer/class */
+ const char *host, /* I - Hostname */
+ const char *resource, /* I - Resource path */
+ cups_ptype_t type, /* I - Printer type */
+ ipp_pstate_t state, /* I - Printer state */
+ const char *location, /* I - Printer location */
+ const char *info, /* I - Printer information */
+ const char *make_model, /* I - Printer make and model */
+ int num_attrs, /* I - Number of attributes */
+ cups_option_t *attrs) /* I - Attributes */
{
- int i; /* Looping var */
- cups_ptype_t type; /* Printer type */
- cupsd_dirsvc_addr_t *b; /* Browse address */
- int bytes; /* Length of packet */
- char packet[1453], /* Browse data packet */
- uri[1024], /* Printer URI */
- location[1024], /* printer-location */
- info[1024], /* printer-info */
- make_model[1024];
- /* printer-make-and-model */
- cupsd_netif_t *iface; /* Network interface */
+ int i; /* Looping var */
+ int update; /* Update printer attributes? */
+ char finaluri[HTTP_MAX_URI], /* Final URI for printer */
+ name[IPP_MAX_NAME], /* Name of printer */
+ newname[IPP_MAX_NAME], /* New name of printer */
+ *hptr, /* Pointer into hostname */
+ *sptr; /* Pointer into ServerName */
+ char local_make_model[IPP_MAX_NAME];
+ /* Local make and model */
+ cupsd_printer_t *p; /* Printer information */
+ const char *ipp_options, /* ipp-options value */
+ *lease_duration; /* lease-duration value */
/*
- * Figure out the printer type value...
+ * Determine if the URI contains any illegal characters in it...
*/
- type = p->type | CUPS_PRINTER_REMOTE;
-
- if (!p->accepting)
- type |= CUPS_PRINTER_REJECTING;
+ if (strncmp(uri, "ipp://", 6) || !host[0] ||
+ (strncmp(resource, "/printers/", 10) &&
+ strncmp(resource, "/classes/", 9)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "process_browse_data: Bad printer URI in browse data: %s",
+ uri);
+ return;
+ }
- if (p == DefaultPrinter)
- type |= CUPS_PRINTER_DEFAULT;
+ if (strchr(resource, '?') ||
+ (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
+ (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "process_browse_data: Bad resource in browse data: %s",
+ resource);
+ return;
+ }
/*
- * Remove quotes from printer-info, printer-location, and
- * printer-make-and-model attributes...
+ * OK, this isn't a local printer; add any remote options...
*/
- dequote(location, p->location, sizeof(location));
- dequote(info, p->info, sizeof(info));
+ ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
- if (p->make_model)
- dequote(make_model, p->make_model, sizeof(make_model));
- else if (p->type & CUPS_PRINTER_CLASS)
+ if (BrowseRemoteOptions)
{
- if (p->num_printers > 0 && p->printers[0]->make_model)
- strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model));
- else
- strlcpy(make_model, "Local Printer Class", sizeof(make_model));
- }
- else if (p->raw)
- strlcpy(make_model, "Local Raw Printer", sizeof(make_model));
- else
- strlcpy(make_model, "Local System V Printer", sizeof(make_model));
+ if (BrowseRemoteOptions[0] == '?')
+ {
+ /*
+ * Override server-supplied options...
+ */
- /*
- * Send a packet to each browse address...
- */
+ snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
+ }
+ else if (ipp_options)
+ {
+ /*
+ * Combine the server and local options...
+ */
- for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
- if (b->iface[0])
+ snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
+ BrowseRemoteOptions);
+ }
+ else
{
/*
- * Send the browse packet to one or more interfaces...
+ * Just use the local options...
*/
- if (!strcmp(b->iface, "*"))
- {
+ snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
+ }
+
+ uri = finaluri;
+ }
+ else if (ipp_options)
+ {
+ /*
+ * Just use the server-supplied options...
+ */
+
+ snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
+ uri = finaluri;
+ }
+
+ /*
+ * See if we already have it listed in the Printers list, and add it if not...
+ */
+
+ type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
+ type &= ~CUPS_PRINTER_IMPLICIT;
+ update = 0;
+ hptr = strchr(host, '.');
+ sptr = strchr(ServerName, '.');
+
+ if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
+ {
+ /*
+ * Strip the common domain name components...
+ */
+
+ while (hptr != NULL)
+ {
+ if (!strcasecmp(hptr, sptr))
+ {
+ *hptr = '\0';
+ break;
+ }
+ else
+ hptr = strchr(hptr + 1, '.');
+ }
+ }
+
+ if (type & CUPS_PRINTER_CLASS)
+ {
+ /*
+ * Remote destination is a class...
+ */
+
+ if (!strncmp(resource, "/classes/", 9))
+ snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
+ else
+ return;
+
+ if (hptr && !*hptr)
+ *hptr = '.'; /* Resource FQDN */
+
+ if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
+ {
+ if ((p = cupsdFindDest(resource + 9)) != NULL)
+ {
+ if (p->hostname && strcasecmp(p->hostname, host))
+ {
+ /*
+ * Nope, this isn't the same host; if the hostname isn't the local host,
+ * add it to the other class and then find a class using the full host
+ * name...
+ */
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Renamed remote class \"%s\" to \"%s@%s\"...",
+ p->name, p->name, p->hostname);
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
+ "Class \'%s\' deleted by directory services.",
+ p->name);
+
+ snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
+ cupsdRenamePrinter(p, newname);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "Class \'%s\' added by directory services.",
+ p->name);
+ }
+
+ p = NULL;
+ }
+ else if (!p->hostname)
+ {
+ /*
+ * Hostname not set, so this must be a cached remote printer
+ * that was created for a pending print job...
+ */
+
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ update = 1;
+ }
+ }
+ else
+ {
/*
- * Send to all local interfaces...
+ * Use the short name for this shared class.
*/
- cupsdNetIFUpdate();
+ strlcpy(name, resource + 9, sizeof(name));
+ }
+ }
+ else if (p && !p->hostname)
+ {
+ /*
+ * Hostname not set, so this must be a cached remote printer
+ * that was created for a pending print job...
+ */
- for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
- iface;
- iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ update = 1;
+ }
+
+ if (!p)
+ {
+ /*
+ * Class doesn't exist; add it...
+ */
+
+ p = cupsdAddClass(name);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote class \"%s\"...", name);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "Class \'%s\' added by directory services.", name);
+
+ /*
+ * Force the URI to point to the real server...
+ */
+
+ p->type = type & ~CUPS_PRINTER_REJECTING;
+ p->accepting = 1;
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ cupsdSetString(&p->hostname, host);
+
+ update = 1;
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ }
+ }
+ else
+ {
+ /*
+ * Remote destination is a printer...
+ */
+
+ if (!strncmp(resource, "/printers/", 10))
+ snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
+ else
+ return;
+
+ if (hptr && !*hptr)
+ *hptr = '.'; /* Resource FQDN */
+
+ if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
+ {
+ if ((p = cupsdFindDest(resource + 10)) != NULL)
+ {
+ if (p->hostname && strcasecmp(p->hostname, host))
{
/*
- * Only send to local, IPv4 interfaces...
+ * Nope, this isn't the same host; if the hostname isn't the local host,
+ * add it to the other printer and then find a printer using the full host
+ * name...
*/
- if (!iface->is_local || !iface->port ||
- iface->address.addr.sa_family != AF_INET)
- continue;
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Renamed remote printer \"%s\" to \"%s@%s\"...",
+ p->name, p->name, p->hostname);
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
+ "Printer \'%s\' deleted by directory services.",
+ p->name);
- httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
- iface->hostname, iface->port,
- (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
- "/printers/%s",
- p->name);
- snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
- type, p->state, uri, location, info, make_model,
- p->browse_attrs ? p->browse_attrs : "");
+ snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
+ cupsdRenamePrinter(p, newname);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "Printer \'%s\' added by directory services.",
+ p->name);
+ }
+
+ p = NULL;
+ }
+ else if (!p->hostname)
+ {
+ /*
+ * Hostname not set, so this must be a cached remote printer
+ * that was created for a pending print job...
+ */
+
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ update = 1;
+ }
+ }
+ else
+ {
+ /*
+ * Use the short name for this shared printer.
+ */
+
+ strlcpy(name, resource + 10, sizeof(name));
+ }
+ }
+ else if (p && !p->hostname)
+ {
+ /*
+ * Hostname not set, so this must be a cached remote printer
+ * that was created for a pending print job...
+ */
+
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ update = 1;
+ }
+
+ if (!p)
+ {
+ /*
+ * Printer doesn't exist; add it...
+ */
+
+ p = cupsdAddPrinter(name);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "Printer \'%s\' added by directory services.", name);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote printer \"%s\"...", name);
+
+ /*
+ * Force the URI to point to the real server...
+ */
+
+ p->type = type & ~CUPS_PRINTER_REJECTING;
+ p->accepting = 1;
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+
+ update = 1;
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ }
+ }
+
+ /*
+ * Update the state...
+ */
+
+ p->state = state;
+ p->browse_time = time(NULL);
+
+ if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
+ attrs)) != NULL)
+ {
+ /*
+ * Grab the lease-duration for the browse data; anything less then 1
+ * second or more than 1 week gets the default BrowseTimeout...
+ */
+
+ i = atoi(lease_duration);
+ if (i < 1 || i > 604800)
+ i = BrowseTimeout;
+
+ p->browse_expire = p->browse_time + i;
+ }
+ else
+ p->browse_expire = p->browse_time + BrowseTimeout;
+
+ if (type & CUPS_PRINTER_REJECTING)
+ {
+ type &= ~CUPS_PRINTER_REJECTING;
+
+ if (p->accepting)
+ {
+ update = 1;
+ p->accepting = 0;
+ }
+ }
+ else if (!p->accepting)
+ {
+ update = 1;
+ p->accepting = 1;
+ }
+
+ if (p->type != type)
+ {
+ p->type = type;
+ update = 1;
+ }
+
+ if (location && (!p->location || strcmp(p->location, location)))
+ {
+ cupsdSetString(&p->location, location);
+ update = 1;
+ }
+
+ if (info && (!p->info || strcmp(p->info, info)))
+ {
+ cupsdSetString(&p->info, info);
+ update = 1;
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ }
+
+ if (!make_model || !make_model[0])
+ {
+ if (type & CUPS_PRINTER_CLASS)
+ snprintf(local_make_model, sizeof(local_make_model),
+ "Remote Class on %s", host);
+ else
+ snprintf(local_make_model, sizeof(local_make_model),
+ "Remote Printer on %s", host);
+ }
+ else
+ snprintf(local_make_model, sizeof(local_make_model),
+ "%s on %s", make_model, host);
+
+ if (!p->make_model || strcmp(p->make_model, local_make_model))
+ {
+ cupsdSetString(&p->make_model, local_make_model);
+ update = 1;
+ }
+
+ if (p->num_options)
+ {
+ if (!update && !(type & CUPS_PRINTER_DELETE))
+ {
+ /*
+ * See if we need to update the attributes...
+ */
+
+ if (p->num_options != num_attrs)
+ update = 1;
+ else
+ {
+ for (i = 0; i < num_attrs; i ++)
+ if (strcmp(attrs[i].name, p->options[i].name) ||
+ (!attrs[i].value != !p->options[i].value) ||
+ (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
+ {
+ update = 1;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Free the old options...
+ */
+
+ cupsFreeOptions(p->num_options, p->options);
+ }
+
+ p->num_options = num_attrs;
+ p->options = attrs;
+
+ if (type & CUPS_PRINTER_DELETE)
+ {
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
+ "%s \'%s\' deleted by directory services.",
+ (type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", p->name);
+
+ cupsdExpireSubscriptions(p, NULL);
+
+ cupsdDeletePrinter(p, 1);
+ cupsdUpdateImplicitClasses();
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ }
+ else if (update)
+ {
+ cupsdSetPrinterAttrs(p);
+ cupsdUpdateImplicitClasses();
+ }
+
+ /*
+ * See if we have a default printer... If not, make the first network
+ * default printer the default.
+ */
+
+ if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
+ {
+ /*
+ * Find the first network default printer and use it...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (p->type & CUPS_PRINTER_DEFAULT)
+ {
+ DefaultPrinter = p;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ break;
+ }
+ }
+
+ /*
+ * Do auto-classing if needed...
+ */
+
+ process_implicit_classes();
+}
+
+
+/*
+ * 'process_implicit_classes()' - Create/update implicit classes as needed.
+ */
+
+static void
+process_implicit_classes(void)
+{
+ int i; /* Looping var */
+ int update; /* Update printer attributes? */
+ char name[IPP_MAX_NAME], /* Name of printer */
+ *hptr; /* Pointer into hostname */
+ cupsd_printer_t *p, /* Printer information */
+ *pclass, /* Printer class */
+ *first; /* First printer in class */
+ int offset, /* Offset of name */
+ len; /* Length of name */
+
+
+ if (!ImplicitClasses || !Printers)
+ return;
+
+ /*
+ * Loop through all available printers and create classes as needed...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
+ update = 0, pclass = NULL, first = NULL;
+ p != NULL;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ /*
+ * Skip implicit classes...
+ */
+
+ if (p->type & CUPS_PRINTER_IMPLICIT)
+ {
+ len = 0;
+ continue;
+ }
+
+ /*
+ * If len == 0, get the length of this printer name up to the "@"
+ * sign (if any).
+ */
+
+ cupsArraySave(Printers);
+
+ if (len > 0 &&
+ !strncasecmp(p->name, name + offset, len) &&
+ (p->name[len] == '\0' || p->name[len] == '@'))
+ {
+ /*
+ * We have more than one printer with the same name; see if
+ * we have a class, and if this printer is a member...
+ */
+
+ if (pclass && strcasecmp(pclass->name, name))
+ {
+ if (update)
+ cupsdSetPrinterAttrs(pclass);
+
+ update = 0;
+ pclass = NULL;
+ }
+
+ if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
+ {
+ /*
+ * Need to add the class...
+ */
+
+ pclass = cupsdAddPrinter(name);
+ cupsArrayAdd(ImplicitPrinters, pclass);
+
+ pclass->type |= CUPS_PRINTER_IMPLICIT;
+ pclass->accepting = 1;
+ pclass->state = IPP_PRINTER_IDLE;
+
+ cupsdSetString(&pclass->location, p->location);
+ cupsdSetString(&pclass->info, p->info);
+
+ cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
+ cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
+
+ update = 1;
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
+ name);
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "Implicit class \'%s\' added by directory services.",
+ name);
+ }
+
+ if (first != NULL)
+ {
+ for (i = 0; i < pclass->num_printers; i ++)
+ if (pclass->printers[i] == first)
+ break;
+
+ if (i >= pclass->num_printers)
+ {
+ first->in_implicit_class = 1;
+ cupsdAddPrinterToClass(pclass, first);
+ }
+
+ first = NULL;
+ }
+
+ for (i = 0; i < pclass->num_printers; i ++)
+ if (pclass->printers[i] == p)
+ break;
+
+ if (i >= pclass->num_printers)
+ {
+ p->in_implicit_class = 1;
+ cupsdAddPrinterToClass(pclass, p);
+ update = 1;
+ }
+ }
+ else
+ {
+ /*
+ * First time around; just get name length and mark it as first
+ * in the list...
+ */
+
+ if ((hptr = strchr(p->name, '@')) != NULL)
+ len = hptr - p->name;
+ else
+ len = strlen(p->name);
+
+ strncpy(name, p->name, len);
+ name[len] = '\0';
+ offset = 0;
+
+ if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
+ !(first->type & CUPS_PRINTER_IMPLICIT))
+ {
+ /*
+ * Can't use same name as a local printer; add "Any" to the
+ * front of the name, unless we have explicitly disabled
+ * the "ImplicitAnyClasses"...
+ */
+
+ if (ImplicitAnyClasses && len < (sizeof(name) - 4))
+ {
+ /*
+ * Add "Any" to the class name...
+ */
+
+ strcpy(name, "Any");
+ strncpy(name + 3, p->name, len);
+ name[len + 3] = '\0';
+ offset = 3;
+ }
+ else
+ {
+ /*
+ * Don't create an implicit class if we have a local printer
+ * with the same name...
+ */
+
+ len = 0;
+ cupsArrayRestore(Printers);
+ continue;
+ }
+ }
+
+ first = p;
+ }
+
+ cupsArrayRestore(Printers);
+ }
+
+ /*
+ * Update the last printer class as needed...
+ */
+
+ if (pclass && update)
+ cupsdSetPrinterAttrs(pclass);
+}
+
+
+/*
+ * 'send_cups_browse()' - Send new browsing information using the CUPS
+ * protocol.
+ */
+
+static void
+send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */
+{
+ int i; /* Looping var */
+ cups_ptype_t type; /* Printer type */
+ cupsd_dirsvc_addr_t *b; /* Browse address */
+ int bytes; /* Length of packet */
+ char packet[1453], /* Browse data packet */
+ uri[1024], /* Printer URI */
+ location[1024], /* printer-location */
+ info[1024], /* printer-info */
+ make_model[1024];
+ /* printer-make-and-model */
+ cupsd_netif_t *iface; /* Network interface */
+
+
+ /*
+ * Figure out the printer type value...
+ */
+
+ type = p->type | CUPS_PRINTER_REMOTE;
+
+ if (!p->accepting)
+ type |= CUPS_PRINTER_REJECTING;
+
+ if (p == DefaultPrinter)
+ type |= CUPS_PRINTER_DEFAULT;
+
+ /*
+ * Remove quotes from printer-info, printer-location, and
+ * printer-make-and-model attributes...
+ */
+
+ dequote(location, p->location, sizeof(location));
+ dequote(info, p->info, sizeof(info));
+
+ if (p->make_model)
+ dequote(make_model, p->make_model, sizeof(make_model));
+ else if (p->type & CUPS_PRINTER_CLASS)
+ {
+ if (p->num_printers > 0 && p->printers[0]->make_model)
+ strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model));
+ else
+ strlcpy(make_model, "Local Printer Class", sizeof(make_model));
+ }
+ else if (p->raw)
+ strlcpy(make_model, "Local Raw Printer", sizeof(make_model));
+ else
+ strlcpy(make_model, "Local System V Printer", sizeof(make_model));
+
+ /*
+ * Send a packet to each browse address...
+ */
+
+ for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
+ if (b->iface[0])
+ {
+ /*
+ * Send the browse packet to one or more interfaces...
+ */
+
+ if (!strcmp(b->iface, "*"))
+ {
+ /*
+ * Send to all local interfaces...
+ */
+
+ cupsdNetIFUpdate();
+
+ for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ iface;
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ {
+ /*
+ * Only send to local, IPv4 interfaces...
+ */
+
+ if (!iface->is_local || !iface->port ||
+ iface->address.addr.sa_family != AF_INET)
+ continue;
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ iface->hostname, iface->port,
+ (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
+ "/printers/%s",
+ p->name);
+ snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
+ type, p->state, uri, location, info, make_model,
+ p->browse_attrs ? p->browse_attrs : "");
+
+ bytes = strlen(packet);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
+ iface->name, packet);
+
+ iface->broadcast.ipv4.sin_port = htons(BrowsePort);
+
+ sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(iface->broadcast),
+ httpAddrLength(&(iface->broadcast)));
+ }
+ }
+ else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
+ {
+ /*
+ * Send to the named interface using the IPv4 address...
+ */
+
+ while (iface)
+ if (strcmp(b->iface, iface->name))
+ {
+ iface = NULL;
+ break;
+ }
+ else if (iface->address.addr.sa_family == AF_INET && iface->port)
+ break;
+ else
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
+
+ if (iface)
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ iface->hostname, iface->port,
+ (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
+ "/printers/%s",
+ p->name);
+ snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
+ type, p->state, uri, location, info, make_model,
+ p->browse_attrs ? p->browse_attrs : "");
+
+ bytes = strlen(packet);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
+ iface->name, packet);
+
+ iface->broadcast.ipv4.sin_port = htons(BrowsePort);
+
+ sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(iface->broadcast),
+ httpAddrLength(&(iface->broadcast)));
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Send the browse packet to the indicated address using
+ * the default server name...
+ */
+
+ snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
+ type, p->state, p->uri, location, info, make_model,
+ p->browse_attrs ? p->browse_attrs : "");
+
+ bytes = strlen(packet);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
+
+ if (sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(b->to),
+ httpAddrLength(&(b->to))) <= 0)
+ {
+ /*
+ * Unable to send browse packet, so remove this address from the
+ * list...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdSendBrowseList: sendto failed for browser "
+ "%d - %s.",
+ (int)(b - Browsers + 1), strerror(errno));
+
+ if (i > 1)
+ memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
+
+ b --;
+ NumBrowsers --;
+ }
+ }
+}
+
+
+#ifdef HAVE_OPENLDAP
+/*
+ * 'send_ldap_browse()' - Send LDAP printer registrations.
+ */
+
+static void
+send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */
+{
+ int i; /* Looping var... */
+ LDAPMod mods[7]; /* The 7 attributes we will be adding */
+ LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
+ LDAPMessage *res; /* Search result token */
+ char *cn_value[2], /* Change records */
+ *uri[2],
+ *info[2],
+ *location[2],
+ *make_model[2],
+ *type[2],
+ typestring[255], /* String to hold printer-type */
+ filter[256], /* Search filter for possible UPDATEs */
+ dn[1024]; /* DN of the printer we are adding */
+ int rc; /* LDAP status */
+ static const char * const objectClass_values[] =
+ { /* The 3 objectClass's we use in */
+ "top", /* our LDAP entries */
+ "device",
+ "cupsPrinter",
+ NULL
+ };
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s", p->name);
+
+ /*
+ * Everything in ldap is ** so we fudge around it...
+ */
+
+ sprintf(typestring, "%u", p->type);
+
+ cn_value[0] = p->name;
+ cn_value[1] = NULL;
+ info[0] = p->info ? p->info : "Unknown";
+ info[1] = NULL;
+ location[0] = p->location ? p->location : "Unknown";
+ location[1] = NULL;
+ make_model[0] = p->make_model ? p->make_model : "Unknown";
+ make_model[1] = NULL;
+ type[0] = typestring;
+ type[1] = NULL;
+ uri[0] = p->uri;
+ uri[1] = NULL;
+
+ snprintf(filter, sizeof(filter),
+ "(&(objectclass=cupsPrinter)(printerURI=%s))", p->uri);
+
+ ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
+ filter, (char **)ldap_attrs, 0, &res);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: Searching \"%s\"",
+ filter);
+
+ mods[0].mod_type = "cn";
+ mods[0].mod_values = cn_value;
+ mods[1].mod_type = "printerDescription";
+ mods[1].mod_values = info;
+ mods[2].mod_type = "printerURI";
+ mods[2].mod_values = uri;
+ mods[3].mod_type = "printerLocation";
+ mods[3].mod_values = location;
+ mods[4].mod_type = "printerMakeAndModel";
+ mods[4].mod_values = make_model;
+ mods[5].mod_type = "printerType";
+ mods[5].mod_values = type;
+ mods[6].mod_type = "objectClass";
+ mods[6].mod_values = (char **)objectClass_values;
+
+ snprintf(dn, sizeof(dn), "cn=%s,ou=printers,%s", p->name, BrowseLDAPDN);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
+
+ if (ldap_count_entries(BrowseLDAPHandle, res) > 0)
+ {
+ /*
+ * Printer has already been registered, modify the current
+ * registration...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: Replacing entry...");
+
+ for (i = 0; i < 7; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_REPLACE;
+ }
+ pmods[i] = NULL;
+
+ if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP modify for %s failed with status %d: %s",
+ p->name, rc, ldap_err2string(rc));
+ }
+ else
+ {
+ /*
+ * Printer has never been registered, add the current
+ * registration...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: Adding entry...");
+
+ for (i = 0; i < 7; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_ADD;
+ }
+ pmods[i] = NULL;
+
+ if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP add for %s failed with status %d: %s",
+ p->name, rc, ldap_err2string(rc));
+ }
+}
+#endif /* HAVE_OPENLDAP */
+
+
+#ifdef HAVE_LIBSLP
+/*
+ * 'send_slp_browse()' - Register the specified printer with SLP.
+ */
+
+static void
+send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */
+{
+ char srvurl[HTTP_MAX_URI], /* Printer service URI */
+ attrs[8192], /* Printer attributes */
+ finishings[1024], /* Finishings to support */
+ make_model[IPP_MAX_NAME * 2],
+ /* Make and model, quoted */
+ location[IPP_MAX_NAME * 2],
+ /* Location, quoted */
+ info[IPP_MAX_NAME * 2], /* Info, quoted */
+ *src, /* Pointer to original string */
+ *dst; /* Pointer to destination string */
+ ipp_attribute_t *authentication; /* uri-authentication-supported value */
+ SLPError error; /* SLP error, if any */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
+ p->name);
+
+ /*
+ * Make the SLP service URL that conforms to the IANA
+ * 'printer:' template.
+ */
+
+ snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
+
+ /*
+ * Figure out the finishings string...
+ */
+
+ if (p->type & CUPS_PRINTER_STAPLE)
+ strcpy(finishings, "staple");
+ else
+ finishings[0] = '\0';
+
+ if (p->type & CUPS_PRINTER_BIND)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",bind", sizeof(finishings));
+ else
+ strcpy(finishings, "bind");
+ }
+
+ if (p->type & CUPS_PRINTER_PUNCH)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",punch", sizeof(finishings));
+ else
+ strcpy(finishings, "punch");
+ }
+
+ if (p->type & CUPS_PRINTER_COVER)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",cover", sizeof(finishings));
+ else
+ strcpy(finishings, "cover");
+ }
+
+ if (p->type & CUPS_PRINTER_SORT)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",sort", sizeof(finishings));
+ else
+ strcpy(finishings, "sort");
+ }
+
+ if (!finishings[0])
+ strcpy(finishings, "none");
+
+ /*
+ * Quote any commas in the make and model, location, and info strings...
+ */
+
+ for (src = p->make_model, dst = make_model;
+ src && *src && dst < (make_model + sizeof(make_model) - 2);)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ if (!make_model[0])
+ strcpy(make_model, "Unknown");
+
+ for (src = p->location, dst = location;
+ src && *src && dst < (location + sizeof(location) - 2);)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ if (!location[0])
+ strcpy(location, "Unknown");
+
+ for (src = p->info, dst = info;
+ src && *src && dst < (info + sizeof(info) - 2);)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ if (!info[0])
+ strcpy(info, "Unknown");
+
+ /*
+ * Get the authentication value...
+ */
+
+ authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
+ IPP_TAG_KEYWORD);
+
+ /*
+ * Make the SLP attribute string list that conforms to
+ * the IANA 'printer:' template.
+ */
+
+ snprintf(attrs, sizeof(attrs),
+ "(printer-uri-supported=%s),"
+ "(uri-authentication-supported=%s>),"
+#ifdef HAVE_SSL
+ "(uri-security-supported=tls>),"
+#else
+ "(uri-security-supported=none>),"
+#endif /* HAVE_SSL */
+ "(printer-name=%s),"
+ "(printer-location=%s),"
+ "(printer-info=%s),"
+ "(printer-more-info=%s),"
+ "(printer-make-and-model=%s),"
+ "(printer-type=%d),"
+ "(charset-supported=utf-8),"
+ "(natural-language-configured=%s),"
+ "(natural-language-supported=de,en,es,fr,it),"
+ "(color-supported=%s),"
+ "(finishings-supported=%s),"
+ "(sides-supported=one-sided%s),"
+ "(multiple-document-jobs-supported=true)"
+ "(ipp-versions-supported=1.0,1.1)",
+ p->uri, authentication->values[0].string.text, p->name, location,
+ info, p->uri, make_model, p->type, DefaultLanguage,
+ p->type & CUPS_PRINTER_COLOR ? "true" : "false",
+ finishings,
+ p->type & CUPS_PRINTER_DUPLEX ?
+ ",two-sided-long-edge,two-sided-short-edge" : "");
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
+
+ /*
+ * Register the printer with the SLP server...
+ */
+
+ error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
+ SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
+
+ if (error != SLP_OK)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
+ error);
+}
+
+
+/*
+ * 'slp_attr_callback()' - SLP attribute callback
+ */
+
+static SLPBoolean /* O - SLP_TRUE for success */
+slp_attr_callback(
+ SLPHandle hslp, /* I - SLP handle */
+ const char *attrlist, /* I - Attribute list */
+ SLPError errcode, /* I - Parsing status for this attr */
+ void *cookie) /* I - Current printer */
+{
+ char *tmp = 0; /* Temporary string */
+ cupsd_printer_t *p = (cupsd_printer_t*)cookie;
+ /* Current printer */
+
+
+ (void)hslp; /* anti-compiler-warning-code */
+
+ /*
+ * Bail if there was an error
+ */
+
+ if (errcode != SLP_OK)
+ return (SLP_TRUE);
+
+ /*
+ * Parse the attrlist to obtain things needed to build CUPS browse packet
+ */
+
+ memset(p, 0, sizeof(cupsd_printer_t));
+
+ if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
+ return (SLP_FALSE);
+ if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
+ return (SLP_FALSE);
+ if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
+ return (SLP_FALSE);
+ if (!slp_get_attr(attrlist, "(printer-type=", &tmp))
+ p->type = atoi(tmp);
+ else
+ p->type = CUPS_PRINTER_REMOTE;
+
+ cupsdClearString(&tmp);
+
+ return (SLP_TRUE);
+}
+
+
+/*
+ * 'slp_dereg_printer()' - SLPDereg() the specified printer
+ */
+
+static void
+slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
+{
+ char srvurl[HTTP_MAX_URI]; /* Printer service URI */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
+
+ if (!(p->type & CUPS_PRINTER_REMOTE))
+ {
+ /*
+ * Make the SLP service URL that conforms to the IANA
+ * 'printer:' template.
+ */
+
+ snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
+
+ /*
+ * Deregister the printer...
+ */
- bytes = strlen(packet);
+ SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
+ }
+}
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
- iface->name, packet);
- iface->broadcast.ipv4.sin_port = htons(BrowsePort);
+/*
+ * 'slp_get_attr()' - Get an attribute from an SLP registration.
+ */
- sendto(BrowseSocket, packet, bytes, 0,
- (struct sockaddr *)&(iface->broadcast),
- httpAddrLength(&(iface->broadcast)));
- }
- }
- else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
- {
- /*
- * Send to the named interface using the IPv4 address...
- */
+static int /* O - 0 on success */
+slp_get_attr(const char *attrlist, /* I - Attribute list string */
+ const char *tag, /* I - Name of attribute */
+ char **valbuf) /* O - Value */
+{
+ char *ptr1, /* Pointer into string */
+ *ptr2; /* ... */
- while (iface)
- if (strcmp(b->iface, iface->name))
- {
- iface = NULL;
- break;
- }
- else if (iface->address.addr.sa_family == AF_INET && iface->port)
- break;
- else
- iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
- if (iface)
- {
- httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
- iface->hostname, iface->port,
- (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" :
- "/printers/%s",
- p->name);
- snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
- type, p->state, uri, location, info, make_model,
- p->browse_attrs ? p->browse_attrs : "");
+ cupsdClearString(valbuf);
- bytes = strlen(packet);
+ if ((ptr1 = strstr(attrlist, tag)) != NULL)
+ {
+ ptr1 += strlen(tag);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
- iface->name, packet);
+ if ((ptr2 = strchr(ptr1,')')) != NULL)
+ {
+ /*
+ * Copy the value...
+ */
- iface->broadcast.ipv4.sin_port = htons(BrowsePort);
+ *valbuf = calloc(ptr2 - ptr1 + 1, 1);
+ strncpy(*valbuf, ptr1, ptr2 - ptr1);
- sendto(BrowseSocket, packet, bytes, 0,
- (struct sockaddr *)&(iface->broadcast),
- httpAddrLength(&(iface->broadcast)));
- }
- }
- }
- else
- {
/*
- * Send the browse packet to the indicated address using
- * the default server name...
+ * Dequote the value...
*/
- snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
- type, p->state, p->uri, location, info, make_model,
- p->browse_attrs ? p->browse_attrs : "");
+ for (ptr1 = *valbuf; *ptr1; ptr1 ++)
+ if (*ptr1 == '\\' && ptr1[1])
+ _cups_strcpy(ptr1, ptr1 + 1);
- bytes = strlen(packet);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
+ return (0);
+ }
+ }
- if (sendto(BrowseSocket, packet, bytes, 0,
- (struct sockaddr *)&(b->to),
- httpAddrLength(&(b->to))) <= 0)
- {
- /*
- * Unable to send browse packet, so remove this address from the
- * list...
- */
+ return (-1);
+}
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdSendBrowseList: sendto failed for browser "
- "%d - %s.",
- (int)(b - Browsers + 1), strerror(errno));
- if (i > 1)
- memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
+/*
+ * 'slp_reg_callback()' - Empty SLPRegReport.
+ */
- b --;
- NumBrowsers --;
- }
- }
+static void
+slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
+ SLPError errcode, /* I - Error code, if any */
+ void *cookie) /* I - App data */
+{
+ (void)hslp;
+ (void)errcode;
+ (void)cookie;
+
+ return;
}
-#ifdef HAVE_OPENLDAP
/*
- * 'send_ldap_browse()' - Send LDAP printer registrations.
+ * 'slp_url_callback()' - SLP service url callback
*/
-static void
-send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */
+static SLPBoolean /* O - TRUE = OK, FALSE = error */
+slp_url_callback(
+ SLPHandle hslp, /* I - SLP handle */
+ const char *srvurl, /* I - URL of service */
+ unsigned short lifetime, /* I - Life of service */
+ SLPError errcode, /* I - Existing error code */
+ void *cookie) /* I - Pointer to service list */
{
- int i; /* Looping var... */
- LDAPMod mods[7]; /* The 7 attributes we will be adding */
- LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
- LDAPMessage *res; /* Search result token */
- char *cn_value[2], /* Change records */
- *uri[2],
- *info[2],
- *location[2],
- *make_model[2],
- *type[2],
- typestring[255], /* String to hold printer-type */
- filter[256], /* Search filter for possible UPDATEs */
- dn[1024]; /* DN of the printer we are adding */
- int rc; /* LDAP status */
- static const char * const objectClass_values[] =
- { /* The 3 objectClass's we use in */
- "top", /* our LDAP entries */
- "device",
- "cupsPrinter",
- NULL
- };
+ slpsrvurl_t *s, /* New service entry */
+ **head; /* Pointer to head of entry */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s\n", p->name);
/*
- * Everything in ldap is ** so we fudge around it...
+ * Let the compiler know we won't be using these vars...
*/
- sprintf(typestring, "%u", p->type);
+ (void)hslp;
+ (void)lifetime;
- cn_value[0] = p->name;
- cn_value[1] = NULL;
- info[0] = p->info ? p->info : "Unknown";
- info[1] = NULL;
- location[0] = p->location ? p->location : "Unknown";
- location[1] = NULL;
- make_model[0] = p->make_model ? p->make_model : "Unknown";
- make_model[1] = NULL;
- type[0] = typestring;
- type[1] = NULL;
- uri[0] = p->uri;
- uri[1] = NULL;
+ /*
+ * Bail if there was an error
+ */
- snprintf(filter, sizeof(filter),
- "(&(objectclass=cupsPrinter)(printerURI=%s))", p->uri);
+ if (errcode != SLP_OK)
+ return (SLP_TRUE);
- ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
- filter, (char **)ldap_attrs, 0, &res);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: Searching \"%s\"",
- filter);
+ /*
+ * Grab the head of the list...
+ */
- mods[0].mod_type = "cn";
- mods[0].mod_values = cn_value;
- mods[1].mod_type = "printerDescription";
- mods[1].mod_values = info;
- mods[2].mod_type = "printerURI";
- mods[2].mod_values = uri;
- mods[3].mod_type = "printerLocation";
- mods[3].mod_values = location;
- mods[4].mod_type = "printerMakeAndModel";
- mods[4].mod_values = make_model;
- mods[5].mod_type = "printerType";
- mods[5].mod_values = type;
- mods[6].mod_type = "objectClass";
- mods[6].mod_values = (char **)objectClass_values;
+ head = (slpsrvurl_t**)cookie;
- snprintf(dn, sizeof(dn), "cn=%s,ou=printers,%s", p->name, BrowseLDAPDN);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
+ /*
+ * Allocate a *temporary* slpsrvurl_t to hold this entry.
+ */
- if (ldap_count_entries(BrowseLDAPHandle, res) > 0)
- {
- /*
- * Printer has already been registered, modify the current
- * registration...
- */
+ if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
+ return (SLP_FALSE);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "send_ldap_browse: Replacing entry...");
+ /*
+ * Copy the SLP service URL...
+ */
- for (i = 0; i < 7; i ++)
- {
- pmods[i] = mods + i;
- pmods[i]->mod_op = LDAP_MOD_REPLACE;
- }
- pmods[i] = NULL;
+ strlcpy(s->url, srvurl, sizeof(s->url));
- if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LDAP modify for %s failed with status %d: %s",
- p->name, rc, ldap_err2string(rc));
- }
- else
- {
- /*
- * Printer has never been registered, add the current
- * registration...
- */
+ /*
+ * Link the SLP service URL into the head of the list
+ */
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "send_ldap_browse: Adding entry...");
+ if (*head)
+ s->next = *head;
- for (i = 0; i < 7; i ++)
- {
- pmods[i] = mods + i;
- pmods[i]->mod_op = LDAP_MOD_ADD;
- }
- pmods[i] = NULL;
+ *head = s;
- if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LDAP add for %s failed with status %d: %s",
- p->name, rc, ldap_err2string(rc));
- }
+ return (SLP_TRUE);
}
-#endif /* HAVE_OPENLDAP */
+#endif /* HAVE_LIBSLP */
-#ifdef HAVE_LIBSLP
/*
- * 'send_slp_browse()' - Register the specified printer with SLP.
+ * 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
*/
static void
-send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */
+update_cups_browse(void)
{
- char srvurl[HTTP_MAX_URI], /* Printer service URI */
- attrs[8192], /* Printer attributes */
- finishings[1024], /* Finishings to support */
- make_model[IPP_MAX_NAME * 2],
- /* Make and model, quoted */
- location[IPP_MAX_NAME * 2],
- /* Location, quoted */
- info[IPP_MAX_NAME * 2], /* Info, quoted */
- *src, /* Pointer to original string */
- *dst; /* Pointer to destination string */
- ipp_attribute_t *authentication; /* uri-authentication-supported value */
- SLPError error; /* SLP error, if any */
-
+ int i; /* Looping var */
+ int auth; /* Authorization status */
+ int len; /* Length of name string */
+ int bytes; /* Number of bytes left */
+ char packet[1541], /* Broadcast packet */
+ *pptr; /* Pointer into packet */
+ socklen_t srclen; /* Length of source address */
+ http_addr_t srcaddr; /* Source address */
+ char srcname[1024]; /* Source hostname */
+ unsigned address[4]; /* Source address */
+ unsigned type; /* Printer type */
+ unsigned state; /* Printer state */
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI], /* Resource portion of URI */
+ info[IPP_MAX_NAME], /* Information string */
+ location[IPP_MAX_NAME], /* Location string */
+ make_model[IPP_MAX_NAME];/* Make and model string */
+ int num_attrs; /* Number of attributes */
+ cups_option_t *attrs; /* Attributes */
- cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
- p->name);
/*
- * Make the SLP service URL that conforms to the IANA
- * 'printer:' template.
+ * Read a packet from the browse socket...
*/
- snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
+ srclen = sizeof(srcaddr);
+ if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
+ (struct sockaddr *)&srcaddr, &srclen)) < 0)
+ {
+ /*
+ * "Connection refused" is returned under Linux if the destination port
+ * or address is unreachable from a previous sendto(); check for the
+ * error here and ignore it for now...
+ */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
+ if (errno != ECONNREFUSED && errno != EAGAIN)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
+ strerror(errno));
+ cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off.");
+
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
+
+ cupsdRemoveSelect(BrowseSocket);
+ BrowseSocket = -1;
+
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
+ }
+
+ return;
+ }
+
+ packet[bytes] = '\0';
/*
- * Figure out the finishings string...
+ * If we're about to sleep, ignore incoming browse packets.
*/
- if (p->type & CUPS_PRINTER_STAPLE)
- strcpy(finishings, "staple");
- else
- finishings[0] = '\0';
+ if (Sleeping)
+ return;
- if (p->type & CUPS_PRINTER_BIND)
- {
- if (finishings[0])
- strlcat(finishings, ",bind", sizeof(finishings));
- else
- strcpy(finishings, "bind");
- }
+ /*
+ * Figure out where it came from...
+ */
- if (p->type & CUPS_PRINTER_PUNCH)
+#ifdef AF_INET6
+ if (srcaddr.addr.sa_family == AF_INET6)
{
- if (finishings[0])
- strlcat(finishings, ",punch", sizeof(finishings));
- else
- strcpy(finishings, "punch");
+ address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
+ address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
+ address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
+ address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
}
-
- if (p->type & CUPS_PRINTER_COVER)
+ else
+#endif /* AF_INET6 */
{
- if (finishings[0])
- strlcat(finishings, ",cover", sizeof(finishings));
- else
- strcpy(finishings, "cover");
+ address[0] = 0;
+ address[1] = 0;
+ address[2] = 0;
+ address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
}
- if (p->type & CUPS_PRINTER_SORT)
- {
- if (finishings[0])
- strlcat(finishings, ",sort", sizeof(finishings));
- else
- strcpy(finishings, "sort");
- }
+ if (HostNameLookups)
+ httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
+ else
+ httpAddrString(&srcaddr, srcname, sizeof(srcname));
- if (!finishings[0])
- strcpy(finishings, "none");
+ len = strlen(srcname);
/*
- * Quote any commas in the make and model, location, and info strings...
+ * Do ACL stuff...
*/
- for (src = p->make_model, dst = make_model;
- src && *src && dst < (make_model + sizeof(make_model) - 2);)
+ if (BrowseACL)
{
- if (*src == ',' || *src == '\\' || *src == ')')
- *dst++ = '\\';
-
- *dst++ = *src++;
- }
+ if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
+ {
+ /*
+ * Access from localhost (127.0.0.1) is always allowed...
+ */
- *dst = '\0';
+ auth = CUPSD_AUTH_ALLOW;
+ }
+ else
+ {
+ /*
+ * Do authorization checks on the domain/address...
+ */
- if (!make_model[0])
- strcpy(make_model, "Unknown");
+ switch (BrowseACL->order_type)
+ {
+ default :
+ auth = CUPSD_AUTH_DENY; /* anti-compiler-warning-code */
+ break;
- for (src = p->location, dst = location;
- src && *src && dst < (location + sizeof(location) - 2);)
- {
- if (*src == ',' || *src == '\\' || *src == ')')
- *dst++ = '\\';
+ case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
+ auth = CUPSD_AUTH_ALLOW;
- *dst++ = *src++;
- }
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_deny, BrowseACL->deny))
+ auth = CUPSD_AUTH_DENY;
- *dst = '\0';
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_allow, BrowseACL->allow))
+ auth = CUPSD_AUTH_ALLOW;
+ break;
- if (!location[0])
- strcpy(location, "Unknown");
+ case CUPSD_AUTH_DENY : /* Order Allow,Deny */
+ auth = CUPSD_AUTH_DENY;
- for (src = p->info, dst = info;
- src && *src && dst < (info + sizeof(info) - 2);)
- {
- if (*src == ',' || *src == '\\' || *src == ')')
- *dst++ = '\\';
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_allow, BrowseACL->allow))
+ auth = CUPSD_AUTH_ALLOW;
- *dst++ = *src++;
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_deny, BrowseACL->deny))
+ auth = CUPSD_AUTH_DENY;
+ break;
+ }
+ }
}
+ else
+ auth = CUPSD_AUTH_ALLOW;
- *dst = '\0';
+ if (auth == CUPSD_AUTH_DENY)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "update_cups_browse: Refused %d bytes from %s", bytes,
+ srcname);
+ return;
+ }
- if (!info[0])
- strcpy(info, "Unknown");
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "update_cups_browse: (%d bytes from %s) %s", bytes,
+ srcname, packet);
/*
- * Get the authentication value...
+ * Parse packet...
*/
- authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
- IPP_TAG_KEYWORD);
+ if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "update_cups_browse: Garbled browse packet - %s", packet);
+ return;
+ }
- /*
- * Make the SLP attribute string list that conforms to
- * the IANA 'printer:' template.
- */
+ strcpy(location, "Location Unknown");
+ strcpy(info, "No Information Available");
+ make_model[0] = '\0';
+ num_attrs = 0;
+ attrs = NULL;
- snprintf(attrs, sizeof(attrs),
- "(printer-uri-supported=%s),"
- "(uri-authentication-supported=%s>),"
-#ifdef HAVE_SSL
- "(uri-security-supported=tls>),"
-#else
- "(uri-security-supported=none>),"
-#endif /* HAVE_SSL */
- "(printer-name=%s),"
- "(printer-location=%s),"
- "(printer-info=%s),"
- "(printer-more-info=%s),"
- "(printer-make-and-model=%s),"
- "(printer-type=%d),"
- "(charset-supported=utf-8),"
- "(natural-language-configured=%s),"
- "(natural-language-supported=de,en,es,fr,it),"
- "(color-supported=%s),"
- "(finishings-supported=%s),"
- "(sides-supported=one-sided%s),"
- "(multiple-document-jobs-supported=true)"
- "(ipp-versions-supported=1.0,1.1)",
- p->uri, authentication->values[0].string.text, p->name, location,
- info, p->uri, make_model, p->type, DefaultLanguage,
- p->type & CUPS_PRINTER_COLOR ? "true" : "false",
- finishings,
- p->type & CUPS_PRINTER_DUPLEX ?
- ",two-sided-long-edge,two-sided-short-edge" : "");
+ if ((pptr = strchr(packet, '\"')) != NULL)
+ {
+ /*
+ * Have extended information; can't use sscanf for it because not all
+ * sscanf's allow empty strings with %[^\"]...
+ */
+
+ for (i = 0, pptr ++;
+ i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ location[i] = *pptr;
+
+ if (i)
+ location[i] = '\0';
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
+ if (*pptr == '\"')
+ pptr ++;
- /*
- * Register the printer with the SLP server...
- */
+ while (*pptr && isspace(*pptr & 255))
+ pptr ++;
- error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
- SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
+ if (*pptr == '\"')
+ {
+ for (i = 0, pptr ++;
+ i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ info[i] = *pptr;
- if (error != SLP_OK)
- cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
- error);
-}
+ info[i] = '\0';
+ if (*pptr == '\"')
+ pptr ++;
-/*
- * 'slp_attr_callback()' - SLP attribute callback
- */
+ while (*pptr && isspace(*pptr & 255))
+ pptr ++;
-static SLPBoolean /* O - SLP_TRUE for success */
-slp_attr_callback(
- SLPHandle hslp, /* I - SLP handle */
- const char *attrlist, /* I - Attribute list */
- SLPError errcode, /* I - Parsing status for this attr */
- void *cookie) /* I - Current printer */
-{
- char *tmp = 0; /* Temporary string */
- cupsd_printer_t *p = (cupsd_printer_t*)cookie;
- /* Current printer */
+ if (*pptr == '\"')
+ {
+ for (i = 0, pptr ++;
+ i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ make_model[i] = *pptr;
+ if (*pptr == '\"')
+ pptr ++;
- (void)hslp; /* anti-compiler-warning-code */
+ make_model[i] = '\0';
+
+ if (*pptr)
+ num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
+ }
+ }
+ }
+
+ DEBUG_puts(packet);
+ DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
+ "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
+ type, state, uri, location, info, make_model));
/*
- * Bail if there was an error
+ * Pull the URI apart to see if this is a local or remote printer...
*/
- if (errcode != SLP_OK)
- return (SLP_TRUE);
+ if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
+ {
+ cupsFreeOptions(num_attrs, attrs);
+ return;
+ }
/*
- * Parse the attrlist to obtain things needed to build CUPS browse packet
+ * Do relaying...
*/
- memset(p, 0, sizeof(cupsd_printer_t));
-
- if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
- return (SLP_FALSE);
- if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
- return (SLP_FALSE);
- if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
- return (SLP_FALSE);
- if (!slp_get_attr(attrlist, "(printer-type=", &tmp))
- p->type = atoi(tmp);
- else
- p->type = CUPS_PRINTER_REMOTE;
+ for (i = 0; i < NumRelays; i ++)
+ if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
+ if (sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(Relays[i].to),
+ httpAddrLength(&(Relays[i].to))) <= 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "update_cups_browse: sendto failed for relay %d - %s.",
+ i + 1, strerror(errno));
+ cupsFreeOptions(num_attrs, attrs);
+ return;
+ }
- cupsdClearString(&tmp);
+ /*
+ * Process the browse data...
+ */
- return (SLP_TRUE);
+ process_browse_data(uri, host, resource, (cups_ptype_t)type,
+ (ipp_pstate_t)state, location, info, make_model,
+ num_attrs, attrs);
}
/*
- * 'slp_dereg_printer()' - SLPDereg() the specified printer
+ * 'update_lpd()' - Update the LPD configuration as needed.
*/
-static void
-slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
+static void
+update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
{
- char srvurl[HTTP_MAX_URI]; /* Printer service URI */
+ if (!LPDConfigFile)
+ return;
+#ifdef __APPLE__
+ /*
+ * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
+ * setting for backwards-compatibility.
+ */
- cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
+ if (onoff && !get_hostconfig("CUPS_LPD"))
+ onoff = 0;
+#endif /* __APPLE__ */
- if (!(p->type & CUPS_PRINTER_REMOTE))
+ if (!strncmp(LPDConfigFile, "xinetd:///", 10))
{
/*
- * Make the SLP service URL that conforms to the IANA
- * 'printer:' template.
+ * Enable/disable LPD via the xinetd.d config file for cups-lpd...
*/
- snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
-
- /*
- * Deregister the printer...
- */
+ char newfile[1024]; /* New cups-lpd.N file */
+ cups_file_t *ofp, /* Original file pointer */
+ *nfp; /* New file pointer */
+ char line[1024]; /* Line from file */
- SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
- }
-}
+ snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
-/*
- * 'slp_get_attr()' - Get an attribute from an SLP registration.
- */
+ if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
+ LPDConfigFile + 9, strerror(errno));
+ return;
+ }
-static int /* O - 0 on success */
-slp_get_attr(const char *attrlist, /* I - Attribute list string */
- const char *tag, /* I - Name of attribute */
- char **valbuf) /* O - Value */
-{
- char *ptr1, /* Pointer into string */
- *ptr2; /* ... */
+ if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
+ newfile, strerror(errno));
+ cupsFileClose(ofp);
+ return;
+ }
+ /*
+ * Copy all of the lines from the cups-lpd file...
+ */
- cupsdClearString(valbuf);
+ while (cupsFileGets(ofp, line, sizeof(line)))
+ {
+ if (line[0] == '{')
+ {
+ cupsFilePrintf(nfp, "%s\n", line);
+ snprintf(line, sizeof(line), "\tdisable = %s",
+ onoff ? "no" : "yes");
+ }
+ else if (!strstr(line, "disable ="))
+ cupsFilePrintf(nfp, "%s\n", line);
+ }
- if ((ptr1 = strstr(attrlist, tag)) != NULL)
+ cupsFileClose(nfp);
+ cupsFileClose(ofp);
+ rename(newfile, LPDConfigFile + 9);
+ }
+#ifdef __APPLE__
+ else if (!strncmp(LPDConfigFile, "launchd:///", 11))
{
- ptr1 += strlen(tag);
-
- if ((ptr2 = strchr(ptr1,')')) != NULL)
- {
- /*
- * Copy the value...
- */
+ /*
+ * Enable/disable LPD via the launchctl command...
+ */
- *valbuf = calloc(ptr2 - ptr1 + 1, 1);
- strncpy(*valbuf, ptr1, ptr2 - ptr1);
+ char *argv[5], /* Arguments for command */
+ *envp[MAX_ENV]; /* Environment for command */
+ int pid; /* Process ID */
- /*
- * Dequote the value...
- */
- for (ptr1 = *valbuf; *ptr1; ptr1 ++)
- if (*ptr1 == '\\' && ptr1[1])
- _cups_strcpy(ptr1, ptr1 + 1);
+ cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+ argv[0] = (char *)"launchctl";
+ argv[1] = (char *)(onoff ? "load" : "unload");
+ argv[2] = (char *)"-w";
+ argv[3] = LPDConfigFile + 10;
+ argv[4] = NULL;
- return (0);
- }
+ cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
+ NULL, &pid);
}
-
- return (-1);
+#endif /* __APPLE__ */
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
}
/*
- * 'slp_reg_callback()' - Empty SLPRegReport.
+ * 'update_polling()' - Read status messages from the poll daemons.
*/
static void
-slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
- SLPError errcode, /* I - Error code, if any */
- void *cookie) /* I - App data */
+update_polling(void)
{
- (void)hslp;
- (void)errcode;
- (void)cookie;
+ char *ptr, /* Pointer to end of line in buffer */
+ message[1024]; /* Pointer to message text */
+ int loglevel; /* Log level for message */
- return;
+
+ while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
+ message, sizeof(message))) != NULL)
+ if (!strchr(PollStatusBuffer->buffer, '\n'))
+ break;
+
+ if (ptr == NULL && !PollStatusBuffer->bufused)
+ {
+ /*
+ * All polling processes have died; stop polling...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "update_polling: all polling processes have exited!");
+ cupsdStopPolling();
+ }
}
/*
- * 'slp_url_callback()' - SLP service url callback
+ * 'update_smb()' - Update the SMB configuration as needed.
*/
-static SLPBoolean /* O - TRUE = OK, FALSE = error */
-slp_url_callback(
- SLPHandle hslp, /* I - SLP handle */
- const char *srvurl, /* I - URL of service */
- unsigned short lifetime, /* I - Life of service */
- SLPError errcode, /* I - Existing error code */
- void *cookie) /* I - Pointer to service list */
+static void
+update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */
{
- slpsrvurl_t *s, /* New service entry */
- **head; /* Pointer to head of entry */
-
-
- /*
- * Let the compiler know we won't be using these vars...
- */
-
- (void)hslp;
- (void)lifetime;
+ if (!SMBConfigFile)
+ return;
- /*
- * Bail if there was an error
- */
+ if (!strncmp(SMBConfigFile, "samba:///", 9))
+ {
+ /*
+ * Enable/disable SMB via the specified smb.conf config file...
+ */
- if (errcode != SLP_OK)
- return (SLP_TRUE);
+ char newfile[1024]; /* New smb.conf.N file */
+ cups_file_t *ofp, /* Original file pointer */
+ *nfp; /* New file pointer */
+ char line[1024]; /* Line from file */
+ int in_printers; /* In [printers] section? */
- /*
- * Grab the head of the list...
- */
- head = (slpsrvurl_t**)cookie;
+ snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
- /*
- * Allocate a *temporary* slpsrvurl_t to hold this entry.
- */
+ if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
+ SMBConfigFile + 8, strerror(errno));
+ return;
+ }
- if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
- return (SLP_FALSE);
+ if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
+ newfile, strerror(errno));
+ cupsFileClose(ofp);
+ return;
+ }
- /*
- * Copy the SLP service URL...
- */
+ /*
+ * Copy all of the lines from the smb.conf file...
+ */
- strlcpy(s->url, srvurl, sizeof(s->url));
+ in_printers = 0;
- /*
- * Link the SLP service URL into the head of the list
- */
+ while (cupsFileGets(ofp, line, sizeof(line)))
+ {
+ if (in_printers && strstr(line, "printable ="))
+ snprintf(line, sizeof(line), " printable = %s",
+ onoff ? "yes" : "no");
- if (*head)
- s->next = *head;
+ cupsFilePrintf(nfp, "%s\n", line);
- *head = s;
+ if (line[0] == '[')
+ in_printers = !strcmp(line, "[printers]");
+ }
- return (SLP_TRUE);
+ cupsFileClose(nfp);
+ cupsFileClose(ofp);
+ rename(newfile, SMBConfigFile + 8);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
}
-#endif /* HAVE_LIBSLP */
/*
- * End of "$Id: dirsvc.c 6205 2007-01-22 22:04:43Z mike $".
+ * End of "$Id: dirsvc.c 7676 2008-06-18 23:42:37Z mike $".
*/