#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
# ifdef HAVE_SYSTEMCONFIGURATION
# include <SystemConfiguration/SystemConfiguration.h>
# endif
# endif
#endif
static char *dequote(char *d, const char *s, int dlen);
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,
const char *resource, cups_ptype_t type,
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 send_cups_browse(cupsd_printer_t *p);
#ifdef HAVE_LDAP
static void send_ldap_browse(cupsd_printer_t *p);
#endif
#ifdef HAVE_LIBSLP
static void send_slp_browse(cupsd_printer_t *p);
#endif
static void update_cups_browse(void);
static void update_polling(void);
#ifdef HAVE_OPENLDAP
static const char * const ldap_attrs[] =
{
"printerDescription",
"printerLocation",
"printerMakeAndModel",
"printerType",
"printerURI",
NULL
};
#endif
#ifdef HAVE_LIBSLP
# define SLP_CUPS_SRVTYPE "service:printer"
# define SLP_CUPS_SRVLEN 15
typedef struct _slpsrvurl_s
{
struct _slpsrvurl_s *next;
char url[HTTP_MAX_URI];
} slpsrvurl_t;
static SLPBoolean slp_attr_callback(SLPHandle hslp, const char *attrlist,
SLPError errcode, void *cookie);
static void slp_dereg_printer(cupsd_printer_t *p);
static int slp_get_attr(const char *attrlist, const char *tag,
char **valbuf);
static void slp_reg_callback(SLPHandle hslp, SLPError errcode,
void *cookie);
static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl,
unsigned short lifetime,
SLPError errcode, void *cookie);
#endif
#ifdef HAVE_DNSSD
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
void
cupsdDeregisterPrinter(
cupsd_printer_t *p,
int removeit)
{
if (!Browsing || !p->shared ||
(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
return;
if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
{
cups_ptype_t savedtype = p->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
#ifdef HAVE_DNSSD
if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD))
dnssdDeregisterPrinter(p);
#endif
}
void
cupsdLoadRemoteCache(void)
{
cups_file_t *fp;
int linenum;
char line[1024],
*value,
*valueptr,
scheme[32],
username[64],
host[HTTP_MAX_HOST],
resource[HTTP_MAX_URI];
int port;
cupsd_printer_t *p;
time_t now;
if (!Browsing || !(BrowseRemoteProtocols & BROWSE_CUPS))
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"cupsdLoadRemoteCache: Not loading remote cache.");
return;
}
snprintf(line, sizeof(line), "%s/remote.cache", CacheDir);
if ((fp = cupsFileOpen(line, "r")) == NULL)
return;
linenum = 0;
p = NULL;
now = time(NULL);
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
{
if (!strcasecmp(line, "<Printer") ||
!strcasecmp(line, "<DefaultPrinter"))
{
if (p == NULL && value)
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"cupsdLoadRemoteCache: Loading printer %s...", value);
if ((p = cupsdFindDest(value)) != NULL)
{
if (p->type & CUPS_PRINTER_CLASS)
{
cupsdLogMessage(CUPSD_LOG_WARN,
"Cached remote printer \"%s\" conflicts with "
"existing class!",
value);
p = NULL;
continue;
}
}
else
p = cupsdAddPrinter(value);
p->accepting = 1;
p->state = IPP_PRINTER_IDLE;
p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
p->browse_time = now;
p->browse_expire = now + BrowseTimeout;
if (!strcasecmp(line, "<DefaultPrinter"))
DefaultPrinter = p;
}
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
}
else if (!strcasecmp(line, "<Class") ||
!strcasecmp(line, "<DefaultClass"))
{
if (p == NULL && value)
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"cupsdLoadRemoteCache: Loading class %s...", value);
if ((p = cupsdFindDest(value)) != NULL)
p->type = CUPS_PRINTER_CLASS;
else
p = cupsdAddClass(value);
p->accepting = 1;
p->state = IPP_PRINTER_IDLE;
p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
p->browse_time = now;
p->browse_expire = now + BrowseTimeout;
if (!strcasecmp(line, "<DefaultClass"))
DefaultPrinter = p;
}
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
}
else if (!strcasecmp(line, "</Printer>") ||
!strcasecmp(line, "</Class>"))
{
if (p != NULL)
{
cupsdSetPrinterAttrs(p);
p = NULL;
}
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
}
else if (!p)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
else if (!strcasecmp(line, "Info"))
{
if (value)
cupsdSetString(&p->info, value);
}
else if (!strcasecmp(line, "MakeModel"))
{
if (value)
cupsdSetString(&p->make_model, value);
}
else if (!strcasecmp(line, "Location"))
{
if (value)
cupsdSetString(&p->location, value);
}
else if (!strcasecmp(line, "DeviceURI"))
{
if (value)
{
httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme),
username, sizeof(username), host, sizeof(host), &port,
resource, sizeof(resource));
cupsdSetString(&p->hostname, host);
cupsdSetString(&p->uri, value);
cupsdSetString(&p->device_uri, value);
}
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
}
else if (!strcasecmp(line, "Option") && value)
{
for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
if (!*valueptr)
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
else
{
for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
p->num_options = cupsAddOption(value, valueptr, p->num_options,
&(p->options));
}
}
else if (!strcasecmp(line, "State"))
{
if (value && !strcasecmp(value, "idle"))
p->state = IPP_PRINTER_IDLE;
else if (value && !strcasecmp(value, "stopped"))
p->state = IPP_PRINTER_STOPPED;
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
}
else if (!strcasecmp(line, "StateMessage"))
{
if (value)
strlcpy(p->state_message, value, sizeof(p->state_message));
}
else if (!strcasecmp(line, "Accepting"))
{
if (value &&
(!strcasecmp(value, "yes") ||
!strcasecmp(value, "on") ||
!strcasecmp(value, "true")))
p->accepting = 1;
else if (value &&
(!strcasecmp(value, "no") ||
!strcasecmp(value, "off") ||
!strcasecmp(value, "false")))
p->accepting = 0;
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
}
else if (!strcasecmp(line, "Type"))
{
if (value)
p->type = atoi(value);
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
}
else if (!strcasecmp(line, "BrowseTime"))
{
if (value)
{
time_t t = atoi(value);
if (t > p->browse_expire)
p->browse_expire = t;
}
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
}
else if (!strcasecmp(line, "JobSheets"))
{
if (value)
{
for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
if (*valueptr)
*valueptr++ = '\0';
cupsdSetString(&p->job_sheets[0], value);
while (isspace(*valueptr & 255))
valueptr ++;
if (*valueptr)
{
for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
if (*valueptr)
*valueptr = '\0';
cupsdSetString(&p->job_sheets[1], value);
}
}
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
}
else if (!strcasecmp(line, "AllowUser"))
{
if (value)
{
p->deny_users = 0;
cupsdAddPrinterUser(p, value);
}
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
}
else if (!strcasecmp(line, "DenyUser"))
{
if (value)
{
p->deny_users = 1;
cupsdAddPrinterUser(p, value);
}
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
break;
}
}
else
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unknown configuration directive %s on line %d of remote.cache.",
line, linenum);
}
}
cupsFileClose(fp);
process_implicit_classes(NULL);
}
void
cupsdRegisterPrinter(cupsd_printer_t *p)
{
if (!Browsing || !BrowseLocalProtocols || !BrowseInterval || !NumBrowsers ||
(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
return;
#ifdef HAVE_LIBSLP
#endif
#ifdef HAVE_DNSSD
if (BrowseLocalProtocols & BROWSE_DNSSD)
dnssdRegisterPrinter(p);
#endif
}
void
cupsdRestartPolling(void)
{
int i;
cupsd_dirsvc_poll_t *pollp;
for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
if (pollp->pid)
kill(pollp->pid, SIGHUP);
}
void
cupsdSaveRemoteCache(void)
{
int i;
cups_file_t *fp;
char temp[1024];
cupsd_printer_t *printer;
time_t curtime;
struct tm *curdate;
cups_option_t *option;
snprintf(temp, sizeof(temp), "%s/remote.cache", CacheDir);
if ((fp = cupsFileOpen(temp, "w")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to save remote.cache - %s", strerror(errno));
return;
}
else
cupsdLogMessage(CUPSD_LOG_DEBUG, "Saving remote.cache...");
fchown(cupsFileNumber(fp), getuid(), Group);
fchmod(cupsFileNumber(fp), ConfigFilePerm);
curtime = time(NULL);
curdate = localtime(&curtime);
strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n");
cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
printer;
printer = (cupsd_printer_t *)cupsArrayNext(Printers))
{
if (!(printer->type & CUPS_PRINTER_DISCOVERED))
continue;
if (printer == DefaultPrinter)
cupsFilePuts(fp, "<Default");
else
cupsFilePutChar(fp, '<');
if (printer->type & CUPS_PRINTER_CLASS)
cupsFilePrintf(fp, "Class %s>\n", printer->name);
else
cupsFilePrintf(fp, "Printer %s>\n", printer->name);
cupsFilePrintf(fp, "Type %d\n", printer->type);
cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_expire);
if (printer->info)
cupsFilePrintf(fp, "Info %s\n", printer->info);
if (printer->make_model)
cupsFilePrintf(fp, "MakeModel %s\n", printer->make_model);
if (printer->location)
cupsFilePrintf(fp, "Location %s\n", printer->location);
if (printer->device_uri)
cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
if (printer->state == IPP_PRINTER_STOPPED)
{
cupsFilePuts(fp, "State Stopped\n");
cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message);
}
else
cupsFilePuts(fp, "State Idle\n");
if (printer->accepting)
cupsFilePuts(fp, "Accepting Yes\n");
else
cupsFilePuts(fp, "Accepting No\n");
cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
printer->job_sheets[1]);
for (i = 0; i < printer->num_users; i ++)
cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
printer->users[i]);
for (i = printer->num_options, option = printer->options;
i > 0;
i --, option ++)
cupsFilePrintf(fp, "Option %s %s\n", option->name, option->value);
if (printer->type & CUPS_PRINTER_CLASS)
cupsFilePuts(fp, "</Class>\n");
else
cupsFilePuts(fp, "</Printer>\n");
}
cupsFileClose(fp);
}
void
cupsdSendBrowseList(void)
{
int count;
cupsd_printer_t *p;
time_t ut,
to;
int write_printcap;
if (!Browsing || !Printers)
return;
to = time(NULL);
ut = to - BrowseInterval;
if (BrowseInterval > 0 && BrowseLocalProtocols)
{
int max_count;
max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1;
for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers);
count < max_count && p != NULL;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
p->shared && p->browse_time < ut)
count ++;
if (BrowseNext)
p = (cupsd_printer_t *)cupsArrayFind(Printers, BrowseNext);
else
p = (cupsd_printer_t *)cupsArrayFirst(Printers);
for (;
count > 0;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
{
if (!p)
p = (cupsd_printer_t *)cupsArrayFirst(Printers);
if (!p)
break;
else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) ||
!p->shared)
continue;
else if (p->browse_time < ut)
{
count --;
p->browse_time = time(NULL);
if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
send_cups_browse(p);
#ifdef HAVE_LIBSLP
if (BrowseLocalProtocols & BROWSE_SLP)
send_slp_browse(p);
#endif
#ifdef HAVE_LDAP
if (BrowseLocalProtocols & BROWSE_LDAP)
send_ldap_browse(p);
#endif
}
}
BrowseNext = p;
}
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), write_printcap = 0;
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
{
if ((p->type & CUPS_PRINTER_DISCOVERED) &&
!(p->type & CUPS_PRINTER_IMPLICIT) &&
p->browse_expire < to)
{
cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
"%s \'%s\' deleted by directory services (timeout).",
(p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
p->name);
cupsdLogMessage(CUPSD_LOG_DEBUG,
"Remote destination \"%s\" has timed out; "
"deleting it...",
p->name);
cupsArraySave(Printers);
cupsdDeletePrinter(p, 1);
cupsArrayRestore(Printers);
write_printcap = 1;
}
}
if (write_printcap)
cupsdWritePrintcap();
}
void
cupsdStartBrowsing(void)
{
int val;
struct sockaddr_in addr;
cupsd_printer_t *p;
BrowseNext = NULL;
if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
return;
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
{
if (BrowseSocket < 0)
{
if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to create broadcast socket - %s.",
strerror(errno));
BrowseLocalProtocols &= ~BROWSE_CUPS;
BrowseRemoteProtocols &= ~BROWSE_CUPS;
return;
}
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_family = AF_INET;
addr.sin_port = htons(BrowsePort);
if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to bind broadcast socket - %s.",
strerror(errno));
#ifdef WIN32
closesocket(BrowseSocket);
#else
close(BrowseSocket);
#endif
BrowseSocket = -1;
BrowseLocalProtocols &= ~BROWSE_CUPS;
BrowseRemoteProtocols &= ~BROWSE_CUPS;
return;
}
}
val = 1;
if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
strerror(errno));
#ifdef WIN32
closesocket(BrowseSocket);
#else
close(BrowseSocket);
#endif
BrowseSocket = -1;
BrowseLocalProtocols &= ~BROWSE_CUPS;
BrowseRemoteProtocols &= ~BROWSE_CUPS;
return;
}
fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
if (BrowseRemoteProtocols & BROWSE_CUPS)
{
cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
NULL, NULL);
}
}
else
BrowseSocket = -1;
#ifdef HAVE_LIBSLP
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
{
if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to open an SLP handle; disabling SLP browsing!");
BrowseLocalProtocols &= ~BROWSE_SLP;
BrowseRemoteProtocols &= ~BROWSE_SLP;
}
BrowseSLPRefresh = 0;
}
else
BrowseSLPHandle = NULL;
#endif
#ifdef HAVE_OPENLDAP
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
{
if (!BrowseLDAPDN)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Need to set BrowseLDAPDN to use LDAP browsing!");
BrowseLocalProtocols &= ~BROWSE_LDAP;
BrowseRemoteProtocols &= ~BROWSE_LDAP;
}
else
{
int rc;
int version = 3;
struct berval bv = {0, ""};
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));
}
if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
rc = ldap_initialize(&BrowseLDAPHandle, "ldapi:///");
else
rc = ldap_initialize(&BrowseLDAPHandle, BrowseLDAPServer);
if (rc != LDAP_SUCCESS)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to initialize LDAP; disabling LDAP browsing!");
BrowseLocalProtocols &= ~BROWSE_LDAP;
BrowseRemoteProtocols &= ~BROWSE_LDAP;
}
else if (ldap_set_option(BrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
(const void *)&version) != LDAP_SUCCESS)
{
ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
BrowseLDAPHandle = NULL;
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to set LDAP protocol version; "
"disabling LDAP browsing!");
BrowseLocalProtocols &= ~BROWSE_LDAP;
BrowseRemoteProtocols &= ~BROWSE_LDAP;
}
else
{
if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
rc = ldap_sasl_bind_s(BrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
NULL, NULL);
else
rc = ldap_bind_s(BrowseLDAPHandle, BrowseLDAPBindDN,
BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
if (rc != LDAP_SUCCESS)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to bind to LDAP server; "
"disabling LDAP browsing!");
ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
BrowseLocalProtocols &= ~BROWSE_LDAP;
BrowseRemoteProtocols &= ~BROWSE_LDAP;
}
}
}
BrowseLDAPRefresh = 0;
}
#endif
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);
}
void
cupsdStartPolling(void)
{
int i;
cupsd_dirsvc_poll_t *pollp;
char polld[1024];
char sport[255];
char bport[255];
char interval[255];
int statusfds[2];
char *argv[6];
char *envp[100];
if (NumPolled == 0 || BrowseSocket < 0)
{
PollPipe = -1;
PollStatusBuffer = NULL;
return;
}
snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
sprintf(bport, "%d", BrowsePort);
if (BrowseInterval)
sprintf(interval, "%d", BrowseInterval);
else
strcpy(interval, "30");
argv[0] = "cups-polld";
argv[2] = sport;
argv[3] = interval;
argv[4] = bport;
argv[5] = NULL;
cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
if (cupsdOpenPipe(statusfds))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to create polling status pipes - %s.",
strerror(errno));
PollPipe = -1;
PollStatusBuffer = NULL;
return;
}
PollPipe = statusfds[0];
PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
{
sprintf(sport, "%d", pollp->port);
argv[1] = pollp->hostname;
if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
0, &(pollp->pid)) < 0)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"cupsdStartPolling: Unable to fork polling daemon - %s",
strerror(errno));
pollp->pid = 0;
break;
}
else
cupsdLogMessage(CUPSD_LOG_DEBUG,
"cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
pollp->hostname, pollp->port, pollp->pid);
}
close(statusfds[1]);
cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
}
void
cupsdStopBrowsing(void)
{
cupsd_printer_t *p;
if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
return;
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);
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
BrowseSocket >= 0)
{
#ifdef WIN32
closesocket(BrowseSocket);
#else
close(BrowseSocket);
#endif
cupsdRemoveSelect(BrowseSocket);
BrowseSocket = -1;
}
#ifdef HAVE_LIBSLP
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
BrowseSLPHandle)
{
SLPClose(BrowseSLPHandle);
BrowseSLPHandle = NULL;
}
#endif
#ifdef HAVE_OPENLDAP
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
BrowseLDAPHandle)
{
ldap_unbind(BrowseLDAPHandle);
BrowseLDAPHandle = NULL;
}
#endif
}
void
cupsdStopPolling(void)
{
int i;
cupsd_dirsvc_poll_t *pollp;
if (PollPipe >= 0)
{
cupsdStatBufDelete(PollStatusBuffer);
close(PollPipe);
cupsdRemoveSelect(PollPipe);
PollPipe = -1;
PollStatusBuffer = NULL;
}
for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
if (pollp->pid)
cupsdEndProcess(pollp->pid, 0);
}
#ifdef HAVE_DNSSD
void
cupsdUpdateDNSSDBrowse(
cupsd_printer_t *p)
{
DNSServiceErrorType sdErr;
if ((sdErr = DNSServiceProcessResult(p->dnssd_ipp_ref))
!= kDNSServiceErr_NoError)
{
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);
p->dnssd_ipp_ref = NULL;
p->dnssd_ipp_fd = -1;
}
}
#endif
#ifdef HAVE_OPENLDAP
void
cupsdUpdateLDAPBrowse(void)
{
char uri[HTTP_MAX_URI],
host[HTTP_MAX_URI],
resource[HTTP_MAX_URI],
location[1024],
info[1024],
make_model[1024],
**value;
int type;
int rc;
int limit;
LDAPMessage *res,
*e;
cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
BrowseLDAPRefresh = time(NULL) + BrowseInterval;
rc = ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
"(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
if (rc != LDAP_SUCCESS)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"LDAP search returned error %d: %s", rc,
ldap_err2string(rc));
return;
}
limit = ldap_count_entries(BrowseLDAPHandle, res);
cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
if (limit < 1)
return;
for (e = ldap_first_entry(BrowseLDAPHandle, res);
e;
e = ldap_next_entry(BrowseLDAPHandle, e))
{
if ((value = ldap_get_values(BrowseLDAPHandle, e,
"printerDescription")) == NULL)
continue;
strlcpy(info, *value, sizeof(info));
ldap_value_free(value);
if ((value = ldap_get_values(BrowseLDAPHandle, e,
"printerLocation")) == NULL)
continue;
strlcpy(location, *value, sizeof(location));
ldap_value_free(value);
if ((value = ldap_get_values(BrowseLDAPHandle, e,
"printerMakeAndModel")) == NULL)
continue;
strlcpy(make_model, *value, sizeof(make_model));
ldap_value_free(value);
if ((value = ldap_get_values(BrowseLDAPHandle, e,
"printerType")) == NULL)
continue;
type = atoi(*value);
ldap_value_free(value);
if ((value = ldap_get_values(BrowseLDAPHandle, e,
"printerURI")) == NULL)
continue;
strlcpy(uri, *value, sizeof(uri));
ldap_value_free(value);
if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
location, info, make_model, 0, NULL);
}
}
#endif
#ifdef HAVE_LIBSLP
void
cupsdUpdateSLPBrowse(void)
{
slpsrvurl_t *s,
*next;
cupsd_printer_t p;
const char *uri;
char host[HTTP_MAX_URI],
resource[HTTP_MAX_URI];
BrowseSLPRefresh = time(NULL) + BrowseInterval;
s = NULL;
SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
slp_url_callback, &s);
for (; s; s = next)
{
next = s->next;
SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
uri = s->url + SLP_CUPS_SRVLEN + 1;
if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
{
if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE,
p.location, p.info, p.make_model, 0, NULL);
}
cupsdClearString(&p.info);
cupsdClearString(&p.location);
cupsdClearString(&p.make_model);
free(s);
}
}
#endif
static char *
dequote(char *d,
const char *s,
int dlen)
{
char *dptr;
if (s)
{
for (dptr = d, dlen --; *s && dlen > 0; s ++)
if (*s != '\"')
{
*dptr++ = *s;
dlen --;
}
*dptr = '\0';
}
else
*d = '\0';
return (d);
}
static int
is_local_queue(const char *uri,
char *host,
int hostlen,
char *resource,
int resourcelen)
{
char scheme[32],
username[HTTP_MAX_URI];
int port;
cupsd_netif_t *iface;
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));
if (!strcasecmp(host, ServerName) && port == LocalPort)
return (1);
cupsdNetIFUpdate();
for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
iface;
iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
if (!strcasecmp(host, iface->hostname) && port == iface->port)
return (1);
return (0);
}
static void
process_browse_data(
const char *uri,
const char *host,
const char *resource,
cups_ptype_t type,
ipp_pstate_t state,
const char *location,
const char *info,
const char *make_model,
int num_attrs,
cups_option_t *attrs)
{
int i;
int update,
write_printcap;
char finaluri[HTTP_MAX_URI],
name[IPP_MAX_NAME],
newname[IPP_MAX_NAME],
*hptr,
*sptr;
const char *shortname;
char local_make_model[IPP_MAX_NAME];
cupsd_printer_t *p;
const char *ipp_options,
*lease_duration;
int is_class;
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"process_browse_data(uri=\"%s\", host=\"%s\", "
"resource=\"%s\", type=%x, state=%d, location=\"%s\", "
"info=\"%s\", make_model=\"%s\", num_attrs=%d, attrs=%p)",
uri, host, resource, type, state,
location ? location : "(nil)", info ? info : "(nil)",
make_model ? make_model : "(nil)", num_attrs, attrs);
if (strncmp(uri, "ipp://", 6) || !host[0] ||
(strncmp(resource, "/printers/", 10) &&
strncmp(resource, "/classes/", 9)))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Bad printer URI in browse data: %s", uri);
return;
}
if (strchr(resource, '?') ||
(!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
(!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Bad resource in browse data: %s",
resource);
return;
}
ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
if (BrowseRemoteOptions)
{
if (BrowseRemoteOptions[0] == '?')
{
snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
}
else if (ipp_options)
{
snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
BrowseRemoteOptions);
}
else
{
snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
}
uri = finaluri;
}
else if (ipp_options)
{
snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
uri = finaluri;
}
type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
type &= ~CUPS_PRINTER_IMPLICIT;
update = 0;
write_printcap = 0;
hptr = strchr(host, '.');
sptr = strchr(ServerName, '.');
is_class = type & CUPS_PRINTER_CLASS;
if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
{
while (hptr != NULL)
{
if (!strcasecmp(hptr, sptr))
{
*hptr = '\0';
break;
}
else
hptr = strchr(hptr + 1, '.');
}
}
if (is_class)
{
if (!strncmp(resource, "/classes/", 9))
snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
else
return;
shortname = resource + 9;
}
else
{
if (!strncmp(resource, "/printers/", 10))
snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
else
return;
shortname = resource + 10;
}
if (hptr && !*hptr)
*hptr = '.';
if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "process_browse_data: %s not found...",
name);
if ((p = cupsdFindDest(shortname)) == NULL)
{
cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_browse_data: %s not found...",
shortname);
strlcpy(name, shortname, sizeof(name));
}
else
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"process_browse_data: %s found, type=%x, hostname=%s...",
shortname, p->type, p->hostname ? p->hostname : "(nil)");
if (p->type & CUPS_PRINTER_IMPLICIT)
p = NULL;
else if (p->hostname && strcasecmp(p->hostname, host))
{
if (p->type & CUPS_PRINTER_REMOTE)
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"Renamed remote %s \"%s\" to \"%s@%s\"...",
is_class ? "class" : "printer", p->name, p->name,
p->hostname);
cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
"%s \'%s\' deleted by directory services.",
is_class ? "Class" : "Printer", p->name);
snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
cupsdRenamePrinter(p, newname);
cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
"%s \'%s\' added by directory services.",
is_class ? "Class" : "Printer", p->name);
}
p = NULL;
}
}
}
else if (p)
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"process_browse_data: %s found, type=%x, hostname=%s...",
name, p->type, p->hostname ? p->hostname : "(nil)");
if (!p)
{
if (is_class)
p = cupsdAddClass(name);
else
p = cupsdAddPrinter(name);
cupsdClearString(&(p->hostname));
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote %s \"%s\"...",
is_class ? "class" : "printer", name);
cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
"%s \'%s\' added by directory services.",
is_class ? "Class" : "Printer", name);
p->type = type & ~CUPS_PRINTER_REJECTING;
p->accepting = 1;
write_printcap = 1;
}
if (!p)
return;
if (!p->hostname)
{
cupsdSetString(&p->hostname, host);
cupsdSetString(&p->uri, uri);
cupsdSetString(&p->device_uri, uri);
update = 1;
}
p->state = state;
p->browse_time = time(NULL);
if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
attrs)) != NULL)
{
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;
write_printcap = 1;
}
if (!make_model || !make_model[0])
{
if (is_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))
{
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;
}
}
}
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.",
is_class ? "Class" : "Printer", p->name);
cupsdExpireSubscriptions(p, NULL);
cupsdDeletePrinter(p, 1);
cupsdUpdateImplicitClasses();
write_printcap = 1;
}
else if (update)
{
cupsdSetPrinterAttrs(p);
cupsdUpdateImplicitClasses();
}
if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
{
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;
}
}
process_implicit_classes(&write_printcap);
if (write_printcap)
cupsdWritePrintcap();
}
#ifdef HAVE_DNSSD
static char *
dnssdBuildTxtRecord(
int *txt_len,
cupsd_printer_t *p)
{
int i, j;
char type_str[32],
state_str[32],
rp_str[1024],
air_str[1024],
*keyvalue[32][2];
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')
{
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";
keyvalue[i ][0] = "Binary";
keyvalue[i++][1] = "T";
if ((p->type & CUPS_PRINTER_FAX))
{
keyvalue[i ][0] = "Fax";
keyvalue[i++][1] = "T";
}
if ((p->type & CUPS_PRINTER_COLOR))
{
keyvalue[i ][0] = "Color";
keyvalue[i++][1] = "T";
}
if ((p->type & CUPS_PRINTER_DUPLEX))
{
keyvalue[i ][0] = "Duplex";
keyvalue[i++][1] = "T";
}
if ((p->type & CUPS_PRINTER_STAPLE))
{
keyvalue[i ][0] = "Staple";
keyvalue[i++][1] = "T";
}
if ((p->type & CUPS_PRINTER_COPIES))
{
keyvalue[i ][0] = "Copies";
keyvalue[i++][1] = "T";
}
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";
}
if ((p->type & CUPS_PRINTER_BIND))
{
keyvalue[i ][0] = "Bind";
keyvalue[i++][1] = "T";
}
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";
if (p->num_auth_info_required)
{
char *air = air_str;
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;
}
return (dnssdPackTxtRecord(txt_len, keyvalue, i));
}
static void
dnssdDeregisterPrinter(
cupsd_printer_t *p)
{
cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
if (p->dnssd_ipp_ref)
{
cupsdRemoveSelect(p->dnssd_ipp_fd);
DNSServiceRefDeallocate(p->dnssd_ipp_ref);
p->dnssd_ipp_ref = NULL;
p->dnssd_ipp_fd = -1;
}
cupsdClearString(&p->reg_name);
if (p->txt_record)
{
free(p->txt_record);
p->txt_record = NULL;
}
}
static char *
dnssdPackTxtRecord(int *txt_len,
char *keyvalue[][2],
int count)
{
int i;
int length;
int length2;
char *txtRecord;
char *cursor;
for (length = i = 0; i < count; i++)
length += 1 + strlen(keyvalue[i][0]) +
(keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
txtRecord = malloc(length);
if (txtRecord)
{
*txt_len = length;
for (cursor = txtRecord, i = 0; i < count; i++)
{
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;
}
}
}
return (txtRecord);
}
static void
dnssdRegisterCallback(
DNSServiceRef sdRef,
DNSServiceFlags flags,
DNSServiceErrorType errorCode,
const char *name,
const char *regtype,
const char *domain,
void *context)
{
(void)context;
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"dnssdRegisterCallback(%s, %s)", name, regtype);
if (errorCode)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"DNSServiceRegister failed with error %d", (int)errorCode);
return;
}
}
static void
dnssdRegisterPrinter(cupsd_printer_t *p)
{
DNSServiceErrorType se;
cupsd_listener_t *lis;
char *txt_record,
*name;
int txt_len,
port;
char str_buffer[1024];
const char *computerName;
const char *regtype;
#ifdef HAVE_COREFOUNDATION_H
CFStringRef computerNameRef;
CFStringEncoding nameEncoding;
CFMutableStringRef shortNameRef;
CFIndex nameLength;
#else
int nameLength;
#endif
cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
!p->dnssd_ipp_ref ? "new" : "update");
if (!p->shared)
{
dnssdDeregisterPrinter(p);
return;
}
#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
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);
#ifdef HAVE_COREFOUNDATION_H
if (computerNameRef)
CFRelease(computerNameRef);
#endif
if (p->reg_name && strcmp(p->reg_name, name))
dnssdDeregisterPrinter(p);
txt_len = 0;
txt_record = dnssdBuildTxtRecord(&txt_len, p);
if (!p->dnssd_ipp_ref)
{
cupsdSetString(&p->reg_name, name);
port = ippPort();
for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
lis;
lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
{
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;
}
}
regtype = (p->type & CUPS_PRINTER_FAX) ? dnssdIPPFaxRegType :
dnssdIPPRegType;
cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) type is \"%s\"",
p->name, regtype);
se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, name, regtype,
NULL, NULL, htons(port), txt_len, txt_record,
dnssdRegisterCallback, p);
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);
}
}
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
}
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;
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);
}
else if (txt_len != p->txt_len || memcmp(txt_record, p->txt_record, txt_len))
{
DNSServiceUpdateRecord(p->dnssd_ipp_ref, NULL, 0, txt_len, txt_record, 0);
if (p->txt_record)
free(p->txt_record);
p->txt_record = txt_record;
p->txt_len = txt_len;
txt_record = NULL;
}
if (txt_record)
free(txt_record);
cupsdClearString(&name);
}
#endif
static void
process_implicit_classes(
int *write_printcap)
{
int i;
int update;
char name[IPP_MAX_NAME],
*hptr;
cupsd_printer_t *p,
*pclass,
*first;
int offset,
len;
if (!ImplicitClasses || !Printers)
return;
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 (p->type & CUPS_PRINTER_IMPLICIT)
{
len = 0;
continue;
}
cupsArraySave(Printers);
if (len > 0 &&
!strncasecmp(p->name, name + offset, len) &&
(p->name[len] == '\0' || p->name[len] == '@'))
{
if (pclass && strcasecmp(pclass->name, name))
{
if (update)
cupsdSetPrinterAttrs(pclass);
update = 0;
pclass = NULL;
}
if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
{
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;
if (write_printcap)
*write_printcap = 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 (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
{
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))
{
if (ImplicitAnyClasses && len < (sizeof(name) - 4))
{
strcpy(name, "Any");
strncpy(name + 3, p->name, len);
name[len + 3] = '\0';
offset = 3;
}
else
{
len = 0;
cupsArrayRestore(Printers);
continue;
}
}
first = p;
}
cupsArrayRestore(Printers);
}
if (pclass && update)
cupsdSetPrinterAttrs(pclass);
}
static void
send_cups_browse(cupsd_printer_t *p)
{
int i;
cups_ptype_t type;
cupsd_dirsvc_addr_t *b;
int bytes;
char packet[1453],
uri[1024],
location[1024],
info[1024],
make_model[1024];
cupsd_netif_t *iface;
type = p->type | CUPS_PRINTER_REMOTE;
if (!p->accepting)
type |= CUPS_PRINTER_REJECTING;
if (p == DefaultPrinter)
type |= CUPS_PRINTER_DEFAULT;
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));
for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
if (b->iface[0])
{
if (!strcmp(b->iface, "*"))
{
cupsdNetIFUpdate();
for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
iface;
iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
{
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)
{
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
{
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)
{
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
static void
send_ldap_browse(cupsd_printer_t *p)
{
int i;
LDAPMod mods[7];
LDAPMod *pmods[8];
LDAPMessage *res;
char *cn_value[2],
*uri[2],
*info[2],
*location[2],
*make_model[2],
*type[2],
typestring[255],
filter[256],
dn[1024];
int rc;
static const char * const objectClass_values[] =
{
"top",
"device",
"cupsPrinter",
NULL
};
cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s\n", p->name);
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)
{
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
{
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
#ifdef HAVE_LIBSLP
static void
send_slp_browse(cupsd_printer_t *p)
{
char srvurl[HTTP_MAX_URI],
attrs[8192],
finishings[1024],
make_model[IPP_MAX_NAME * 2],
location[IPP_MAX_NAME * 2],
info[IPP_MAX_NAME * 2],
*src,
*dst;
ipp_attribute_t *authentication;
SLPError error;
cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
p->name);
snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
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");
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");
authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
IPP_TAG_KEYWORD);
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
"(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);
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);
}
static SLPBoolean
slp_attr_callback(
SLPHandle hslp,
const char *attrlist,
SLPError errcode,
void *cookie)
{
char *tmp = 0;
cupsd_printer_t *p = (cupsd_printer_t*)cookie;
(void)hslp;
if (errcode != SLP_OK)
return (SLP_TRUE);
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);
}
static void
slp_dereg_printer(cupsd_printer_t *p)
{
char srvurl[HTTP_MAX_URI];
cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
if (!(p->type & CUPS_PRINTER_REMOTE))
{
snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
}
}
static int
slp_get_attr(const char *attrlist,
const char *tag,
char **valbuf)
{
char *ptr1,
*ptr2;
cupsdClearString(valbuf);
if ((ptr1 = strstr(attrlist, tag)) != NULL)
{
ptr1 += strlen(tag);
if ((ptr2 = strchr(ptr1,')')) != NULL)
{
*valbuf = calloc(ptr2 - ptr1 + 1, 1);
strncpy(*valbuf, ptr1, ptr2 - ptr1);
for (ptr1 = *valbuf; *ptr1; ptr1 ++)
if (*ptr1 == '\\' && ptr1[1])
_cups_strcpy(ptr1, ptr1 + 1);
return (0);
}
}
return (-1);
}
static void
slp_reg_callback(SLPHandle hslp,
SLPError errcode,
void *cookie)
{
(void)hslp;
(void)errcode;
(void)cookie;
return;
}
static SLPBoolean
slp_url_callback(
SLPHandle hslp,
const char *srvurl,
unsigned short lifetime,
SLPError errcode,
void *cookie)
{
slpsrvurl_t *s,
**head;
(void)hslp;
(void)lifetime;
if (errcode != SLP_OK)
return (SLP_TRUE);
head = (slpsrvurl_t**)cookie;
if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
return (SLP_FALSE);
strlcpy(s->url, srvurl, sizeof(s->url));
if (*head)
s->next = *head;
*head = s;
return (SLP_TRUE);
}
#endif
static void
update_cups_browse(void)
{
int i;
int auth;
int len;
int bytes;
char packet[1541],
*pptr;
socklen_t srclen;
http_addr_t srcaddr;
char srcname[1024];
unsigned address[4];
unsigned type;
unsigned state;
char uri[HTTP_MAX_URI],
host[HTTP_MAX_URI],
resource[HTTP_MAX_URI],
info[IPP_MAX_NAME],
location[IPP_MAX_NAME],
make_model[IPP_MAX_NAME];
int num_attrs;
cups_option_t *attrs;
srclen = sizeof(srcaddr);
if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
(struct sockaddr *)&srcaddr, &srclen)) < 0)
{
if (errno != ECONNREFUSED && errno != EAGAIN)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
strerror(errno));
cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
cupsdStopBrowsing();
Browsing = 0;
}
return;
}
packet[bytes] = '\0';
if (Sleeping)
return;
#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
{
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);
if (BrowseACL)
{
if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
{
auth = CUPSD_AUTH_ALLOW;
}
else
{
switch (BrowseACL->order_type)
{
default :
auth = CUPSD_AUTH_DENY;
break;
case CUPSD_AUTH_ALLOW :
auth = CUPSD_AUTH_ALLOW;
if (cupsdCheckAuth(address, srcname, len,
BrowseACL->num_deny, BrowseACL->deny))
auth = CUPSD_AUTH_DENY;
if (cupsdCheckAuth(address, srcname, len,
BrowseACL->num_allow, BrowseACL->allow))
auth = CUPSD_AUTH_ALLOW;
break;
case CUPSD_AUTH_DENY :
auth = CUPSD_AUTH_DENY;
if (cupsdCheckAuth(address, srcname, len,
BrowseACL->num_allow, BrowseACL->allow))
auth = CUPSD_AUTH_ALLOW;
if (cupsdCheckAuth(address, srcname, len,
BrowseACL->num_deny, BrowseACL->deny))
auth = CUPSD_AUTH_DENY;
break;
}
}
}
else
auth = CUPSD_AUTH_ALLOW;
if (auth == CUPSD_AUTH_DENY)
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"update_cups_browse: Refused %d bytes from %s", bytes,
srcname);
return;
}
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"update_cups_browse: (%d bytes from %s) %s", bytes,
srcname, packet);
if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
{
cupsdLogMessage(CUPSD_LOG_WARN,
"update_cups_browse: 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)
{
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));
if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
{
cupsFreeOptions(num_attrs, attrs);
return;
}
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;
}
process_browse_data(uri, host, resource, (cups_ptype_t)type,
(ipp_pstate_t)state, location, info, make_model,
num_attrs, attrs);
}
static void
update_polling(void)
{
char *ptr,
message[1024];
int loglevel;
while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
message, sizeof(message))) != NULL)
if (!strchr(PollStatusBuffer->buffer, '\n'))
break;
if (ptr == NULL && !PollStatusBuffer->bufused)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"update_polling: all polling processes have exited!");
cupsdStopPolling();
}
}