/*
- * "$Id: dirsvc.c 5023 2006-01-29 14:39:44Z mike $"
+ * "$Id: dirsvc.c 5043 2006-02-01 18:55:16Z mike $"
*
* Directory services routines for the Common UNIX Printing System (CUPS).
*
* Contents:
*
* cupsdLoadRemoteCache() - Load the remote printer cache.
- * cupsdProcessBrowseData() - Process new browse data.
- * cupsdProcessImplicitClasses() - Create/update implicit classes as needed.
* cupsdSaveRemoteCache() - Save the remote printer cache.
* cupsdSendBrowseDelete() - Send a "browse delete" message for a
* printer.
* protocol.
* cupsdUpdatePolling() - Read status messages from the poll daemons.
* cupsdUpdateSLPBrowse() - Get browsing information via SLP.
+ * dequote() - Remote quotes from a string.
+ * process_browse_data() - Process new browse data.
+ * process_implicit_classes() - Create/update implicit classes as needed.
* slp_attr_callback() - SLP attribute callback
* slp_dereg_printer() - SLPDereg() the specified printer
* slp_get_attr() - Get an attribute from an SLP registration.
/*
- * SLP definitions...
+ * Local functions...
*/
+static char *dequote(char *d, const char *s, int dlen);
+static void process_browse_data(const char *uri, 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(void);
+
+
#ifdef HAVE_LIBSLP
+/*
+ * SLP definitions...
+ */
+
/*
* SLP service name for CUPS...
*/
* Do auto-classing if needed...
*/
- cupsdProcessImplicitClasses();
+ process_implicit_classes();
}
/*
- * 'cupsdProcessBrowseData()' - Process new browse data.
+ * 'cupsdSaveRemoteCache()' - Save the remote printer cache.
*/
void
-cupsdProcessBrowseData(
- const char *uri, /* I - URI of printer/class */
- 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 */
+cupsdSaveRemoteCache(void)
{
- int update; /* Update printer attributes? */
- char finaluri[HTTP_MAX_URI], /* Final URI for printer */
- method[HTTP_MAX_URI], /* Method portion of URI */
- username[HTTP_MAX_URI], /* Username portion of URI */
- host[HTTP_MAX_URI], /* Host portion of URI */
- resource[HTTP_MAX_URI]; /* Resource portion of URI */
- int port; /* Port portion of URI */
- char name[IPP_MAX_NAME], /* 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 */
-
-
- /*
- * Pull the URI apart to see if this is a local or remote printer...
- */
+ int i; /* Looping var */
+ cups_file_t *fp; /* printers.conf file */
+ char temp[1024]; /* Temporary string */
+ cupsd_printer_t *printer; /* Current printer class */
+ time_t curtime; /* Current time */
+ struct tm *curdate; /* Current date */
- httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method), username,
- sizeof(username), host, sizeof(host), &port, resource,
- sizeof(resource));
/*
- * Determine if the URI contains any illegal characters in it...
+ * Create the remote.cache file...
*/
- if (strncmp(uri, "ipp://", 6) || !host[0] ||
- (strncmp(resource, "/printers/", 10) &&
- strncmp(resource, "/classes/", 9)))
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdProcessBrowseData: Bad printer URI in browse data: %s",
- uri);
- return;
- }
+ snprintf(temp, sizeof(temp), "%s/remote.cache", CacheDir);
- if (strchr(resource, '?') ||
- (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
- (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
+ if ((fp = cupsFileOpen(temp, "w")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdProcessBrowseData: Bad resource in browse data: %s",
- resource);
+ "Unable to save remote.cache - %s", strerror(errno));
return;
}
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "Saving remote.cache...");
/*
- * OK, this isn't a local printer; add any remote options...
+ * Restrict access to the file...
*/
- ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
-
- 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...
- */
-
- snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
- BrowseRemoteOptions);
- }
- else
- {
- /*
- * Just use the local options...
- */
+ fchown(cupsFileNumber(fp), getuid(), Group);
+ fchmod(cupsFileNumber(fp), ConfigFilePerm);
- snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
- }
+ /*
+ * Write a small header to the file...
+ */
- uri = finaluri;
- }
- else if (ipp_options)
- {
- /*
- * Just use the server-supplied options...
- */
+ curtime = time(NULL);
+ curdate = localtime(&curtime);
+ strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
- snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
- uri = finaluri;
- }
+ cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n");
+ cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
/*
- * See if we already have it listed in the Printers list, and add it if not...
+ * Write each local printer known to the system...
*/
- type |= CUPS_PRINTER_REMOTE;
- type &= ~CUPS_PRINTER_IMPLICIT;
- update = 0;
- hptr = strchr(host, '.');
- sptr = strchr(ServerName, '.');
-
- if (sptr != NULL && hptr != NULL)
+ for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ printer;
+ printer = (cupsd_printer_t *)cupsArrayNext(Printers))
{
/*
- * Strip the common domain name components...
+ * Skip local destinations...
*/
- while (hptr != NULL)
- {
- if (!strcasecmp(hptr, sptr))
- {
- *hptr = '\0';
- break;
- }
- else
- hptr = strchr(hptr + 1, '.');
- }
- }
+ if (!(printer->type & CUPS_PRINTER_REMOTE))
+ continue;
- if (type & CUPS_PRINTER_CLASS)
- {
/*
- * Remote destination is a class...
+ * Write printers as needed...
*/
- if (!strncmp(resource, "/classes/", 9))
- snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
+ if (printer == DefaultPrinter)
+ cupsFilePuts(fp, "<Default");
else
- return;
+ cupsFilePutChar(fp, '<');
- if ((p = cupsdFindClass(name)) == NULL && BrowseShortNames)
- {
- if ((p = cupsdFindClass(resource + 9)) != NULL)
- {
- if (p->hostname && strcasecmp(p->hostname, host))
- {
- /*
- * Nope, this isn't the same host; if the hostname isn't the local host,
- * add it to the other class and then find a class using the full host
- * name...
- */
+ if (printer->type & CUPS_PRINTER_CLASS)
+ cupsFilePrintf(fp, "Class %s>\n", printer->name);
+ else
+ cupsFilePrintf(fp, "Printer %s>\n", printer->name);
- if (p->type & CUPS_PRINTER_REMOTE)
- {
- cupsdLogMessage(CUPSD_LOG_INFO,
- "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);
+ cupsFilePrintf(fp, "Type %d\n", printer->type);
- cupsArrayRemove(Printers, p);
- cupsdSetStringf(&p->name, "%s@%s", p->name, p->hostname);
- cupsdSetPrinterAttrs(p);
- cupsArrayAdd(Printers, p);
+ cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_time);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Class \'%s\' added by directory services.",
- p->name);
- }
+ if (printer->info)
+ cupsFilePrintf(fp, "Info %s\n", printer->info);
- 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 (printer->make_model)
+ cupsFilePrintf(fp, "MakeModel %s\n", printer->make_model);
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
- }
- }
- else
- {
- /*
- * Use the short name for this shared class.
- */
+ if (printer->location)
+ cupsFilePrintf(fp, "Location %s\n", printer->location);
- 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...
- */
+ if (printer->device_uri)
+ cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
+ 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 (!p)
- {
- /*
- * Class doesn't exist; add it...
- */
+ if (printer->accepting)
+ cupsFilePuts(fp, "Accepting Yes\n");
+ else
+ cupsFilePuts(fp, "Accepting No\n");
- p = cupsdAddClass(name);
+ cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
+ printer->job_sheets[1]);
- cupsdLogMessage(CUPSD_LOG_INFO, "Added remote class \"%s\"...", name);
+ for (i = 0; i < printer->num_users; i ++)
+ cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
+ printer->users[i]);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Class \'%s\' added by directory services.", name);
+ if (printer->type & CUPS_PRINTER_CLASS)
+ cupsFilePuts(fp, "</Class>\n");
+ else
+ cupsFilePuts(fp, "</Printer>\n");
+ }
- /*
- * Force the URI to point to the real server...
- */
+ cupsFileClose(fp);
+}
- p->type = type & ~CUPS_PRINTER_REJECTING;
- p->accepting = 1;
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- cupsdSetString(&p->hostname, host);
- update = 1;
- }
- }
- else
- {
- /*
- * Remote destination is a printer...
- */
+/*
+ * 'cupsdSendBrowseDelete()' - Send a "browse delete" message for a printer.
+ */
- if (strncmp(resource, "/printers/", 10) == 0)
- snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
- else
- return;
+void
+cupsdSendBrowseDelete(
+ cupsd_printer_t *p) /* I - Printer to delete */
+{
+ /*
+ * Only announce if browsing is enabled...
+ */
- if ((p = cupsdFindPrinter(name)) == NULL && BrowseShortNames)
- {
- if ((p = cupsdFindPrinter(resource + 10)) != NULL)
- {
- if (p->hostname && strcasecmp(p->hostname, host))
- {
- /*
- * Nope, this isn't the same host; if the hostname isn't the local host,
- * add it to the other printer and then find a printer using the full host
- * name...
- */
+ if (!Browsing || !p->shared)
+ return;
- if (p->type & CUPS_PRINTER_REMOTE)
- {
- cupsdLogMessage(CUPSD_LOG_INFO,
- "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);
+ /*
+ * First mark the printer for deletion...
+ */
- cupsArrayRemove(Printers, p);
- cupsdSetStringf(&p->name, "%s@%s", p->name, p->hostname);
- cupsdSetPrinterAttrs(p);
- cupsArrayAdd(Printers, p);
+ p->type |= CUPS_PRINTER_DELETE;
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Printer \'%s\' added by directory services.",
- p->name);
- }
+ /*
+ * Announce the deletion...
+ */
- 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 (BrowseLocalProtocols & BROWSE_CUPS)
+ cupsdSendCUPSBrowse(p);
+#ifdef HAVE_LIBSLP
+ if (BrowseLocalProtocols & BROWSE_SLP)
+ slp_dereg_printer(p);
+#endif /* HAVE_LIBSLP */
+}
- 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...
- */
+/*
+ * 'cupsdSendBrowseList()' - Send new browsing information as necessary.
+ */
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
- }
+void
+cupsdSendBrowseList(void)
+{
+ int count; /* Number of dests to update */
+ cupsd_printer_t *p; /* Current printer */
+ time_t ut, /* Minimum update time */
+ to; /* Timeout time */
- if (!p)
+
+ if (!Browsing || !BrowseLocalProtocols || !Printers)
+ return;
+
+ /*
+ * Compute the update and timeout times...
+ */
+
+ ut = time(NULL) - BrowseInterval;
+ to = time(NULL) - BrowseTimeout;
+
+ /*
+ * Figure out how many printers need an update...
+ */
+
+ if (BrowseInterval > 0)
+ {
+ int max_count; /* Maximum number to update */
+
+
+ /*
+ * Throttle the number of printers we'll be updating this time
+ * around based on the number of queues that need updating and
+ * the maximum number of queues to update each second...
+ */
+
+ 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 ++;
+
+ /*
+ * Loop through all of the printers and send local updates as needed...
+ */
+
+ 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))
{
/*
- * Printer doesn't exist; add it...
+ * Check for wraparound...
*/
- p = cupsdAddPrinter(name);
+ if (!p)
+ p = (cupsd_printer_t *)cupsArrayFirst(Printers);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Printer \'%s\' added by directory services.", name);
+ if (!p)
+ break;
+ else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) ||
+ !p->shared)
+ continue;
+ else if (p->browse_time < ut)
+ {
+ /*
+ * Need to send an update...
+ */
- cupsdLogMessage(CUPSD_LOG_INFO, "Added remote printer \"%s\"...", name);
+ count --;
- /*
- * Force the URI to point to the real server...
- */
+ p->browse_time = time(NULL);
- p->type = type & ~CUPS_PRINTER_REJECTING;
- p->accepting = 1;
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
+ if (BrowseLocalProtocols & BROWSE_CUPS)
+ cupsdSendCUPSBrowse(p);
- update = 1;
+#ifdef HAVE_LIBSLP
+ if (BrowseLocalProtocols & BROWSE_SLP)
+ cupsdSendSLPBrowse(p);
+#endif /* HAVE_LIBSLP */
+ }
}
+
+ /*
+ * Save where we left off so that all printers get updated...
+ */
+
+ BrowseNext = p;
}
/*
- * Update the state...
+ * Loop through all of the printers and send local updates as needed...
*/
- p->state = state;
- p->browse_time = time(NULL);
-
- if (type & CUPS_PRINTER_REJECTING)
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
{
- type &= ~CUPS_PRINTER_REJECTING;
+ /*
+ * If this is a remote queue, see if it needs to be timed out...
+ */
- if (p->accepting)
+ if (p->type & CUPS_PRINTER_REMOTE)
{
- update = 1;
- p->accepting = 0;
+ if (p->browse_time < 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_INFO,
+ "Remote destination \"%s\" has timed out; deleting it...",
+ p->name);
+
+ cupsArraySave(Printers);
+ cupsdDeletePrinter(p, 1);
+ cupsArrayRestore(Printers);
+ }
}
}
- 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;
- }
+/*
+ * 'cupsdSendCUPSBrowse()' - Send new browsing information using the CUPS protocol.
+ */
- if (info && (!p->info || strcmp(p->info, info)))
- {
- cupsdSetString(&p->info, info);
- update = 1;
- }
-
- if (!make_model || !make_model[0])
- {
- if (type & CUPS_PRINTER_CLASS)
- snprintf(local_make_model, sizeof(local_make_model),
- "Remote Class on %s", host);
- else
- snprintf(local_make_model, sizeof(local_make_model),
- "Remote Printer on %s", host);
- }
- else
- snprintf(local_make_model, sizeof(local_make_model),
- "%s on %s", make_model, host);
-
- if (!p->make_model || strcmp(p->make_model, local_make_model))
- {
- cupsdSetString(&p->make_model, local_make_model);
- update = 1;
- }
-
- if (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);
+void
+cupsdSendCUPSBrowse(cupsd_printer_t *p) /* I - Printer to send */
+{
+ int i; /* Looping var */
+ cups_ptype_t type; /* Printer type */
+ cupsd_dirsvc_addr_t *b; /* Browse address */
+ int bytes; /* Length of packet */
+ char packet[1453], /* Browse data packet */
+ uri[1024], /* Printer URI */
+ options[1024], /* Browse local options */
+ location[1024], /* printer-location */
+ info[1024], /* printer-info */
+ make_model[1024];
+ /* printer-make-and-model */
+ cupsd_netif_t *iface; /* Network interface */
- cupsdExpireSubscriptions(p, NULL);
-
- cupsdDeletePrinter(p, 1);
- cupsdUpdateImplicitClasses();
- }
- else if (update)
- {
- cupsdSetPrinterAttrs(p);
- cupsdUpdateImplicitClasses();
- }
/*
- * See if we have a default printer... If not, make the first printer the
- * default.
+ * Figure out the printer type value...
*/
- if (DefaultPrinter == NULL && Printers != NULL)
- DefaultPrinter = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ type = p->type | CUPS_PRINTER_REMOTE;
- /*
- * Do auto-classing if needed...
- */
+ if (!p->accepting)
+ type |= CUPS_PRINTER_REJECTING;
- cupsdProcessImplicitClasses();
+ if (p == DefaultPrinter)
+ type |= CUPS_PRINTER_DEFAULT;
/*
- * Update the printcap file...
+ * Initialize the browse options...
*/
- cupsdWritePrintcap();
-}
-
-
-/*
- * 'cupsdProcessImplicitClasses()' - Create/update implicit classes as needed.
- */
-
-void
-cupsdProcessImplicitClasses(void)
-{
- int i; /* Looping var */
- int update; /* Update printer attributes? */
- char name[IPP_MAX_NAME], /* Name of printer */
- *hptr; /* Pointer into hostname */
- cupsd_printer_t *p, /* Printer information */
- *pclass, /* Printer class */
- *first; /* First printer in class */
- int offset, /* Offset of name */
- len; /* Length of name */
-
-
- if (!ImplicitClasses || !Printers)
- return;
+ if (BrowseLocalOptions)
+ snprintf(options, sizeof(options), " ipp-options=%s", BrowseLocalOptions);
+ else
+ options[0] = '\0';
/*
- * Loop through all available printers and create classes as needed...
+ * Remove quotes from printer-info, printer-location, and
+ * printer-make-and-model attributes...
*/
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
- update = 0, pclass = NULL, first = NULL;
- p != NULL;
- p = (cupsd_printer_t *)cupsArrayNext(Printers))
- {
- /*
- * Skip implicit classes...
- */
-
- if (p->type & CUPS_PRINTER_IMPLICIT)
- {
- len = 0;
- continue;
- }
-
- /*
- * If len == 0, get the length of this printer name up to the "@"
- * sign (if any).
- */
+ dequote(location, p->location, sizeof(p->location));
+ dequote(info, p->info, sizeof(p->info));
+ dequote(make_model, p->make_model ? p->make_model : "Unknown",
+ sizeof(make_model));
- cupsArraySave(Printers);
+ /*
+ * Send a packet to each browse address...
+ */
- if (len > 0 &&
- strncasecmp(p->name, name + offset, len) == 0 &&
- (p->name[len] == '\0' || p->name[len] == '@'))
+ for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
+ if (b->iface[0])
{
/*
- * We have more than one printer with the same name; see if
- * we have a class, and if this printer is a member...
+ * Send the browse packet to one or more interfaces...
*/
- if (pclass && strcasecmp(pclass->name, name))
- {
- if (update)
- cupsdSetPrinterAttrs(pclass);
-
- update = 0;
- pclass = NULL;
- }
-
- if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
+ if (!strcmp(b->iface, "*"))
{
/*
- * Need to add the class...
+ * Send to all local interfaces...
*/
- pclass = cupsdAddPrinter(name);
- cupsArrayAdd(ImplicitPrinters, pclass);
+ cupsdNetIFUpdate();
- pclass->type |= CUPS_PRINTER_IMPLICIT;
- pclass->accepting = 1;
- pclass->state = IPP_PRINTER_IDLE;
+ for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ iface;
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ {
+ /*
+ * Only send to local, IPv4 interfaces...
+ */
- cupsdSetString(&pclass->location, p->location);
- cupsdSetString(&pclass->info, p->info);
+ if (!iface->is_local || !iface->port ||
+ iface->address.addr.sa_family != AF_INET)
+ continue;
- update = 1;
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ iface->hostname, iface->port,
+ (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" :
+ "/printers/%s",
+ p->name);
+ snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n",
+ type, p->state, uri, location, info, make_model, options);
- cupsdLogMessage(CUPSD_LOG_INFO, "Added implicit class \"%s\"...",
- name);
- }
+ bytes = strlen(packet);
- if (first != NULL)
+ 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),
+ sizeof(struct sockaddr_in));
+ }
+ }
+ else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
{
- for (i = 0; i < pclass->num_printers; i ++)
- if (pclass->printers[i] == first)
+ /*
+ * Send to the named interface using the IPv4 address...
+ */
+
+ while (iface)
+ if (strcmp(b->iface, iface->name))
+ {
+ iface = NULL;
break;
+ }
+ else if (iface->address.addr.sa_family == AF_INET && iface->port)
+ break;
+ else
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
- if (i >= pclass->num_printers)
+ if (iface)
{
- first->in_implicit_class = 1;
- cupsdAddPrinterToClass(pclass, first);
- }
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ iface->hostname, iface->port,
+ (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" :
+ "/printers/%s",
+ p->name);
+ snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n",
+ type, p->state, uri, location, info, make_model, options);
- first = NULL;
- }
+ bytes = strlen(packet);
- for (i = 0; i < pclass->num_printers; i ++)
- if (pclass->printers[i] == p)
- break;
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
+ iface->name, packet);
- if (i >= pclass->num_printers)
- {
- p->in_implicit_class = 1;
- cupsdAddPrinterToClass(pclass, p);
- update = 1;
+ iface->broadcast.ipv4.sin_port = htons(BrowsePort);
+
+ sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(iface->broadcast),
+ sizeof(struct sockaddr_in));
+ }
}
}
else
{
/*
- * First time around; just get name length and mark it as first
- * in the list...
+ * Send the browse packet to the indicated address using
+ * the default server name...
*/
- if ((hptr = strchr(p->name, '@')) != NULL)
- len = hptr - p->name;
- else
- len = strlen(p->name);
+ snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n",
+ type, p->state, p->uri, location, info, make_model, options);
- strncpy(name, p->name, len);
- name[len] = '\0';
- offset = 0;
+ bytes = strlen(packet);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
- if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
- !(first->type & CUPS_PRINTER_IMPLICIT))
+ if (sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(b->to),
+ sizeof(struct sockaddr_in)) <= 0)
{
/*
- * Can't use same name as a local printer; add "Any" to the
- * front of the name, unless we have explicitly disabled
- * the "ImplicitAnyClasses"...
+ * Unable to send browse packet, so remove this address from the
+ * list...
*/
- if (ImplicitAnyClasses && len < (sizeof(name) - 4))
- {
- /*
- * Add "Any" to the class name...
- */
-
- strcpy(name, "Any");
- strncpy(name + 3, p->name, len);
- name[len + 3] = '\0';
- offset = 3;
- }
- else
- {
- /*
- * Don't create an implicit class if we have a local printer
- * with the same name...
- */
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdSendBrowseList: sendto failed for browser %d - %s.",
+ b - Browsers + 1, strerror(errno));
- len = 0;
- cupsArrayRestore(Printers);
- continue;
- }
- }
+ if (i > 1)
+ memcpy(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
- first = p;
+ b --;
+ NumBrowsers --;
+ }
}
-
- cupsArrayRestore(Printers);
- }
-
- /*
- * Update the last printer class as needed...
- */
-
- if (pclass && update)
- cupsdSetPrinterAttrs(pclass);
}
+#ifdef HAVE_LIBSLP
/*
- * 'cupsdSaveRemoteCache()' - Save the remote printer cache.
+ * 'cupsdSendSLPBrowse()' - Register the specified printer with SLP.
*/
-void
-cupsdSaveRemoteCache(void)
+void
+cupsdSendSLPBrowse(cupsd_printer_t *p) /* I - Printer to register */
{
- int i; /* Looping var */
- cups_file_t *fp; /* printers.conf file */
- char temp[1024]; /* Temporary string */
- cupsd_printer_t *printer; /* Current printer class */
- time_t curtime; /* Current time */
- struct tm *curdate; /* Current date */
-
-
- /*
- * Create the remote.cache file...
- */
-
- 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_INFO, "Saving remote.cache...");
+ char srvurl[HTTP_MAX_URI], /* Printer service URI */
+ attrs[8192], /* Printer attributes */
+ finishings[1024], /* Finishings to support */
+ make_model[IPP_MAX_NAME * 2],
+ /* Make and model, quoted */
+ location[IPP_MAX_NAME * 2],
+ /* Location, quoted */
+ info[IPP_MAX_NAME * 2], /* Info, quoted */
+ *src, /* Pointer to original string */
+ *dst; /* Pointer to destination string */
+ ipp_attribute_t *authentication; /* uri-authentication-supported value */
+ SLPError error; /* SLP error, if any */
- /*
- * Restrict access to the file...
- */
- fchown(cupsFileNumber(fp), getuid(), Group);
- fchmod(cupsFileNumber(fp), ConfigFilePerm);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSendSLPBrowse(%p = \"%s\")", p,
+ p->name);
/*
- * Write a small header to the file...
+ * Make the SLP service URL that conforms to the IANA
+ * 'printer:' template.
*/
- curtime = time(NULL);
- curdate = localtime(&curtime);
- strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
+ snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
- cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n");
- cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
/*
- * Write each local printer known to the system...
+ * Figure out the finishings string...
*/
- for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
- printer;
- printer = (cupsd_printer_t *)cupsArrayNext(Printers))
- {
- /*
- * Skip local destinations...
- */
+ if (p->type & CUPS_PRINTER_STAPLE)
+ strcpy(finishings, "staple");
+ else
+ finishings[0] = '\0';
- if (!(printer->type & CUPS_PRINTER_REMOTE))
- continue;
+ if (p->type & CUPS_PRINTER_BIND)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",bind", sizeof(finishings));
+ else
+ strcpy(finishings, "bind");
+ }
- /*
- * Write printers as needed...
- */
+ if (p->type & CUPS_PRINTER_PUNCH)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",punch", sizeof(finishings));
+ else
+ strcpy(finishings, "punch");
+ }
- if (printer == DefaultPrinter)
- cupsFilePuts(fp, "<Default");
+ if (p->type & CUPS_PRINTER_COVER)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",cover", sizeof(finishings));
else
- cupsFilePutChar(fp, '<');
+ strcpy(finishings, "cover");
+ }
- if (printer->type & CUPS_PRINTER_CLASS)
- cupsFilePrintf(fp, "Class %s>\n", printer->name);
+ if (p->type & CUPS_PRINTER_SORT)
+ {
+ if (finishings[0])
+ strlcat(finishings, ",sort", sizeof(finishings));
else
- cupsFilePrintf(fp, "Printer %s>\n", printer->name);
+ strcpy(finishings, "sort");
+ }
- cupsFilePrintf(fp, "Type %d\n", printer->type);
+ if (!finishings[0])
+ strcpy(finishings, "none");
- cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_time);
+ /*
+ * Quote any commas in the make and model, location, and info strings...
+ */
- if (printer->info)
- cupsFilePrintf(fp, "Info %s\n", printer->info);
+ for (src = p->make_model, dst = make_model;
+ src && *src && dst < (make_model + sizeof(make_model) - 2);)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
- if (printer->make_model)
- cupsFilePrintf(fp, "MakeModel %s\n", printer->make_model);
+ *dst++ = *src++;
+ }
- if (printer->location)
- cupsFilePrintf(fp, "Location %s\n", printer->location);
+ *dst = '\0';
- if (printer->device_uri)
- cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
+ if (!make_model[0])
+ strcpy(make_model, "Unknown");
- 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");
+ for (src = p->location, dst = location;
+ src && *src && dst < (location + sizeof(location) - 2);)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
- if (printer->accepting)
- cupsFilePuts(fp, "Accepting Yes\n");
- else
- cupsFilePuts(fp, "Accepting No\n");
+ *dst++ = *src++;
+ }
- cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
- printer->job_sheets[1]);
+ *dst = '\0';
- for (i = 0; i < printer->num_users; i ++)
- cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
- printer->users[i]);
+ if (!location[0])
+ strcpy(location, "Unknown");
- if (printer->type & CUPS_PRINTER_CLASS)
- cupsFilePuts(fp, "</Class>\n");
- else
- cupsFilePuts(fp, "</Printer>\n");
- }
+ for (src = p->info, dst = info;
+ src && *src && dst < (info + sizeof(info) - 2);)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
- cupsFileClose(fp);
-}
+ *dst++ = *src++;
+ }
+ *dst = '\0';
-/*
- * 'cupsdSendBrowseDelete()' - Send a "browse delete" message for a printer.
- */
+ if (!info[0])
+ strcpy(info, "Unknown");
-void
-cupsdSendBrowseDelete(
- cupsd_printer_t *p) /* I - Printer to delete */
-{
/*
- * Only announce if browsing is enabled...
+ * Get the authentication value...
*/
- if (!Browsing || !p->shared)
- return;
+ authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
+ IPP_TAG_KEYWORD);
/*
- * First mark the printer for deletion...
+ * Make the SLP attribute string list that conforms to
+ * the IANA 'printer:' template.
*/
- p->type |= CUPS_PRINTER_DELETE;
+ snprintf(attrs, sizeof(attrs),
+ "(printer-uri-supported=%s),"
+ "(uri-authentication-supported=%s>),"
+#ifdef HAVE_SSL
+ "(uri-security-supported=tls>),"
+#else
+ "(uri-security-supported=none>),"
+#endif /* HAVE_SSL */
+ "(printer-name=%s),"
+ "(printer-location=%s),"
+ "(printer-info=%s),"
+ "(printer-more-info=%s),"
+ "(printer-make-and-model=%s),"
+ "(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, 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);
/*
- * Announce the deletion...
+ * Register the printer with the SLP server...
*/
- if (BrowseLocalProtocols & BROWSE_CUPS)
- cupsdSendCUPSBrowse(p);
-#ifdef HAVE_LIBSLP
- if (BrowseLocalProtocols & BROWSE_SLP)
- slp_dereg_printer(p);
-#endif /* HAVE_LIBSLP */
-}
-
+ error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
+ SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
-/*
- * 'cupsdSendBrowseList()' - Send new browsing information as necessary.
+ if (error != SLP_OK)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
+ error);
+}
+#endif /* HAVE_LIBSLP */
+
+
+/*
+ * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
*/
void
-cupsdSendBrowseList(void)
+cupsdStartBrowsing(void)
{
- int count; /* Number of dests to update */
- cupsd_printer_t *p; /* Current printer */
- time_t ut, /* Minimum update time */
- to; /* Timeout time */
+ int val; /* Socket option value */
+ struct sockaddr_in addr; /* Broadcast address */
- if (!Browsing || !BrowseLocalProtocols || !Printers)
- return;
+ BrowseNext = NULL;
- /*
- * Compute the update and timeout times...
- */
+ if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
+ return;
- ut = time(NULL) - BrowseInterval;
- to = time(NULL) - BrowseTimeout;
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
+ {
+ if (BrowseSocket < 0)
+ {
+ /*
+ * Create the broadcast socket...
+ */
- /*
- * Figure out how many printers need an update...
- */
+ if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdStartBrowsing: Unable to create broadcast "
+ "socket - %s.", strerror(errno));
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
+ return;
+ }
- if (BrowseInterval > 0)
- {
- int max_count; /* Maximum number to update */
+ /*
+ * Bind the socket to browse port...
+ */
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(BrowsePort);
- /*
- * Throttle the number of printers we'll be updating this time
- * around based on the number of queues that need updating and
- * the maximum number of queues to update each second...
- */
+ if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdStartBrowsing: Unable to bind broadcast "
+ "socket - %s.", strerror(errno));
- max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1;
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
- 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 ++;
+ BrowseSocket = -1;
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
+ return;
+ }
+ }
/*
- * Loop through all of the printers and send local updates as needed...
+ * Set the "broadcast" flag...
*/
- 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))
+ val = 1;
+ if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
{
- /*
- * Check for wraparound...
- */
-
- 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)
- {
- /*
- * Need to send an update...
- */
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdStartBrowsing: Unable to set broadcast mode - %s.",
+ strerror(errno));
- count --;
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
- p->browse_time = time(NULL);
+ BrowseSocket = -1;
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
+ return;
+ }
- if (BrowseLocalProtocols & BROWSE_CUPS)
- cupsdSendCUPSBrowse(p);
+ /*
+ * Close the socket on exec...
+ */
-#ifdef HAVE_LIBSLP
- if (BrowseLocalProtocols & BROWSE_SLP)
- cupsdSendSLPBrowse(p);
-#endif /* HAVE_LIBSLP */
- }
- }
+ fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
/*
- * Save where we left off so that all printers get updated...
+ * Finally, add the socket to the input selection set...
*/
- BrowseNext = p;
- }
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdStartBrowsing: Adding fd %d to InputSet...",
+ BrowseSocket);
- /*
- * Loop through all of the printers and send local updates as needed...
- */
+ FD_SET(BrowseSocket, InputSet);
+ }
+ else
+ BrowseSocket = -1;
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
- p;
- p = (cupsd_printer_t *)cupsArrayNext(Printers))
+#ifdef HAVE_LIBSLP
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
{
- /*
- * If this is a remote queue, see if it needs to be timed out...
+ /*
+ * Open SLP handle...
*/
- if (p->type & CUPS_PRINTER_REMOTE)
+ if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
{
- if (p->browse_time < 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_INFO,
- "Remote destination \"%s\" has timed out; deleting it...",
- p->name);
-
- cupsArraySave(Printers);
- cupsdDeletePrinter(p, 1);
- cupsArrayRestore(Printers);
- }
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open an SLP handle; disabling SLP browsing!");
+ BrowseLocalProtocols &= ~BROWSE_SLP;
+ BrowseRemoteProtocols &= ~BROWSE_SLP;
}
+
+ BrowseSLPRefresh = 0;
}
+#endif /* HAVE_LIBSLP */
}
/*
- * 'cupsdSendCUPSBrowse()' - Send new browsing information using the CUPS protocol.
+ * 'cupsdStartPolling()' - Start polling servers as needed.
*/
void
-cupsdSendCUPSBrowse(cupsd_printer_t *p) /* I - Printer to send */
+cupsdStartPolling(void)
{
int i; /* Looping var */
- cups_ptype_t type; /* Printer type */
- cupsd_dirsvc_addr_t *b; /* Browse address */
- int bytes; /* Length of packet */
- char packet[1453]; /* Browse data packet */
- char uri[1024]; /* Printer URI */
- char options[1024]; /* Browse local options */
- cupsd_netif_t *iface; /* Network interface */
+ cupsd_dirsvc_poll_t *pollp; /* Current polling server */
+ char polld[1024]; /* Poll daemon path */
+ char sport[10]; /* Server port */
+ char bport[10]; /* Browser port */
+ char interval[10]; /* Poll interval */
+ int statusfds[2]; /* Status pipe */
+ char *argv[6]; /* Arguments */
+ char *envp[100]; /* Environment */
/*
- * Figure out the printer type value...
+ * Don't do anything if we aren't polling...
*/
- type = p->type | CUPS_PRINTER_REMOTE;
-
- if (!p->accepting)
- type |= CUPS_PRINTER_REJECTING;
+ if (NumPolled == 0)
+ {
+ PollPipe = -1;
+ PollStatusBuffer = NULL;
+ return;
+ }
/*
- * Initialize the browse options...
+ * Setup string arguments for polld, port and interval options.
*/
- if (BrowseLocalOptions)
- snprintf(options, sizeof(options), " ipp-options=%s", BrowseLocalOptions);
- else
- options[0] = '\0';
+ snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
- /*
- * Send a packet to each browse address...
- */
+ sprintf(bport, "%d", BrowsePort);
- for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
- if (b->iface[0])
- {
- /*
- * Send the browse packet to one or more interfaces...
- */
+ if (BrowseInterval)
+ sprintf(interval, "%d", BrowseInterval);
+ else
+ strcpy(interval, "30");
- if (strcmp(b->iface, "*") == 0)
- {
- /*
- * Send to all local interfaces...
- */
+ argv[0] = "cups-polld";
+ argv[2] = sport;
+ argv[3] = interval;
+ argv[4] = bport;
+ argv[5] = NULL;
- cupsdNetIFUpdate();
+ cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
- for (iface = NetIFList; iface != NULL; iface = iface->next)
- {
- /*
- * Only send to local, IPv4 interfaces...
- */
+ /*
+ * Create a pipe that receives the status messages from each
+ * polling daemon...
+ */
- 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%s" :
- "/printers/%s",
- p->name);
- snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n",
- type, p->state, uri, p->location ? p->location : "",
- p->info ? p->info : "",
- p->make_model ? p->make_model : "Unknown", options);
-
- 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),
- sizeof(struct sockaddr_in));
- }
- }
- else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
- {
- /*
- * Send to the named interface using the IPv4 address...
- */
-
- while (iface)
- if (strcasecmp(b->iface, iface->name))
- {
- iface = NULL;
- break;
- }
- else if (iface->address.addr.sa_family == AF_INET && iface->port)
- break;
- else
- iface = iface->next;
+ if (cupsdOpenPipe(statusfds))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create polling status pipes - %s.",
+ strerror(errno));
+ PollPipe = -1;
+ PollStatusBuffer = NULL;
+ return;
+ }
- if (iface)
- {
- httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
- iface->hostname, iface->port,
- (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" :
- "/printers/%s",
- p->name);
- snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n",
- type, p->state, uri, p->location ? p->location : "",
- p->info ? p->info : "",
- p->make_model ? p->make_model : "Unknown", options);
+ PollPipe = statusfds[0];
+ PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
- bytes = strlen(packet);
+ /*
+ * Run each polling daemon, redirecting stderr to the polling pipe...
+ */
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
- iface->name, packet);
+ for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
+ {
+ sprintf(sport, "%d", pollp->port);
- iface->broadcast.ipv4.sin_port = htons(BrowsePort);
+ argv[1] = pollp->hostname;
- sendto(BrowseSocket, packet, bytes, 0,
- (struct sockaddr *)&(iface->broadcast),
- sizeof(struct sockaddr_in));
- }
- }
+ if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1,
+ 0, &(pollp->pid)) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdStartPolling: Unable to fork polling daemon - %s",
+ strerror(errno));
+ pollp->pid = 0;
+ break;
}
else
- {
- /*
- * Send the browse packet to the indicated address using
- * the default server name...
- */
-
- snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n",
- type, p->state, p->uri,
- p->location ? p->location : "",
- p->info ? p->info : "",
- p->make_model ? p->make_model : "Unknown", options);
-
- bytes = strlen(packet);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
+ pollp->hostname, pollp->port, pollp->pid);
+ }
- if (sendto(BrowseSocket, packet, bytes, 0,
- (struct sockaddr *)&(b->to),
- sizeof(struct sockaddr_in)) <= 0)
- {
- /*
- * Unable to send browse packet, so remove this address from the
- * list...
- */
+ close(statusfds[1]);
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdSendBrowseList: sendto failed for browser %d - %s.",
- b - Browsers + 1, strerror(errno));
+ /*
+ * Finally, add the pipe to the input selection set...
+ */
- if (i > 1)
- memcpy(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdStartPolling: Adding fd %d to InputSet...", PollPipe);
- b --;
- NumBrowsers --;
- }
- }
+ FD_SET(PollPipe, InputSet);
}
-#ifdef HAVE_LIBSLP
/*
- * 'cupsdSendSLPBrowse()' - Register the specified printer with SLP.
+ * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
*/
-void
-cupsdSendSLPBrowse(cupsd_printer_t *p) /* I - Printer to register */
+void
+cupsdStopBrowsing(void)
{
- char srvurl[HTTP_MAX_URI], /* Printer service URI */
- attrs[8192], /* Printer attributes */
- finishings[1024], /* Finishings to support */
- make_model[IPP_MAX_NAME * 2],
- /* Make and model, quoted */
- location[IPP_MAX_NAME * 2],
- /* Location, quoted */
- info[IPP_MAX_NAME * 2], /* Info, quoted */
- *src, /* Pointer to original string */
- *dst; /* Pointer to destination string */
- ipp_attribute_t *authentication; /* uri-authentication-supported value */
- SLPError error; /* SLP error, if any */
-
-
- cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSendSLPBrowse(%p = \"%s\")", p,
- p->name);
-
- /*
- * Make the SLP service URL that conforms to the IANA
- * 'printer:' template.
- */
-
- snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
+ if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
+ return;
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
+ if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
+ BrowseSocket >= 0)
+ {
+ /*
+ * Close the socket and remove it from the input selection set.
+ */
- /*
- * Figure out the finishings string...
- */
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
- if (p->type & CUPS_PRINTER_STAPLE)
- strcpy(finishings, "staple");
- else
- finishings[0] = '\0';
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdStopBrowsing: Removing fd %d from InputSet...",
+ BrowseSocket);
- if (p->type & CUPS_PRINTER_BIND)
- {
- if (finishings[0])
- strlcat(finishings, ",bind", sizeof(finishings));
- else
- strcpy(finishings, "bind");
+ FD_CLR(BrowseSocket, InputSet);
+ BrowseSocket = -1;
}
- if (p->type & CUPS_PRINTER_PUNCH)
+#ifdef HAVE_LIBSLP
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
{
- if (finishings[0])
- strlcat(finishings, ",punch", sizeof(finishings));
- else
- strcpy(finishings, "punch");
- }
+ /*
+ * Close SLP handle...
+ */
- if (p->type & CUPS_PRINTER_COVER)
- {
- if (finishings[0])
- strlcat(finishings, ",cover", sizeof(finishings));
- else
- strcpy(finishings, "cover");
+ SLPClose(BrowseSLPHandle);
}
+#endif /* HAVE_LIBSLP */
+}
- if (p->type & CUPS_PRINTER_SORT)
- {
- if (finishings[0])
- strlcat(finishings, ",sort", sizeof(finishings));
- else
- strcpy(finishings, "sort");
- }
- if (!finishings[0])
- strcpy(finishings, "none");
+/*
+ * 'cupsdStopPolling()' - Stop polling servers as needed.
+ */
- /*
- * Quote any commas in the make and model, location, and info strings...
- */
+void
+cupsdStopPolling(void)
+{
+ int i; /* Looping var */
+ cupsd_dirsvc_poll_t *pollp; /* Current polling server */
- for (src = p->make_model, dst = make_model;
- src && *src && dst < (make_model + sizeof(make_model) - 2);)
+
+ if (PollPipe >= 0)
{
- if (*src == ',' || *src == '\\' || *src == ')')
- *dst++ = '\\';
+ cupsdStatBufDelete(PollStatusBuffer);
+ close(PollPipe);
- *dst++ = *src++;
- }
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdStopPolling: removing fd %d from InputSet.", PollPipe);
+ FD_CLR(PollPipe, InputSet);
- *dst = '\0';
+ PollPipe = -1;
+ PollStatusBuffer = NULL;
+ }
- if (!make_model[0])
- strcpy(make_model, "Unknown");
+ for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
+ if (pollp->pid)
+ cupsdEndProcess(pollp->pid, 0);
+}
- for (src = p->location, dst = location;
- src && *src && dst < (location + sizeof(location) - 2);)
- {
- if (*src == ',' || *src == '\\' || *src == ')')
- *dst++ = '\\';
- *dst++ = *src++;
- }
+/*
+ * 'cupsdUpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol.
+ */
- *dst = '\0';
+void
+cupsdUpdateCUPSBrowse(void)
+{
+ int i; /* Looping var */
+ int auth; /* Authorization status */
+ int len; /* Length of name string */
+ int bytes; /* Number of bytes left */
+ char packet[1541], /* Broadcast packet */
+ *pptr; /* Pointer into packet */
+ socklen_t srclen; /* Length of source address */
+ http_addr_t srcaddr; /* Source address */
+ char srcname[1024]; /* Source hostname */
+ unsigned address[4]; /* Source address */
+ unsigned type; /* Printer type */
+ unsigned state; /* Printer state */
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ method[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI], /* Resource portion of URI */
+ info[IPP_MAX_NAME], /* Information string */
+ location[IPP_MAX_NAME], /* Location string */
+ make_model[IPP_MAX_NAME];/* Make and model string */
+ int port; /* Port portion of URI */
+ cupsd_netif_t *iface; /* Network interface */
+ int num_attrs; /* Number of attributes */
+ cups_option_t *attrs; /* Attributes */
- if (!location[0])
- strcpy(location, "Unknown");
- for (src = p->info, dst = info;
- src && *src && dst < (info + sizeof(info) - 2);)
- {
- if (*src == ',' || *src == '\\' || *src == ')')
- *dst++ = '\\';
+ /*
+ * Read a packet from the browse socket...
+ */
- *dst++ = *src++;
- }
+ srclen = sizeof(srcaddr);
+ if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
+ (struct sockaddr *)&srcaddr, &srclen)) < 0)
+ {
+ /*
+ * "Connection refused" is returned under Linux if the destination port
+ * or address is unreachable from a previous sendto(); check for the
+ * error here and ignore it for now...
+ */
- *dst = '\0';
+ if (errno != ECONNREFUSED && errno != EAGAIN)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
+ strerror(errno));
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
- if (!info[0])
- strcpy(info, "Unknown");
+ cupsdStopBrowsing();
+ Browsing = 0;
+ }
- /*
- * Get the authentication value...
- */
+ return;
+ }
- authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
- IPP_TAG_KEYWORD);
+ packet[bytes] = '\0';
/*
- * Make the SLP attribute string list that conforms to
- * the IANA 'printer:' template.
+ * If we're about to sleep, ignore incoming browse packets.
*/
- snprintf(attrs, sizeof(attrs),
- "(printer-uri-supported=%s),"
- "(uri-authentication-supported=%s>),"
-#ifdef HAVE_SSL
- "(uri-security-supported=tls>),"
-#else
- "(uri-security-supported=none>),"
-#endif /* HAVE_SSL */
- "(printer-name=%s),"
- "(printer-location=%s),"
- "(printer-info=%s),"
- "(printer-more-info=%s),"
- "(printer-make-and-model=%s),"
- "(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, 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);
+ if (Sleeping)
+ return;
/*
- * Register the printer with the SLP server...
+ * Figure out where it came from...
*/
- 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);
-}
-#endif /* HAVE_LIBSLP */
-
-
-/*
- * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
- */
-
-void
-cupsdStartBrowsing(void)
-{
- int val; /* Socket option value */
- struct sockaddr_in addr; /* Broadcast address */
+#ifdef AF_INET6
+ if (srcaddr.addr.sa_family == AF_INET6)
+ {
+ address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
+ address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
+ address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
+ address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
+ }
+ else
+#endif /* AF_INET6 */
+ {
+ address[0] = 0;
+ address[1] = 0;
+ address[2] = 0;
+ address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
+ }
+ if (HostNameLookups)
+ httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
+ else
+ httpAddrString(&srcaddr, srcname, sizeof(srcname));
- BrowseNext = NULL;
+ len = strlen(srcname);
- if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
- return;
+ /*
+ * Do ACL stuff...
+ */
- if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
+ if (BrowseACL)
{
- if (BrowseSocket < 0)
+ if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
{
/*
- * Create the broadcast socket...
+ * Access from localhost (127.0.0.1) is always allowed...
*/
- if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to create broadcast "
- "socket - %s.", strerror(errno));
- BrowseLocalProtocols &= ~BROWSE_CUPS;
- BrowseRemoteProtocols &= ~BROWSE_CUPS;
- return;
- }
-
+ auth = AUTH_ALLOW;
+ }
+ else
+ {
/*
- * Bind the socket to browse port...
+ * Do authorization checks on the domain/address...
*/
- 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)))
+ switch (BrowseACL->order_type)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to bind broadcast "
- "socket - %s.", strerror(errno));
+ default :
+ auth = AUTH_DENY; /* anti-compiler-warning-code */
+ break;
-#ifdef WIN32
- closesocket(BrowseSocket);
-#else
- close(BrowseSocket);
-#endif /* WIN32 */
+ case AUTH_ALLOW : /* Order Deny,Allow */
+ auth = AUTH_ALLOW;
- BrowseSocket = -1;
- BrowseLocalProtocols &= ~BROWSE_CUPS;
- BrowseRemoteProtocols &= ~BROWSE_CUPS;
- return;
- }
- }
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_deny, BrowseACL->deny))
+ auth = AUTH_DENY;
- /*
- * Set the "broadcast" flag...
- */
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_allow, BrowseACL->allow))
+ auth = AUTH_ALLOW;
+ break;
- val = 1;
- if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to set broadcast mode - %s.",
- strerror(errno));
+ case AUTH_DENY : /* Order Allow,Deny */
+ auth = AUTH_DENY;
-#ifdef WIN32
- closesocket(BrowseSocket);
-#else
- close(BrowseSocket);
-#endif /* WIN32 */
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_allow, BrowseACL->allow))
+ auth = AUTH_ALLOW;
- BrowseSocket = -1;
- BrowseLocalProtocols &= ~BROWSE_CUPS;
- BrowseRemoteProtocols &= ~BROWSE_CUPS;
- return;
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_deny, BrowseACL->deny))
+ auth = AUTH_DENY;
+ break;
+ }
}
-
- /*
- * Close the socket on exec...
- */
-
- fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
-
- /*
- * Finally, add the socket to the input selection set...
- */
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStartBrowsing: Adding fd %d to InputSet...",
- BrowseSocket);
-
- FD_SET(BrowseSocket, InputSet);
}
else
- BrowseSocket = -1;
+ auth = AUTH_ALLOW;
-#ifdef HAVE_LIBSLP
- if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
+ if (auth == AUTH_DENY)
{
- /*
- * Open SLP handle...
- */
-
- 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;
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdUpdateCUPSBrowse: Refused %d bytes from %s", bytes,
+ srcname);
+ return;
}
-#endif /* HAVE_LIBSLP */
-}
-
-
-/*
- * 'cupsdStartPolling()' - Start polling servers as needed.
- */
-
-void
-cupsdStartPolling(void)
-{
- int i; /* Looping var */
- cupsd_dirsvc_poll_t *pollp; /* Current polling server */
- char polld[1024]; /* Poll daemon path */
- char sport[10]; /* Server port */
- char bport[10]; /* Browser port */
- char interval[10]; /* Poll interval */
- int statusfds[2]; /* Status pipe */
- char *argv[6]; /* Arguments */
- char *envp[100]; /* Environment */
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdUpdateCUPSBrowse: (%d bytes from %s) %s", bytes,
+ srcname, packet);
/*
- * Don't do anything if we aren't polling...
+ * Parse packet...
*/
- if (NumPolled == 0)
+ if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
{
- PollPipe = -1;
- PollStatusBuffer = NULL;
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "cupsdUpdateCUPSBrowse: Garbled browse packet - %s", packet);
return;
}
- /*
- * Setup string arguments for polld, port and interval options.
- */
+ strcpy(location, "Location Unknown");
+ strcpy(info, "No Information Available");
+ make_model[0] = '\0';
+ num_attrs = 0;
+ attrs = NULL;
- snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
+ if ((pptr = strchr(packet, '\"')) != NULL)
+ {
+ /*
+ * Have extended information; can't use sscanf for it because not all
+ * sscanf's allow empty strings with %[^\"]...
+ */
- sprintf(bport, "%d", BrowsePort);
+ for (i = 0, pptr ++;
+ i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ location[i] = *pptr;
- if (BrowseInterval)
- sprintf(interval, "%d", BrowseInterval);
- else
- strcpy(interval, "30");
+ if (i)
+ location[i] = '\0';
- argv[0] = "cups-polld";
- argv[2] = sport;
- argv[3] = interval;
- argv[4] = bport;
- argv[5] = NULL;
+ if (*pptr == '\"')
+ pptr ++;
- cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+ 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));
/*
- * Create a pipe that receives the status messages from each
- * polling daemon...
+ * Pull the URI apart to see if this is a local or remote printer...
*/
- if (cupsdOpenPipe(statusfds))
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to create polling status pipes - %s.",
- strerror(errno));
- PollPipe = -1;
- PollStatusBuffer = NULL;
- return;
- }
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method), username,
+ sizeof(username), host, sizeof(host), &port, resource,
+ sizeof(resource));
- PollPipe = statusfds[0];
- PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
+ DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
/*
- * Run each polling daemon, redirecting stderr to the polling pipe...
+ * Check for packets from the local server...
*/
- for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
+ if (!strcasecmp(host, ServerName) && port == LocalPort)
{
- sprintf(sport, "%d", pollp->port);
+ cupsFreeOptions(num_attrs, attrs);
+ return;
+ }
- argv[1] = pollp->hostname;
+ cupsdNetIFUpdate();
- if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1,
- 0, &(pollp->pid)) < 0)
+ for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ iface;
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ if (!strcasecmp(host, iface->hostname) && port == iface->port)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartPolling: Unable to fork polling daemon - %s",
- strerror(errno));
- pollp->pid = 0;
- break;
+ cupsFreeOptions(num_attrs, attrs);
+ return;
}
- else
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
- pollp->hostname, pollp->port, pollp->pid);
- }
-
- close(statusfds[1]);
/*
- * Finally, add the pipe to the input selection set...
+ * Do relaying...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStartPolling: Adding fd %d to InputSet...", PollPipe);
+ 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),
+ sizeof(http_addr_t)) <= 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdUpdateCUPSBrowse: sendto failed for relay %d - %s.",
+ i + 1, strerror(errno));
+ cupsFreeOptions(num_attrs, attrs);
+ return;
+ }
- FD_SET(PollPipe, InputSet);
+ /*
+ * Process the browse data...
+ */
+
+ process_browse_data(uri, (cups_ptype_t)type, (ipp_pstate_t)state, location,
+ info, make_model, num_attrs, attrs);
+ cupsFreeOptions(num_attrs, attrs);
}
/*
- * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
+ * 'cupsdUpdatePolling()' - Read status messages from the poll daemons.
*/
void
-cupsdStopBrowsing(void)
+cupsdUpdatePolling(void)
{
- if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
- return;
-
- if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
- BrowseSocket >= 0)
- {
- /*
- * Close the socket and remove it from the input selection set.
- */
-
-#ifdef WIN32
- closesocket(BrowseSocket);
-#else
- close(BrowseSocket);
-#endif /* WIN32 */
+ char *ptr, /* Pointer to end of line in buffer */
+ message[1024]; /* Pointer to message text */
+ int loglevel; /* Log level for message */
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStopBrowsing: Removing fd %d from InputSet...",
- BrowseSocket);
- FD_CLR(BrowseSocket, InputSet);
- BrowseSocket = -1;
- }
+ while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
+ message, sizeof(message))) != NULL)
+ if (!strchr(PollStatusBuffer->buffer, '\n'))
+ break;
-#ifdef HAVE_LIBSLP
- if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
+ if (ptr == NULL)
{
- /*
- * Close SLP handle...
+ /*
+ * All polling processes have died; stop polling...
*/
- SLPClose(BrowseSLPHandle);
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdUpdatePolling: all polling processes have exited!");
+ cupsdStopPolling();
}
-#endif /* HAVE_LIBSLP */
}
+#ifdef HAVE_LIBSLP
/*
- * 'cupsdStopPolling()' - Stop polling servers as needed.
+ * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
*/
void
-cupsdStopPolling(void)
+cupsdUpdateSLPBrowse(void)
{
- int i; /* Looping var */
- cupsd_dirsvc_poll_t *pollp; /* Current polling server */
+ slpsrvurl_t *s, /* Temporary list of service URLs */
+ *next; /* Next service in list */
+ cupsd_printer_t p; /* Printer information */
+ const char *uri; /* Pointer to printer URI */
+ char method[HTTP_MAX_URI],
+ /* Method portion of URI */
+ username[HTTP_MAX_URI],
+ /* Username portion of URI */
+ host[HTTP_MAX_URI],
+ /* Host portion of URI */
+ resource[HTTP_MAX_URI];
+ /* Resource portion of URI */
+ int port; /* Port portion of URI */
- if (PollPipe >= 0)
- {
- cupsdStatBufDelete(PollStatusBuffer);
- close(PollPipe);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdUpdateSLPBrowse() Start...");
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStopPolling: removing fd %d from InputSet.", PollPipe);
- FD_CLR(PollPipe, InputSet);
+ /*
+ * Reset the refresh time...
+ */
- PollPipe = -1;
- PollStatusBuffer = NULL;
+ BrowseSLPRefresh = time(NULL) + BrowseInterval;
+
+ /*
+ * Poll for remote printers using SLP...
+ */
+
+ s = NULL;
+
+ SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
+ slp_url_callback, &s);
+
+ /*
+ * Loop through the list of available printers...
+ */
+
+ for (; s; s = next)
+ {
+ /*
+ * Save the "next" pointer...
+ */
+
+ next = s->next;
+
+ /*
+ * Load a cupsd_printer_t structure with the SLP service attributes...
+ */
+
+ SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
+
+ /*
+ * Process this printer entry...
+ */
+
+ uri = s->url + SLP_CUPS_SRVLEN + 1;
+
+ if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
+ {
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method),
+ username, sizeof(username), host, sizeof(host), &port,
+ resource, sizeof(resource));
+
+ if (!strcasecmp(host, ServerName))
+ continue;
+
+ /*
+ * OK, at least an IPP printer, see if it is a CUPS printer or
+ * class...
+ */
+
+ if (strstr(uri, "/printers/") != NULL)
+ process_browse_data(uri, p.type, IPP_PRINTER_IDLE, p.location,
+ p.info, p.make_model, 0, NULL);
+ else if (strstr(uri, "/classes/") != NULL)
+ process_browse_data(uri, p.type | CUPS_PRINTER_CLASS, IPP_PRINTER_IDLE,
+ p.location, p.info, p.make_model, 0, NULL);
+ }
+
+ /*
+ * Free this listing...
+ */
+
+ free(s);
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdUpdateSLPBrowse() End...");
+}
+#endif /* HAVE_LIBSLP */
+
+
+/*
+ * 'dequote()' - Remote quotes from a string.
+ */
+
+static char * /* O - Dequoted string */
+dequote(char *d, /* I - Destination string */
+ const char *s, /* I - Source string */
+ int dlen) /* I - Destination length */
+{
+ char *dptr; /* Pointer into destination */
+
+
+ if (s)
+ {
+ for (dptr = d, dlen --; *s && dlen > 0; s ++)
+ if (*s != '\"')
+ {
+ *dptr++ = *s;
+ dlen --;
+ }
+
+ *dptr = '\0';
}
+ else
+ *d = '\0';
- for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
- if (pollp->pid)
- cupsdEndProcess(pollp->pid, 0);
+ return (d);
}
/*
- * 'cupsdUpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol.
+ * 'process_browse_data()' - Process new browse data.
*/
-void
-cupsdUpdateCUPSBrowse(void)
+static void
+process_browse_data(
+ const char *uri, /* I - URI of printer/class */
+ 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 auth; /* Authorization status */
- int len; /* Length of name string */
- int bytes; /* Number of bytes left */
- char packet[1541], /* Broadcast packet */
- *pptr; /* Pointer into packet */
- socklen_t srclen; /* Length of source address */
- http_addr_t srcaddr; /* Source address */
- char srcname[1024]; /* Source hostname */
- unsigned address[4]; /* Source address */
- unsigned type; /* Printer type */
- unsigned state; /* Printer state */
- char uri[HTTP_MAX_URI], /* Printer URI */
+ int update; /* Update printer attributes? */
+ char finaluri[HTTP_MAX_URI], /* Final URI for printer */
method[HTTP_MAX_URI], /* Method portion of URI */
username[HTTP_MAX_URI], /* Username portion of URI */
host[HTTP_MAX_URI], /* Host portion of URI */
- resource[HTTP_MAX_URI], /* Resource portion of URI */
- info[IPP_MAX_NAME], /* Information string */
- location[IPP_MAX_NAME], /* Location string */
- make_model[IPP_MAX_NAME];/* Make and model string */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
int port; /* Port portion of URI */
- cupsd_netif_t *iface; /* Network interface */
- int num_attrs; /* Number of attributes */
- cups_option_t *attrs; /* Attributes */
+ char name[IPP_MAX_NAME], /* 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 */
/*
- * Read a packet from the browse socket...
+ * Pull the URI apart to see if this is a local or remote printer...
*/
- srclen = sizeof(srcaddr);
- if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
- (struct sockaddr *)&srcaddr, &srclen)) < 0)
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method), username,
+ sizeof(username), host, sizeof(host), &port, resource,
+ sizeof(resource));
+
+ /*
+ * Determine if the URI contains any illegal characters in it...
+ */
+
+ if (strncmp(uri, "ipp://", 6) || !host[0] ||
+ (strncmp(resource, "/printers/", 10) &&
+ strncmp(resource, "/classes/", 9)))
{
- /*
- * "Connection refused" is returned under Linux if the destination port
- * or address is unreachable from a previous sendto(); check for the
- * error here and ignore it for now...
- */
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "process_browse_data: Bad printer URI in browse data: %s",
+ uri);
+ return;
+ }
- if (errno != ECONNREFUSED && errno != EAGAIN)
+ if (strchr(resource, '?') ||
+ (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
+ (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "process_browse_data: Bad resource in browse data: %s",
+ resource);
+ return;
+ }
+
+ /*
+ * OK, this isn't a local printer; add any remote options...
+ */
+
+ ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
+
+ if (BrowseRemoteOptions)
+ {
+ if (BrowseRemoteOptions[0] == '?')
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
- strerror(errno));
- cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
+ /*
+ * Override server-supplied options...
+ */
- cupsdStopBrowsing();
- Browsing = 0;
+ snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
+ }
+ else if (ipp_options)
+ {
+ /*
+ * Combine the server and local options...
+ */
+
+ snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
+ BrowseRemoteOptions);
+ }
+ else
+ {
+ /*
+ * Just use the local options...
+ */
+
+ snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
}
- return;
+ uri = finaluri;
}
+ else if (ipp_options)
+ {
+ /*
+ * Just use the server-supplied options...
+ */
- packet[bytes] = '\0';
+ snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
+ uri = finaluri;
+ }
/*
- * If we're about to sleep, ignore incoming browse packets.
+ * See if we already have it listed in the Printers list, and add it if not...
*/
- if (Sleeping)
- return;
+ type |= CUPS_PRINTER_REMOTE;
+ type &= ~CUPS_PRINTER_IMPLICIT;
+ update = 0;
+ hptr = strchr(host, '.');
+ sptr = strchr(ServerName, '.');
- /*
- * Figure out where it came from...
- */
+ if (sptr != NULL && hptr != NULL)
+ {
+ /*
+ * Strip the common domain name components...
+ */
-#ifdef AF_INET6
- if (srcaddr.addr.sa_family == AF_INET6)
+ while (hptr != NULL)
+ {
+ if (!strcasecmp(hptr, sptr))
+ {
+ *hptr = '\0';
+ break;
+ }
+ else
+ hptr = strchr(hptr + 1, '.');
+ }
+ }
+
+ if (type & CUPS_PRINTER_CLASS)
{
- 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]);
+ /*
+ * Remote destination is a class...
+ */
+
+ if (!strncmp(resource, "/classes/", 9))
+ snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
+ else
+ return;
+
+ if ((p = cupsdFindClass(name)) == NULL && BrowseShortNames)
+ {
+ if ((p = cupsdFindClass(resource + 9)) != NULL)
+ {
+ if (p->hostname && strcasecmp(p->hostname, host))
+ {
+ /*
+ * Nope, this isn't the same host; if the hostname isn't the local host,
+ * add it to the other class and then find a class using the full host
+ * name...
+ */
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "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);
+
+ cupsArrayRemove(Printers, p);
+ cupsdSetStringf(&p->name, "%s@%s", p->name, p->hostname);
+ cupsdSetPrinterAttrs(p);
+ cupsArrayAdd(Printers, p);
+
+ 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...
+ */
+
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ update = 1;
+ }
+
+ if (!p)
+ {
+ /*
+ * Class doesn't exist; add it...
+ */
+
+ p = cupsdAddClass(name);
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "Added remote class \"%s\"...", name);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "Class \'%s\' added by directory services.", name);
+
+ /*
+ * Force the URI to point to the real server...
+ */
+
+ p->type = type & ~CUPS_PRINTER_REJECTING;
+ p->accepting = 1;
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ cupsdSetString(&p->hostname, host);
+
+ update = 1;
+ }
}
else
-#endif /* AF_INET6 */
{
- address[0] = 0;
- address[1] = 0;
- address[2] = 0;
- address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
- }
+ /*
+ * Remote destination is a printer...
+ */
+
+ if (!strncmp(resource, "/printers/", 10))
+ snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
+ else
+ return;
+
+ if ((p = cupsdFindPrinter(name)) == NULL && BrowseShortNames)
+ {
+ if ((p = cupsdFindPrinter(resource + 10)) != NULL)
+ {
+ if (p->hostname && strcasecmp(p->hostname, host))
+ {
+ /*
+ * Nope, this isn't the same host; if the hostname isn't the local host,
+ * add it to the other printer and then find a printer using the full host
+ * name...
+ */
- if (HostNameLookups)
- httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
- else
- httpAddrString(&srcaddr, srcname, sizeof(srcname));
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "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);
- len = strlen(srcname);
+ cupsArrayRemove(Printers, p);
+ cupsdSetStringf(&p->name, "%s@%s", p->name, p->hostname);
+ cupsdSetPrinterAttrs(p);
+ cupsArrayAdd(Printers, p);
- /*
- * Do ACL stuff...
- */
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "Printer \'%s\' added by directory services.",
+ p->name);
+ }
- if (BrowseACL)
- {
- if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
+ 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)
{
/*
- * Access from localhost (127.0.0.1) is always allowed...
+ * Hostname not set, so this must be a cached remote printer
+ * that was created for a pending print job...
*/
- auth = AUTH_ALLOW;
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ update = 1;
}
- else
+
+ if (!p)
{
/*
- * Do authorization checks on the domain/address...
+ * Printer doesn't exist; add it...
*/
- switch (BrowseACL->order_type)
- {
- default :
- auth = AUTH_DENY; /* anti-compiler-warning-code */
- break;
-
- case AUTH_ALLOW : /* Order Deny,Allow */
- auth = AUTH_ALLOW;
+ p = cupsdAddPrinter(name);
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_deny, BrowseACL->deny))
- auth = AUTH_DENY;
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "Printer \'%s\' added by directory services.", name);
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_allow, BrowseACL->allow))
- auth = AUTH_ALLOW;
- break;
+ cupsdLogMessage(CUPSD_LOG_INFO, "Added remote printer \"%s\"...", name);
- case AUTH_DENY : /* Order Allow,Deny */
- auth = AUTH_DENY;
+ /*
+ * Force the URI to point to the real server...
+ */
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_allow, BrowseACL->allow))
- auth = AUTH_ALLOW;
+ p->type = type & ~CUPS_PRINTER_REJECTING;
+ p->accepting = 1;
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_deny, BrowseACL->deny))
- auth = AUTH_DENY;
- break;
- }
+ update = 1;
}
}
- else
- auth = AUTH_ALLOW;
-
- if (auth == AUTH_DENY)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "cupsdUpdateCUPSBrowse: Refused %d bytes from %s", bytes,
- srcname);
- return;
- }
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdUpdateCUPSBrowse: (%d bytes from %s) %s", bytes,
- srcname, packet);
/*
- * Parse packet...
+ * Update the state...
*/
- if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
- {
- cupsdLogMessage(CUPSD_LOG_WARN,
- "cupsdUpdateCUPSBrowse: Garbled browse packet - %s", packet);
- return;
- }
-
- strcpy(location, "Location Unknown");
- strcpy(info, "No Information Available");
- make_model[0] = '\0';
- num_attrs = 0;
- attrs = NULL;
+ p->state = state;
+ p->browse_time = time(NULL);
- if ((pptr = strchr(packet, '\"')) != NULL)
+ if (type & CUPS_PRINTER_REJECTING)
{
- /*
- * Have extended information; can't use sscanf for it because not all
- * sscanf's allow empty strings with %[^\"]...
- */
-
- for (i = 0, pptr ++;
- i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
- i ++, pptr ++)
- location[i] = *pptr;
-
- if (i)
- location[i] = '\0';
-
- if (*pptr == '\"')
- pptr ++;
-
- while (*pptr && isspace(*pptr & 255))
- pptr ++;
+ type &= ~CUPS_PRINTER_REJECTING;
- if (*pptr == '\"')
+ if (p->accepting)
{
- 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);
- }
+ update = 1;
+ p->accepting = 0;
}
}
+ else if (!p->accepting)
+ {
+ update = 1;
+ p->accepting = 1;
+ }
- DEBUG_puts(packet);
- DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
- "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
- type, state, uri, location, info, make_model));
-
- /*
- * Pull the URI apart to see if this is a local or remote printer...
- */
+ if (p->type != type)
+ {
+ p->type = type;
+ update = 1;
+ }
- httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method), username,
- sizeof(username), host, sizeof(host), &port, resource,
- sizeof(resource));
+ if (location && (!p->location || strcmp(p->location, location)))
+ {
+ cupsdSetString(&p->location, location);
+ update = 1;
+ }
- DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
+ if (info && (!p->info || strcmp(p->info, info)))
+ {
+ cupsdSetString(&p->info, info);
+ update = 1;
+ }
- /*
- * Check for packets from the local server...
- */
+ 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 (!strcasecmp(host, ServerName) && port == LocalPort)
+ if (!p->make_model || strcmp(p->make_model, local_make_model))
{
- cupsFreeOptions(num_attrs, attrs);
- return;
+ cupsdSetString(&p->make_model, local_make_model);
+ update = 1;
}
- cupsdNetIFUpdate();
+ 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);
- for (iface = NetIFList; iface != NULL; iface = iface->next)
- if (!strcasecmp(host, iface->hostname) && port == iface->port)
- {
- cupsFreeOptions(num_attrs, attrs);
- return;
- }
+ cupsdExpireSubscriptions(p, NULL);
+
+ cupsdDeletePrinter(p, 1);
+ cupsdUpdateImplicitClasses();
+ }
+ else if (update)
+ {
+ cupsdSetPrinterAttrs(p);
+ cupsdUpdateImplicitClasses();
+ }
/*
- * Do relaying...
+ * See if we have a default printer... If not, make the first printer the
+ * default.
*/
- 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),
- sizeof(http_addr_t)) <= 0)
+ 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)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdUpdateCUPSBrowse: sendto failed for relay %d - %s.",
- i + 1, strerror(errno));
- cupsFreeOptions(num_attrs, attrs);
- return;
+ DefaultPrinter = p;
+ break;
}
+ }
/*
- * Process the browse data...
+ * Do auto-classing if needed...
*/
- cupsdProcessBrowseData(uri, (cups_ptype_t)type, (ipp_pstate_t)state, location,
- info, make_model, num_attrs, attrs);
- cupsFreeOptions(num_attrs, attrs);
+ process_implicit_classes();
+
+ /*
+ * Update the printcap file...
+ */
+
+ cupsdWritePrintcap();
}
/*
- * 'cupsdUpdatePolling()' - Read status messages from the poll daemons.
+ * 'process_implicit_classes()' - Create/update implicit classes as needed.
*/
-void
-cupsdUpdatePolling(void)
+static void
+process_implicit_classes(void)
{
- char *ptr, /* Pointer to end of line in buffer */
- message[1024]; /* Pointer to message text */
- int loglevel; /* Log level for message */
+ int i; /* Looping var */
+ int update; /* Update printer attributes? */
+ char name[IPP_MAX_NAME], /* Name of printer */
+ *hptr; /* Pointer into hostname */
+ cupsd_printer_t *p, /* Printer information */
+ *pclass, /* Printer class */
+ *first; /* First printer in class */
+ int offset, /* Offset of name */
+ len; /* Length of name */
- while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
- message, sizeof(message))) != NULL)
- if (!strchr(PollStatusBuffer->buffer, '\n'))
- break;
+ if (!ImplicitClasses || !Printers)
+ return;
- if (ptr == NULL)
+ /*
+ * Loop through all available printers and create classes as needed...
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
+ update = 0, pclass = NULL, first = NULL;
+ p != NULL;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
{
/*
- * All polling processes have died; stop polling...
+ * Skip implicit classes...
*/
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdUpdatePolling: all polling processes have exited!");
- cupsdStopPolling();
- }
-}
-
-
-#ifdef HAVE_LIBSLP
-/*
- * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
- */
+ if (p->type & CUPS_PRINTER_IMPLICIT)
+ {
+ len = 0;
+ continue;
+ }
-void
-cupsdUpdateSLPBrowse(void)
-{
- slpsrvurl_t *s, /* Temporary list of service URLs */
- *next; /* Next service in list */
- cupsd_printer_t p; /* Printer information */
- const char *uri; /* Pointer to printer URI */
- char method[HTTP_MAX_URI],
- /* Method portion of URI */
- username[HTTP_MAX_URI],
- /* Username portion of URI */
- host[HTTP_MAX_URI],
- /* Host portion of URI */
- resource[HTTP_MAX_URI];
- /* Resource portion of URI */
- int port; /* Port portion of URI */
+ /*
+ * If len == 0, get the length of this printer name up to the "@"
+ * sign (if any).
+ */
+ cupsArraySave(Printers);
- cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdUpdateSLPBrowse() Start...");
+ if (len > 0 &&
+ !strncasecmp(p->name, name + offset, len) &&
+ (p->name[len] == '\0' || p->name[len] == '@'))
+ {
+ /*
+ * We have more than one printer with the same name; see if
+ * we have a class, and if this printer is a member...
+ */
- /*
- * Reset the refresh time...
- */
+ if (pclass && strcasecmp(pclass->name, name))
+ {
+ if (update)
+ cupsdSetPrinterAttrs(pclass);
- BrowseSLPRefresh = time(NULL) + BrowseInterval;
+ update = 0;
+ pclass = NULL;
+ }
- /*
- * Poll for remote printers using SLP...
- */
+ if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
+ {
+ /*
+ * Need to add the class...
+ */
- s = NULL;
+ pclass = cupsdAddPrinter(name);
+ cupsArrayAdd(ImplicitPrinters, pclass);
- SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
- slp_url_callback, &s);
+ pclass->type |= CUPS_PRINTER_IMPLICIT;
+ pclass->accepting = 1;
+ pclass->state = IPP_PRINTER_IDLE;
- /*
- * Loop through the list of available printers...
- */
+ cupsdSetString(&pclass->location, p->location);
+ cupsdSetString(&pclass->info, p->info);
- for (; s; s = next)
- {
- /*
- * Save the "next" pointer...
- */
+ update = 1;
- next = s->next;
+ cupsdLogMessage(CUPSD_LOG_INFO, "Added implicit class \"%s\"...",
+ name);
+ }
- /*
- * Load a cupsd_printer_t structure with the SLP service attributes...
- */
+ if (first != NULL)
+ {
+ for (i = 0; i < pclass->num_printers; i ++)
+ if (pclass->printers[i] == first)
+ break;
- SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
+ if (i >= pclass->num_printers)
+ {
+ first->in_implicit_class = 1;
+ cupsdAddPrinterToClass(pclass, first);
+ }
- /*
- * Process this printer entry...
- */
+ first = NULL;
+ }
- uri = s->url + SLP_CUPS_SRVLEN + 1;
+ for (i = 0; i < pclass->num_printers; i ++)
+ if (pclass->printers[i] == p)
+ break;
- if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
+ if (i >= pclass->num_printers)
+ {
+ p->in_implicit_class = 1;
+ cupsdAddPrinterToClass(pclass, p);
+ update = 1;
+ }
+ }
+ else
{
/*
- * Pull the URI apart to see if this is a local or remote printer...
+ * First time around; just get name length and mark it as first
+ * in the list...
*/
- httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method),
- username, sizeof(username), host, sizeof(host), &port,
- resource, sizeof(resource));
+ if ((hptr = strchr(p->name, '@')) != NULL)
+ len = hptr - p->name;
+ else
+ len = strlen(p->name);
- if (strcasecmp(host, ServerName) == 0)
- continue;
+ strncpy(name, p->name, len);
+ name[len] = '\0';
+ offset = 0;
- /*
- * OK, at least an IPP printer, see if it is a CUPS printer or
- * class...
- */
+ if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
+ !(first->type & CUPS_PRINTER_IMPLICIT))
+ {
+ /*
+ * Can't use same name as a local printer; add "Any" to the
+ * front of the name, unless we have explicitly disabled
+ * the "ImplicitAnyClasses"...
+ */
- if (strstr(uri, "/printers/") != NULL)
- cupsdProcessBrowseData(uri, p.type, IPP_PRINTER_IDLE, p.location,
- p.info, p.make_model, 0, NULL);
- else if (strstr(uri, "/classes/") != NULL)
- cupsdProcessBrowseData(uri, p.type | CUPS_PRINTER_CLASS, IPP_PRINTER_IDLE,
- p.location, p.info, p.make_model, 0, NULL);
+ if (ImplicitAnyClasses && len < (sizeof(name) - 4))
+ {
+ /*
+ * Add "Any" to the class name...
+ */
+
+ strcpy(name, "Any");
+ strncpy(name + 3, p->name, len);
+ name[len + 3] = '\0';
+ offset = 3;
+ }
+ else
+ {
+ /*
+ * Don't create an implicit class if we have a local printer
+ * with the same name...
+ */
+
+ len = 0;
+ cupsArrayRestore(Printers);
+ continue;
+ }
+ }
+
+ first = p;
}
- /*
- * Free this listing...
- */
+ cupsArrayRestore(Printers);
+ }
- free(s);
- }
+ /*
+ * Update the last printer class as needed...
+ */
- cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdUpdateSLPBrowse() End...");
+ if (pclass && update)
+ cupsdSetPrinterAttrs(pclass);
}
+#ifdef HAVE_LIBSLP
/*
* 'slp_attr_callback()' - SLP attribute callback
*/
if (slp_get_attr(attrlist, "(color-supported=", &tmp))
return (SLP_FALSE);
- if (strcasecmp(tmp, "true") == 0)
+ if (!strcasecmp(tmp, "true"))
p->type |= CUPS_PRINTER_COLOR;
if (slp_get_attr(attrlist, "(finishings-supported=", &tmp))
/*
- * End of "$Id: dirsvc.c 5023 2006-01-29 14:39:44Z mike $".
+ * End of "$Id: dirsvc.c 5043 2006-02-01 18:55:16Z mike $".
*/