/*
- * "$Id: dirsvc.c 7003 2007-10-01 23:10:13Z mike $"
+ * "$Id: dirsvc.c 7676 2008-06-18 23:42:37Z mike $"
*
* Directory services routines for the Common UNIX Printing System (CUPS).
*
* cupsdStopBrowsing() - Stop sending and receiving broadcast
* information.
* cupsdStopPolling() - Stop polling servers as needed.
- * cupsdUpdateDNSSDBrowse() - Handle DNS-SD queries.
+ * 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.
- * is_local_queue() - Determine whether the URI points at a local
- * queue.
- * process_browse_data() - Process new browse data.
* 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
* 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.
*/
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,
ipp_pstate_t state, const char *location,
const char *info, const char *make_model,
int num_attrs, cups_option_t *attrs);
-static void process_implicit_classes(int *write_printcap);
+static void process_implicit_classes(void);
static void send_cups_browse(cupsd_printer_t *p);
#ifdef HAVE_LDAP
static void send_ldap_browse(cupsd_printer_t *p);
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 */
{
SLPError errcode, void *cookie);
#endif /* HAVE_LIBSLP */
-#ifdef HAVE_DNSSD
-/*
- * For IPP register using a subtype of 'cups' so that shared printer browsing
- * only finds other CUPS servers (not all IPP based printers).
- */
-static char dnssdIPPRegType[] = "_ipp._tcp,_cups";
-static char dnssdIPPFaxRegType[] = "_fax-ipp._tcp";
-
-static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p);
-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);
-#endif /* HAVE_DNSSD */
-
/*
* 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
int removeit) /* I - Printer being permanently removed */
{
/*
- * Only deregister if browsing is enabled and it's a local printers...
+ * Only deregister if browsing is enabled and it's a local printer...
*/
if (!Browsing || !p->shared ||
#endif /* HAVE_LIBSLP */
#ifdef HAVE_DNSSD
- if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD))
+ if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
dnssdDeregisterPrinter(p);
#endif /* HAVE_DNSSD */
}
/*
- * 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.");
* Do auto-classing if needed...
*/
- process_implicit_classes(NULL);
+ process_implicit_classes();
}
void
cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
{
- if (!Browsing || !BrowseLocalProtocols || !BrowseInterval || !NumBrowsers ||
+ if (!Browsing || !BrowseLocalProtocols ||
(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
return;
#endif /* HAVE_LIBSLP */
#ifdef HAVE_DNSSD
- if (BrowseLocalProtocols & BROWSE_DNSSD)
+ if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
dnssdRegisterPrinter(p);
#endif /* HAVE_DNSSD */
}
cupsd_printer_t *p; /* Current printer */
time_t ut, /* Minimum update time */
to; /* Timeout time */
- int write_printcap; /* Write the printcap file? */
if (!Browsing || !BrowseLocalProtocols || !Printers)
* Loop through all of the printers and send local updates as needed...
*/
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), write_printcap = 0;
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
{
cupsArraySave(Printers);
cupsdDeletePrinter(p, 1);
cupsArrayRestore(Printers);
- write_printcap = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
}
}
}
-
- if (write_printcap)
- cupsdWritePrintcap();
}
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)
{
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)
#ifdef HAVE_DNSSD
/*
- * 'cupsdUpdateDNSSDBrowse()' - Handle DNS-SD queries.
+ * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
*/
void
-cupsdUpdateDNSSDBrowse(
- cupsd_printer_t *p) /* I - Printer being queried */
+cupsdUpdateDNSSDName(void)
{
- DNSServiceErrorType sdErr; /* Service discovery error */
+ 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 */
+
+
+ /*
+ * Only share the web interface and printers when non-local listening is
+ * enabled...
+ */
+ if (!DNSSDPort)
+ return;
+
+ /*
+ * Get the computer name as a c-string...
+ */
+
+#ifdef HAVE_COREFOUNDATION_H
+ cupsdClearString(&DNSSDName);
- if ((sdErr = DNSServiceProcessResult(p->dnssd_ipp_ref))
- != kDNSServiceErr_NoError)
+ if ((nameRef = SCDynamicStoreCopyComputerName(NULL,
+ &nameEncoding)) != NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "DNS Service Discovery registration error %d for \"%s\"!",
- sdErr, p->name);
- cupsdRemoveSelect(p->dnssd_ipp_fd);
- DNSServiceRefDeallocate(p->dnssd_ipp_ref);
+ if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
+ kCFStringEncodingUTF8))
+ cupsdSetString(&DNSSDName, nameBuffer);
- p->dnssd_ipp_ref = NULL;
- p->dnssd_ipp_fd = -1;
+ CFRelease(nameRef);
}
+
+#else
+ cupsdSetString(&DNSSDName, ServerName);
+#endif /* HAVE_COREFOUNDATION_H */
+
+ /*
+ * Then (re)register the web interface...
+ */
+
+ 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_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? */
- write_printcap; /* Write the printcap file? */
- 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...
- */
-
- ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
+ if ((p->type & CUPS_PRINTER_DUPLEX))
+ {
+ keyvalue[i ][0] = "Duplex";
+ keyvalue[i++][1] = "T";
+ }
- if (BrowseRemoteOptions)
+ if ((p->type & CUPS_PRINTER_STAPLE))
{
- if (BrowseRemoteOptions[0] == '?')
- {
- /*
- * Override server-supplied options...
- */
+ keyvalue[i ][0] = "Staple";
+ 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_COPIES))
+ {
+ keyvalue[i ][0] = "Copies";
+ 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_COLLATE))
+ {
+ keyvalue[i ][0] = "Collate";
+ keyvalue[i++][1] = "T";
+ }
- snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
- }
+ if ((p->type & CUPS_PRINTER_PUNCH))
+ {
+ keyvalue[i ][0] = "Punch";
+ keyvalue[i++][1] = "T";
+ }
- uri = finaluri;
+ if ((p->type & CUPS_PRINTER_BIND))
+ {
+ keyvalue[i ][0] = "Bind";
+ keyvalue[i++][1] = "T";
}
- else if (ipp_options)
+
+ if ((p->type & CUPS_PRINTER_SORT))
{
- /*
- * Just use the server-supplied options...
- */
+ keyvalue[i ][0] = "Sort";
+ keyvalue[i++][1] = "T";
+ }
- snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
- uri = finaluri;
+ keyvalue[i ][0] = "pdl";
+ keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
+
+ if (p->num_auth_info_required)
+ {
+ char *air = air_str; /* Pointer into string */
+
+
+ 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 | CUPS_PRINTER_DISCOVERED;
- type &= ~CUPS_PRINTER_IMPLICIT;
- update = 0;
- write_printcap = 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;
-
- if (hptr && !*hptr)
- *hptr = '.'; /* Resource FQDN */
+ free(p->ipp_txt);
+ p->ipp_txt = NULL;
+ }
+}
- 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);
+/*
+ * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
+ * TXT record format.
+ */
- snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
- cupsdRenamePrinter(p, newname);
+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 */
- 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...
- */
+ /*
+ * Calculate the buffer size
+ */
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
- }
- }
- else
- {
- /*
- * Use the short name for this shared class.
- */
+ for (length = i = 0; i < count; i++)
+ length += 1 + strlen(keyvalue[i][0]) +
+ (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
- 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...
- */
+ /*
+ * Allocate and fill it
+ */
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
- }
+ txtRecord = malloc(length);
+ if (txtRecord)
+ {
+ *txt_len = length;
- if (!p)
+ for (cursor = txtRecord, i = 0; i < count; i++)
{
/*
- * Class doesn't exist; add it...
+ * Drop in the p-string style length byte followed by the data
*/
- 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);
+ length = strlen(keyvalue[i][0]);
+ length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
- /*
- * Force the URI to point to the real server...
- */
+ *cursor++ = (unsigned char)(length + length2);
- p->type = type & ~CUPS_PRINTER_REJECTING;
- p->accepting = 1;
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- cupsdSetString(&p->hostname, host);
+ memcpy(cursor, keyvalue[i][0], length);
+ cursor += length;
- update = 1;
- write_printcap = 1;
+ if (length2)
+ {
+ length2 --;
+ *cursor++ = '=';
+ memcpy(cursor, keyvalue[i][1], length2);
+ cursor += length2;
+ }
}
}
- else
- {
- /*
- * Remote destination is a printer...
- */
- if (!strncmp(resource, "/printers/", 10))
- snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
- else
- return;
+ return (txtRecord);
+}
- 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))
- {
- /*
- * 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...
- */
+/*
+ * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
+ */
- 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);
+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 */
- 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);
- }
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s",
+ name, regtype, p ? p->name : "Web Interface");
- 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 (errorCode)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNSServiceRegister failed with error %d", (int)errorCode);
+ return;
+ }
+ else if (p && strcasecmp(name, p->reg_name))
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
+ name, p->name);
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
- }
- }
- else
- {
- /*
- * Use the short name for this shared printer.
- */
+ cupsArrayRemove(DNSSDPrinters, p);
+ cupsdSetString(&p->reg_name, name);
+ cupsArrayAdd(DNSSDPrinters, p);
- 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...
- */
+ LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
+ }
+}
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
- }
- if (!p)
- {
- /*
- * Printer doesn't exist; add it...
- */
+/*
+ * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
+ * or update the broadcast contents.
+ */
- p = cupsdAddPrinter(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 */
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Printer \'%s\' added by directory services.", name);
- cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote printer \"%s\"...", name);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
+ !p->ipp_ref ? "new" : "update");
- /*
- * Force the URI to point to the real server...
- */
+ /*
+ * If per-printer sharing was just disabled make sure we're not
+ * registered before returning.
+ */
- p->type = type & ~CUPS_PRINTER_REJECTING;
- p->accepting = 1;
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
+ if (!p->shared)
+ {
+ dnssdDeregisterPrinter(p);
+ return;
+ }
- write_printcap = 1;
- update = 1;
- }
+ /*
+ * The registered name takes the form of "<printer-info> @ <computer name>"...
+ */
+
+ 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));
/*
- * Update the state...
+ * If an existing printer was renamed, unregister it and start over...
*/
- p->state = state;
- p->browse_time = time(NULL);
+ if (p->reg_name && strcmp(p->reg_name, name))
+ dnssdDeregisterPrinter(p);
- if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
- attrs)) != NULL)
+ if (!p->reg_name)
{
- /*
- * Grab the lease-duration for the browse data; anything less then 1
- * second or more than 1 week gets the default BrowseTimeout...
- */
+ cupsdSetString(&p->reg_name, name);
+ cupsArrayAdd(DNSSDPrinters, p);
+ }
- i = atoi(lease_duration);
- if (i < 1 || i > 604800)
- i = BrowseTimeout;
+ /*
+ * If 'Allow printing from the Internet' is enabled (i.e. from any address)
+ * let dnssd decide on the domain, otherwise restrict it to ".local".
+ */
- p->browse_expire = p->browse_time + i;
- }
+ if (p->type & CUPS_PRINTER_CLASS)
+ snprintf(resource, sizeof(resource), "/classes/%s", p->name);
else
- p->browse_expire = p->browse_time + BrowseTimeout;
+ snprintf(resource, sizeof(resource), "/printers/%s", p->name);
- if (type & CUPS_PRINTER_REJECTING)
+ address[0] = address[1] = address[2] = address[3] = 0;
+ location = cupsdFindBest(resource, HTTP_POST);
+ policy = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
+
+ if ((location && !cupsdCheckAccess(address, "", 0, location)) ||
+ (policy && !cupsdCheckAccess(address, "", 0, policy)))
+ domain = "local.";
+ else
+ domain = NULL;
+
+ /*
+ * Register IPP and (optionally) LPD...
+ */
+
+ ipp_len = 0; /* anti-compiler-warning-code */
+ ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
+
+ if (!p->ipp_ref)
{
- type &= ~CUPS_PRINTER_REJECTING;
+ /*
+ * Initial registration. Use the _fax subtype for fax queues...
+ */
- if (p->accepting)
+ regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" :
+ "_ipp._tcp,_cups";
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Registering DNS-SD printer %s with name \"%s\", "
+ "type \"%s\", and domain \"%s\"", p->name, name, regtype,
+ domain ? domain : "(null)");
+
+ /*
+ * Register the queue, dropping characters as needed until we succeed...
+ */
+
+ 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;
- write_printcap = 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...
- */
+ /* A TTL of 0 means use record's original value (Radar 3176248) */
+ DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len,
+ printer_txt, 0);
- cupsFreeOptions(p->num_options, p->options);
- }
+ if (p->printer_txt)
+ free(p->printer_txt);
- p->num_options = num_attrs;
- p->options = attrs;
+ p->printer_txt = printer_txt;
+ p->printer_len = printer_len;
+ printer_txt = NULL;
+ }
- 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);
+ if (printer_txt)
+ free(printer_txt);
+ }
+}
- cupsdExpireSubscriptions(p, NULL);
-
- cupsdDeletePrinter(p, 1);
- cupsdUpdateImplicitClasses();
- write_printcap = 1;
- }
- 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;
- write_printcap = 1;
- break;
- }
- }
- /*
- * Do auto-classing if needed...
- */
+/*
+ * 'dnssdUpdate()' - Handle DNS-SD queries.
+ */
- process_implicit_classes(&write_printcap);
+static void
+dnssdUpdate(void)
+{
+ DNSServiceErrorType sdErr; /* Service discovery error */
- /*
- * Update the printcap file...
- */
- if (write_printcap)
- cupsdWritePrintcap();
+ if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNS Service Discovery registration error %d!",
+ sdErr);
}
+#endif /* HAVE_DNSSD */
-#ifdef HAVE_DNSSD
+#ifdef __APPLE__
/*
- * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
+ * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
*/
-static char * /* O - TXT record */
-dnssdBuildTxtRecord(
- int *txt_len, /* O - TXT record length */
- cupsd_printer_t *p) /* I - Printer information */
+static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
+get_hostconfig(const char *name) /* I - Name of service */
{
- 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 */
+ cups_file_t *fp; /* Hostconfig file */
+ char line[1024], /* Line from file */
+ *ptr; /* Pointer to value */
+ int state = 1; /* State of service */
/*
- * Load up the key value pairs...
+ * Try opening the /etc/hostconfig file; if we can't open it, assume that
+ * the service is enabled/auto.
*/
- i = 0;
-
- keyvalue[i ][0] = "txtvers";
- keyvalue[i++][1] = "1";
-
- keyvalue[i ][0] = "qtotal";
- keyvalue[i++][1] = "1";
-
- keyvalue[i ][0] = "rp";
- keyvalue[i++][1] = rp_str;
- snprintf(rp_str, sizeof(rp_str), "%s/%s",
- (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
-
- keyvalue[i ][0] = "ty";
- keyvalue[i++][1] = p->make_model;
-
- if (p->location && *p->location != '\0')
+ if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
{
- keyvalue[i ][0] = "note";
- keyvalue[i++][1] = p->location;
- }
-
- 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);
-
- keyvalue[i ][0] = "printer-state";
- keyvalue[i++][1] = state_str;
-
- keyvalue[i ][0] = "printer-type";
- keyvalue[i++][1] = type_str;
-
- keyvalue[i ][0] = "Transparent";
- keyvalue[i++][1] = "T";
+ /*
+ * Read lines from the file until we find the service...
+ */
- keyvalue[i ][0] = "Binary";
- keyvalue[i++][1] = "T";
+ while (cupsFileGets(fp, line, sizeof(line)))
+ {
+ if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
+ continue;
- if ((p->type & CUPS_PRINTER_FAX))
- {
- keyvalue[i ][0] = "Fax";
- keyvalue[i++][1] = "T";
- }
+ *ptr++ = '\0';
- if ((p->type & CUPS_PRINTER_COLOR))
- {
- keyvalue[i ][0] = "Color";
- keyvalue[i++][1] = "T";
- }
+ if (!strcasecmp(line, name))
+ {
+ /*
+ * Found the service, see if it is set to "-NO-"...
+ */
- if ((p->type & CUPS_PRINTER_DUPLEX))
- {
- keyvalue[i ][0] = "Duplex";
- keyvalue[i++][1] = "T";
- }
+ if (!strncasecmp(ptr, "-NO-", 4))
+ state = 0;
+ break;
+ }
+ }
- if ((p->type & CUPS_PRINTER_STAPLE))
- {
- keyvalue[i ][0] = "Staple";
- keyvalue[i++][1] = "T";
+ cupsFileClose(fp);
}
- if ((p->type & CUPS_PRINTER_COPIES))
- {
- keyvalue[i ][0] = "Copies";
- keyvalue[i++][1] = "T";
- }
+ return (state);
+}
+#endif /* __APPLE__ */
- if ((p->type & CUPS_PRINTER_COLLATE))
- {
- keyvalue[i ][0] = "Collate";
- keyvalue[i++][1] = "T";
- }
- if ((p->type & CUPS_PRINTER_PUNCH))
- {
- keyvalue[i ][0] = "Punch";
- keyvalue[i++][1] = "T";
- }
+/*
+ * 'is_local_queue()' - Determine whether the URI points at a local queue.
+ */
- if ((p->type & CUPS_PRINTER_BIND))
- {
- keyvalue[i ][0] = "Bind";
- keyvalue[i++][1] = "T";
- }
+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 ((p->type & CUPS_PRINTER_SORT))
- {
- keyvalue[i ][0] = "Sort";
- keyvalue[i++][1] = "T";
- }
- keyvalue[i ][0] = "pdl";
- keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
- if (p->num_auth_info_required)
- {
- char *air = air_str; /* Pointer into string */
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
+ username, sizeof(username), host, hostlen, &port,
+ resource, resourcelen) < HTTP_URI_OK)
+ return (-1);
+ DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
- for (j = 0; j < p->num_auth_info_required; j ++)
- {
- if (air >= (air_str + sizeof(air_str) - 2))
- break;
+ /*
+ * Check for local server addresses...
+ */
- if (j)
- *air++ = ',';
+ if (!strcasecmp(host, ServerName) && port == LocalPort)
+ return (1);
- strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str));
- air += strlen(air);
- }
+ cupsdNetIFUpdate();
- keyvalue[i ][0] = "air";
- keyvalue[i++][1] = air;
- }
+ for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ iface;
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ if (!strcasecmp(host, iface->hostname) && port == iface->port)
+ return (1);
/*
- * Then pack them into a proper txt record...
+ * If we get here, the printer is remote...
*/
- return (dnssdPackTxtRecord(txt_len, keyvalue, i));
+ return (0);
}
/*
- * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
- * printer.
+ * 'process_browse_data()' - Process new browse data.
*/
static void
-dnssdDeregisterPrinter(
- cupsd_printer_t *p) /* I - Printer */
+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 */
{
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
+ 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 */
+
/*
- * Closing the socket deregisters the service
+ * Determine if the URI contains any illegal characters in it...
*/
- if (p->dnssd_ipp_ref)
+ if (strncmp(uri, "ipp://", 6) || !host[0] ||
+ (strncmp(resource, "/printers/", 10) &&
+ strncmp(resource, "/classes/", 9)))
{
- cupsdRemoveSelect(p->dnssd_ipp_fd);
- DNSServiceRefDeallocate(p->dnssd_ipp_ref);
- p->dnssd_ipp_ref = NULL;
- p->dnssd_ipp_fd = -1;
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "process_browse_data: Bad printer URI in browse data: %s",
+ uri);
+ return;
}
- cupsdClearString(&p->reg_name);
-
- if (p->txt_record)
+ if (strchr(resource, '?') ||
+ (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
+ (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
{
- /*
- * p->txt_record is malloc'd, not _cupsStrAlloc'd...
- */
-
- free(p->txt_record);
- p->txt_record = NULL;
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "process_browse_data: Bad resource in browse data: %s",
+ resource);
+ return;
}
-}
+ /*
+ * OK, this isn't a local printer; add any remote options...
+ */
-/*
- * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
- * TXT record format.
- */
+ ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
-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 */
+ if (BrowseRemoteOptions)
+ {
+ if (BrowseRemoteOptions[0] == '?')
+ {
+ /*
+ * Override server-supplied options...
+ */
+ snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
+ }
+ else if (ipp_options)
+ {
+ /*
+ * Combine the server and local options...
+ */
- /*
- * Calculate the buffer size
- */
+ snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
+ BrowseRemoteOptions);
+ }
+ else
+ {
+ /*
+ * Just use the local options...
+ */
- for (length = i = 0; i < count; i++)
- length += 1 + strlen(keyvalue[i][0]) +
- (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
+ 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;
+ }
/*
- * Allocate and fill it
+ * See if we already have it listed in the Printers list, and add it if not...
*/
- txtRecord = malloc(length);
- if (txtRecord)
+ 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)
{
- *txt_len = length;
+ /*
+ * Strip the common domain name components...
+ */
- for (cursor = txtRecord, i = 0; i < count; i++)
+ while (hptr != NULL)
{
- /*
- * Drop in the p-string style length byte followed by the data
- */
+ if (!strcasecmp(hptr, sptr))
+ {
+ *hptr = '\0';
+ break;
+ }
+ else
+ hptr = strchr(hptr + 1, '.');
+ }
+ }
- length = strlen(keyvalue[i][0]);
- length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
+ if (type & CUPS_PRINTER_CLASS)
+ {
+ /*
+ * Remote destination is a class...
+ */
- *cursor++ = (unsigned char)(length + length2);
+ if (!strncmp(resource, "/classes/", 9))
+ snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
+ else
+ return;
- memcpy(cursor, keyvalue[i][0], length);
- cursor += length;
+ if (hptr && !*hptr)
+ *hptr = '.'; /* Resource FQDN */
- if (length2)
+ if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
+ {
+ if ((p = cupsdFindDest(resource + 9)) != NULL)
{
- length2 --;
- *cursor++ = '=';
- memcpy(cursor, keyvalue[i][1], length2);
- cursor += length2;
+ 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
+ {
+ /*
+ * Use the short name for this shared class.
+ */
+
+ 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...
+ */
- return (txtRecord);
-}
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ update = 1;
+ }
+ if (!p)
+ {
+ /*
+ * Class doesn't exist; add it...
+ */
-/*
- * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
- */
+ p = cupsdAddClass(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 */
-{
- (void)context;
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote class \"%s\"...", name);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "dnssdRegisterCallback(%s, %s)", name, regtype);
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "Class \'%s\' added by directory services.", name);
- if (errorCode)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "DNSServiceRegister failed with error %d", (int)errorCode);
- return;
+ /*
+ * 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 */
-/*
- * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
- * or update the broadcast contents.
- */
+ if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
+ {
+ if ((p = cupsdFindDest(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...
+ */
-static void
-dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
-{
- DNSServiceErrorType se; /* dnssd errors */
- cupsd_listener_t *lis; /* Current listening socket */
- char *txt_record, /* TXT record buffer */
- *name; /* Service name */
- int txt_len, /* TXT record length */
- port; /* IPP port number */
- char resource[1024], /* Resource path for printer */
- str_buffer[1024];
- /* C-string buffer */
- const char *computerName; /* Computer name c-string ptr */
- 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 */
-#ifdef HAVE_COREFOUNDATION_H
- CFStringRef computerNameRef;/* Computer name CFString */
- CFStringEncoding nameEncoding; /* Computer name encoding */
- CFMutableStringRef shortNameRef; /* Mutable name string */
- CFIndex nameLength; /* Name string length */
-#else
- int nameLength; /* Name string length */
-#endif /* HAVE_COREFOUNDATION_H */
+ 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);
+
+ 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...
+ */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
- !p->dnssd_ipp_ref ? "new" : "update");
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ update = 1;
+ }
- /*
- * If per-printer sharing was just disabled make sure we're not
- * registered before returning.
- */
+ if (!p)
+ {
+ /*
+ * Printer doesn't exist; add it...
+ */
- if (!p->shared)
- {
- dnssdDeregisterPrinter(p);
- return;
- }
+ p = cupsdAddPrinter(name);
- /*
- * Get the computer name as a c-string...
- */
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "Printer \'%s\' added by directory services.", name);
-#ifdef HAVE_COREFOUNDATION_H
- computerName = NULL;
- if ((computerNameRef = SCDynamicStoreCopyComputerName(NULL, &nameEncoding)))
- if ((computerName = CFStringGetCStringPtr(computerNameRef,
- kCFStringEncodingUTF8)) == NULL)
- if (CFStringGetCString(computerNameRef, str_buffer, sizeof(str_buffer),
- kCFStringEncodingUTF8))
- computerName = str_buffer;
-#else
- computerName = ServerName;
-#endif /* HAVE_COREFOUNDATION_H */
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote printer \"%s\"...", name);
- /*
- * The registered name takes the form of "<printer-info> @ <computer name>"...
- */
+ /*
+ * Force the URI to point to the real server...
+ */
- name = NULL;
- if (computerName)
- cupsdSetStringf(&name, "%s @ %s",
- (p->info && strlen(p->info)) ? p->info : p->name,
- computerName);
- else
- cupsdSetString(&name, (p->info && strlen(p->info)) ? p->info : p->name);
+ p->type = type & ~CUPS_PRINTER_REJECTING;
+ p->accepting = 1;
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
-#ifdef HAVE_COREFOUNDATION_H
- if (computerNameRef)
- CFRelease(computerNameRef);
-#endif /* HAVE_COREFOUNDATION_H */
+ update = 1;
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ }
+ }
/*
- * If an existing printer was renamed, unregister it and start over...
+ * Update the state...
*/
- if (p->reg_name && strcmp(p->reg_name, name))
- dnssdDeregisterPrinter(p);
-
- txt_len = 0; /* anti-compiler-warning-code */
- txt_record = dnssdBuildTxtRecord(&txt_len, p);
+ p->state = state;
+ p->browse_time = time(NULL);
- if (!p->dnssd_ipp_ref)
+ if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
+ attrs)) != NULL)
{
/*
- * Initial registration...
+ * Grab the lease-duration for the browse data; anything less then 1
+ * second or more than 1 week gets the default BrowseTimeout...
*/
- cupsdSetString(&p->reg_name, name);
+ i = atoi(lease_duration);
+ if (i < 1 || i > 604800)
+ i = BrowseTimeout;
- port = ippPort();
+ p->browse_expire = p->browse_time + i;
+ }
+ else
+ p->browse_expire = p->browse_time + BrowseTimeout;
+
+ if (type & CUPS_PRINTER_REJECTING)
+ {
+ type &= ~CUPS_PRINTER_REJECTING;
- for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
- lis;
- lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ if (p->accepting)
{
- if (lis->address.addr.sa_family == AF_INET)
- {
- port = ntohs(lis->address.ipv4.sin_port);
- break;
- }
- else if (lis->address.addr.sa_family == AF_INET6)
- {
- port = ntohs(lis->address.ipv6.sin6_port);
- break;
- }
+ update = 1;
+ p->accepting = 0;
}
+ }
+ else if (!p->accepting)
+ {
+ update = 1;
+ p->accepting = 1;
+ }
- /*
- * If 'Allow printing from the Internet' is enabled (i.e. from any address)
- * let dnssd decide on the domain, otherwise restrict it to ".local".
- */
-
- if (p->type & CUPS_PRINTER_CLASS)
- snprintf(resource, sizeof(resource), "/classes/%s", p->name);
- else
- snprintf(resource, sizeof(resource), "/printers/%s", p->name);
+ if (p->type != type)
+ {
+ p->type = type;
+ update = 1;
+ }
- address[0] = address[1] = address[2] = address[3] = 0;
- location = cupsdFindBest(resource, HTTP_POST);
- policy = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
+ if (location && (!p->location || strcmp(p->location, location)))
+ {
+ cupsdSetString(&p->location, location);
+ update = 1;
+ }
- if ((location && !cupsdCheckAccess(address, "", 0, location)) ||
- (policy && !cupsdCheckAccess(address, "", 0, policy)))
- domain = "local.";
- else
- domain = NULL;
+ if (info && (!p->info || strcmp(p->info, info)))
+ {
+ cupsdSetString(&p->info, info);
+ update = 1;
- /*
- * Use the _fax subtype for fax queues...
- */
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ }
- regtype = (p->type & CUPS_PRINTER_FAX) ? dnssdIPPFaxRegType :
- dnssdIPPRegType;
+ 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;
+ }
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "dnssdRegisterPrinter(%s) type, domain is \"%s\", \"%s\"",
- p->name, regtype, domain ? domain : "(null)");
+ if (p->num_options)
+ {
+ if (!update && !(type & CUPS_PRINTER_DELETE))
+ {
+ /*
+ * See if we need to update the attributes...
+ */
- se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, name, regtype,
- domain, NULL, htons(port), txt_len, txt_record,
- dnssdRegisterCallback, p);
+ 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;
+ }
+ }
+ }
/*
- * In case the name is too long, try shortening the string one character
- * at a time...
+ * Free the old options...
*/
- if (se == kDNSServiceErr_BadParam)
- {
-#ifdef HAVE_COREFOUNDATION_H
- if ((shortNameRef = CFStringCreateMutable(NULL, 0)) != NULL)
- {
- CFStringAppendCString(shortNameRef, name, kCFStringEncodingUTF8);
- nameLength = CFStringGetLength(shortNameRef);
-
- while (se == kDNSServiceErr_BadParam && nameLength > 1)
- {
- CFStringDelete(shortNameRef, CFRangeMake(--nameLength, 1));
- if (CFStringGetCString(shortNameRef, str_buffer, sizeof(str_buffer),
- kCFStringEncodingUTF8))
- {
- se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer,
- regtype, NULL, NULL, htons(port),
- txt_len, txt_record,
- dnssdRegisterCallback, p);
- }
- }
+ cupsFreeOptions(p->num_options, p->options);
+ }
- CFRelease(shortNameRef);
- }
-#else
- nameLength = strlen(name);
- while (se == kDNSServiceErr_BadParam && nameLength > 1)
- {
- name[--nameLength] = '\0';
- se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer, regtype,
- NULL, NULL, htons(port), txt_len, txt_record,
- dnssdRegisterCallback, p);
- }
-#endif /* HAVE_COREFOUNDATION_H */
- }
+ p->num_options = num_attrs;
+ p->options = attrs;
- if (se == kDNSServiceErr_NoError)
- {
- p->dnssd_ipp_fd = DNSServiceRefSockFD(p->dnssd_ipp_ref);
- p->txt_record = txt_record;
- p->txt_len = txt_len;
- txt_record = NULL;
+ 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);
- cupsdAddSelect(p->dnssd_ipp_fd, (cupsd_selfunc_t)cupsdUpdateDNSSDBrowse,
- NULL, (void *)p);
- }
- else
- cupsdLogMessage(CUPSD_LOG_WARN,
- "DNS-SD registration of \"%s\" failed with %d",
- p->name, se);
+ cupsdExpireSubscriptions(p, NULL);
+
+ cupsdDeletePrinter(p, 1);
+ cupsdUpdateImplicitClasses();
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
}
- else if (txt_len != p->txt_len || memcmp(txt_record, p->txt_record, txt_len))
+ else if (update)
{
- /*
- * Update the existing registration...
- */
+ cupsdSetPrinterAttrs(p);
+ cupsdUpdateImplicitClasses();
+ }
- /* A TTL of 0 means use record's original value (Radar 3176248) */
- se = DNSServiceUpdateRecord(p->dnssd_ipp_ref, NULL, 0,
- txt_len, txt_record, 0);
+ /*
+ * See if we have a default printer... If not, make the first network
+ * default printer the default.
+ */
- if (p->txt_record)
- free(p->txt_record);
+ if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
+ {
+ /*
+ * Find the first network default printer and use it...
+ */
- p->txt_record = txt_record;
- p->txt_len = txt_len;
- txt_record = NULL;
+ 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;
+ }
}
- if (txt_record)
- free(txt_record);
+ /*
+ * Do auto-classing if needed...
+ */
- cupsdClearString(&name);
+ process_implicit_classes();
}
-#endif /* HAVE_DNSSD */
/*
*/
static void
-process_implicit_classes(
- int *write_printcap) /* O - Write printcap file? */
+process_implicit_classes(void)
{
int i; /* Looping var */
int update; /* Update printer attributes? */
update = 1;
- if (write_printcap)
- *write_printcap = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
name);
NULL
};
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s\n", p->name);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s", p->name);
/*
* Everything in ldap is ** so we fudge around it...
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
strerror(errno));
- cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
+ cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off.");
+
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
+
+ cupsdRemoveSelect(BrowseSocket);
+ BrowseSocket = -1;
- cupsdStopBrowsing();
- Browsing = 0;
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
}
return;
* Access from localhost (127.0.0.1) is always allowed...
*/
- auth = AUTH_ALLOW;
+ auth = CUPSD_AUTH_ALLOW;
}
else
{
switch (BrowseACL->order_type)
{
default :
- auth = AUTH_DENY; /* anti-compiler-warning-code */
+ auth = CUPSD_AUTH_DENY; /* anti-compiler-warning-code */
break;
- case AUTH_ALLOW : /* Order Deny,Allow */
- auth = AUTH_ALLOW;
+ case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
+ auth = CUPSD_AUTH_ALLOW;
if (cupsdCheckAuth(address, srcname, len,
BrowseACL->num_deny, BrowseACL->deny))
- auth = AUTH_DENY;
+ auth = CUPSD_AUTH_DENY;
if (cupsdCheckAuth(address, srcname, len,
BrowseACL->num_allow, BrowseACL->allow))
- auth = AUTH_ALLOW;
+ auth = CUPSD_AUTH_ALLOW;
break;
- case AUTH_DENY : /* Order Allow,Deny */
- auth = AUTH_DENY;
+ case CUPSD_AUTH_DENY : /* Order Allow,Deny */
+ auth = CUPSD_AUTH_DENY;
if (cupsdCheckAuth(address, srcname, len,
BrowseACL->num_allow, BrowseACL->allow))
- auth = AUTH_ALLOW;
+ auth = CUPSD_AUTH_ALLOW;
if (cupsdCheckAuth(address, srcname, len,
BrowseACL->num_deny, BrowseACL->deny))
- auth = AUTH_DENY;
+ auth = CUPSD_AUTH_DENY;
break;
}
}
}
else
- auth = AUTH_ALLOW;
+ auth = CUPSD_AUTH_ALLOW;
- if (auth == AUTH_DENY)
+ if (auth == CUPSD_AUTH_DENY)
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"update_cups_browse: Refused %d bytes from %s", bytes,
if (!LPDConfigFile)
return;
+#ifdef __APPLE__
+ /*
+ * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
+ * setting for backwards-compatibility.
+ */
+
+ if (onoff && !get_hostconfig("CUPS_LPD"))
+ onoff = 0;
+#endif /* __APPLE__ */
+
if (!strncmp(LPDConfigFile, "xinetd:///", 10))
{
/*
snprintf(line, sizeof(line), "\tdisable = %s",
onoff ? "no" : "yes");
}
- else if (strstr(line, "disable ="))
- continue;
-
- cupsFilePrintf(nfp, "%s\n", line);
+ else if (!strstr(line, "disable ="))
+ cupsFilePrintf(nfp, "%s\n", line);
}
cupsFileClose(nfp);
cupsFileClose(ofp);
rename(newfile, LPDConfigFile + 9);
}
+#ifdef __APPLE__
else if (!strncmp(LPDConfigFile, "launchd:///", 11))
{
/*
cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
NULL, &pid);
}
+#endif /* __APPLE__ */
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
}
cupsFileClose(ofp);
rename(newfile, SMBConfigFile + 8);
}
- else if (!strncmp(SMBConfigFile, "launchd:///", 11))
- {
- /*
- * Enable/disable SMB via the launchctl command...
- */
-
- char *argv[5], /* Arguments for command */
- *envp[MAX_ENV]; /* Environment for command */
- int pid; /* Process ID */
-
-
- cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
- argv[0] = (char *)"launchctl";
- argv[1] = (char *)(onoff ? "load" : "unload");
- argv[2] = (char *)"-w";
- argv[3] = SMBConfigFile + 10;
- argv[4] = NULL;
-
- cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
- NULL, &pid);
- }
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
}
/*
- * End of "$Id: dirsvc.c 7003 2007-10-01 23:10:13Z mike $".
+ * End of "$Id: dirsvc.c 7676 2008-06-18 23:42:37Z mike $".
*/