- process_implicit_classes();
-}
-
-
-/*
- * 'cupsdRegisterPrinter()' - Start sending broadcast information for a
- * printer or update the broadcast contents.
- */
-
-void
-cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
-{
- if (!Browsing || !BrowseLocalProtocols ||
- (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
- return;
-
-#ifdef HAVE_LIBSLP
-/* if (BrowseLocalProtocols & BROWSE_SLP)
- slpRegisterPrinter(p); */
-#endif /* HAVE_LIBSLP */
-
-#ifdef HAVE_DNSSD
- if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
- dnssdRegisterPrinter(p);
-#endif /* HAVE_DNSSD */
-}
-
-
-/*
- * 'cupsdRestartPolling()' - Restart polling servers as needed.
- */
-
-void
-cupsdRestartPolling(void)
-{
- int i; /* Looping var */
- cupsd_dirsvc_poll_t *pollp; /* Current polling server */
-
-
- for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
- if (pollp->pid)
- kill(pollp->pid, SIGHUP);
-}
-
-
-/*
- * 'cupsdSaveRemoteCache()' - Save the remote printer cache.
- */
-
-void
-cupsdSaveRemoteCache(void)
-{
- 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 */
- cups_option_t *option; /* Current option */
-
-
- /*
- * 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_DEBUG, "Saving remote.cache...");
-
- /*
- * Restrict access to the file...
- */
-
- fchown(cupsFileNumber(fp), getuid(), Group);
- fchmod(cupsFileNumber(fp), ConfigFilePerm);
-
- /*
- * Write a small header to the file...
- */
-
- 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);
-
- /*
- * Write each local printer known to the system...
- */
-
- for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
- printer;
- printer = (cupsd_printer_t *)cupsArrayNext(Printers))
- {
- /*
- * Skip local destinations...
- */
-
- if (!(printer->type & CUPS_PRINTER_DISCOVERED))
- continue;
-
- /*
- * Write printers as needed...
- */
-
- 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);
-}
-
-
-/*
- * 'cupsdSendBrowseList()' - Send new browsing information as necessary.
- */
-
-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 (!Browsing || !Printers)
- return;
-
- /*
- * Compute the update and timeout times...
- */
-
- to = time(NULL);
- ut = to - BrowseInterval;
-
- /*
- * Figure out how many printers need an update...
- */
-
- if (BrowseInterval > 0 && BrowseLocalProtocols)
- {
- 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))
- {
- /*
- * 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...
- */
-
- 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 /* HAVE_LIBSLP */
-
-#ifdef HAVE_LDAP
- if (BrowseLocalProtocols & BROWSE_LDAP)
- send_ldap_browse(p);
-#endif /* HAVE_LDAP */
- }
- }
-
- /*
- * Save where we left off so that all printers get updated...
- */
-
- BrowseNext = p;
- }
-
- /*
- * Loop through all of the printers and timeout old printers as needed...
- */
-
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
- p;
- p = (cupsd_printer_t *)cupsArrayNext(Printers))
- {
- /*
- * If this is a remote queue, see if it needs to be timed out...
- */
-
- 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);
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
- }
- }
-}
-
-
-#ifdef HAVE_LDAP_REBIND_PROC
-# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-/*
- * 'ldap_rebind_proc()' - Callback function for LDAP rebind
- */
-
-static int
-ldap_rebind_proc (LDAP *RebindLDAPHandle,
- LDAP_CONST char *refsp,
- ber_tag_t request,
- ber_int_t msgid,
- void *params)
-{
- int rc;
-
- /*
- * Bind to new LDAP server...
- */
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "ldap_rebind_proc: Rebind to %s", refsp);
-
-# if LDAP_API_VERSION > 3000
- struct berval bval;
- bval.bv_val = BrowseLDAPPassword;
- bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
-
- rc = ldap_sasl_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL);
-# else
- rc = ldap_bind_s(RebindLDAPHandle, BrowseLDAPBindDN,
- BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
-# endif /* LDAP_API_VERSION > 3000 */
-
- return (rc);
-}
-
-# else /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
-
-/*
- * 'ldap_rebind_proc()' - Callback function for LDAP rebind
- */
-
-static int
-ldap_rebind_proc (LDAP *RebindLDAPHandle,
- char **dnp,
- char **passwdp,
- int *authmethodp,
- int freeit,
- void *arg)
-{
- switch ( freeit ) {
-
- case 1:
-
- /*
- * Free current values...
- */
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "ldap_rebind_proc: Free values...");
-
- if ( dnp && *dnp ) {
- free( *dnp );
- }
- if ( passwdp && *passwdp ) {
- free( *passwdp );
- }
- break;
-
- case 0:
-
- /*
- * Return credentials for LDAP referal...
- */
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "ldap_rebind_proc: Return necessary values...");
-
- *dnp = strdup(BrowseLDAPBindDN);
- *passwdp = strdup(BrowseLDAPPassword);
- *authmethodp = LDAP_AUTH_SIMPLE;
- break;
-
- default:
-
- /*
- * Should never happen...
- */
-
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LDAP rebind has been called with wrong freeit value!");
- break;
-
- }
-
- return (LDAP_SUCCESS);
-}
-# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
-#endif /* HAVE_LDAP_REBIND_PROC */
-
-
-#ifdef HAVE_LDAP
-/*
- * 'ldap_connect()' - Start new LDAP connection
- */
-
-static LDAP *
-ldap_connect(void)
-{
- /*
- * Open LDAP handle...
- */
-
- int rc; /* LDAP API status */
- int version = 3; /* LDAP version */
- struct berval bv = {0, ""}; /* SASL bind value */
- LDAP *TempBrowseLDAPHandle=NULL; /* Temporary LDAP Handle */
-# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
- int ldap_ssl = 0; /* LDAP SSL indicator */
- int ssl_err = 0; /* LDAP SSL error value */
-# endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
-
-# ifdef HAVE_OPENLDAP
-# ifdef HAVE_LDAP_SSL
-
- /*
- * Set the certificate file to use for encrypted LDAP sessions...
- */
-
- if (BrowseLDAPCACertFile)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "cupsdStartBrowsing: Setting CA certificate file \"%s\"",
- BrowseLDAPCACertFile);
-
- if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
- (void *)BrowseLDAPCACertFile)) != LDAP_SUCCESS)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to set CA certificate file for LDAP "
- "connections: %d - %s", rc, ldap_err2string(rc));
- }
-
-# endif /* HAVE_LDAP_SSL */
- /*
- * Initialize OPENLDAP connection...
- * LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
- */
-
- if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
- rc = ldap_initialize(&TempBrowseLDAPHandle, "ldapi:///");
- else
- rc = ldap_initialize(&TempBrowseLDAPHandle, BrowseLDAPServer);
-
-# else /* HAVE_OPENLDAP */
-
- int ldap_port = 0; /* LDAP port */
- char ldap_protocol[11], /* LDAP protocol */
- ldap_host[255]; /* LDAP host */
-
- /*
- * Split LDAP URI into its components...
- */
-
- if (! BrowseLDAPServer)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "BrowseLDAPServer not configured! Disable LDAP browsing!");
- BrowseLocalProtocols &= ~BROWSE_LDAP;
- BrowseRemoteProtocols &= ~BROWSE_LDAP;
- return (NULL);
- }
-
- sscanf(BrowseLDAPServer, "%10[^:]://%254[^:/]:%d", ldap_protocol, ldap_host, &ldap_port);
-
- if (strcmp(ldap_protocol, "ldap") == 0) {
- ldap_ssl = 0;
- } else if (strcmp(ldap_protocol, "ldaps") == 0) {
- ldap_ssl = 1;
- } else {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "unrecognised ldap protocol (%s)!", ldap_protocol);
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Disable LDAP browsing!");
- BrowseLocalProtocols &= ~BROWSE_LDAP;
- BrowseRemoteProtocols &= ~BROWSE_LDAP;
- return (NULL);
- }
-
- if (ldap_port == 0)
- {
- if (ldap_ssl)
- ldap_port = LDAPS_PORT;
- else
- ldap_port = LDAP_PORT;
- }
-
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "LDAP Connection Details: PROT:%s HOST:%s PORT:%d",
- ldap_protocol, ldap_host, ldap_port);
-
- /*
- * Initialize LDAP connection...
- */
-
- if (! ldap_ssl)
- {
- if ((TempBrowseLDAPHandle = ldap_init(ldap_host, ldap_port)) == NULL)
- rc = LDAP_OPERATIONS_ERROR;
- else
- rc = LDAP_SUCCESS;
-
-# ifdef HAVE_LDAP_SSL
- }
- else
- {
-
- /*
- * Initialize SSL LDAP connection...
- */
- if (BrowseLDAPCACertFile)
- {
- rc = ldapssl_client_init(BrowseLDAPCACertFile, (void *)NULL);
- if (rc != LDAP_SUCCESS) {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Failed to initialize LDAP SSL client!");
- rc = LDAP_OPERATIONS_ERROR;
- } else {
- if ((TempBrowseLDAPHandle = ldapssl_init(ldap_host, ldap_port, 1)) == NULL)
- rc = LDAP_OPERATIONS_ERROR;
- else
- rc = LDAP_SUCCESS;
- }
- }
- else
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LDAP SSL certificate file/database not configured!");
- rc = LDAP_OPERATIONS_ERROR;
- }
-
-# else /* HAVE_LDAP_SSL */
-
- /*
- * Return error, because client libraries doesn't support SSL
- */
-
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LDAP client libraries does not support TLS");
- rc = LDAP_OPERATIONS_ERROR;
-
-# endif /* HAVE_LDAP_SSL */
- }
-# endif /* HAVE_OPENLDAP */
-
- /*
- * Check return code from LDAP initialize...
- */
-
- if (rc != LDAP_SUCCESS)
- {
- if ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR))
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to initialize LDAP! Temporary disable LDAP browsing...");
- }
- else
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to initialize LDAP! Disable LDAP browsing!");
- BrowseLocalProtocols &= ~BROWSE_LDAP;
- BrowseRemoteProtocols &= ~BROWSE_LDAP;
- }
-
- ldap_disconnect(TempBrowseLDAPHandle);
- TempBrowseLDAPHandle = NULL;
- }
-
- /*
- * Upgrade LDAP version...
- */
-
- else if (ldap_set_option(TempBrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
- (const void *)&version) != LDAP_SUCCESS)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to set LDAP protocol version %d! Disable LDAP browsing!",
- version);
- BrowseLocalProtocols &= ~BROWSE_LDAP;
- BrowseRemoteProtocols &= ~BROWSE_LDAP;
- ldap_disconnect(TempBrowseLDAPHandle);
- TempBrowseLDAPHandle = NULL;
- }
- else
- {
-
- /*
- * Register LDAP rebind procedure...
- */
-
-# ifdef HAVE_LDAP_REBIND_PROC
-# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-
- rc = ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL);
- if ( rc != LDAP_SUCCESS )
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Setting LDAP rebind function failed with status %d: %s",
- rc, ldap_err2string(rc));
-
-# else
-
- ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL);
-
-# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
-# endif /* HAVE_LDAP_REBIND_PROC */
-
- /*
- * Start LDAP bind...
- */
-
-# if LDAP_API_VERSION > 3000
- struct berval bval;
- bval.bv_val = BrowseLDAPPassword;
- bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
-
- if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
- rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
- NULL, NULL);
- else
- rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL);
-# else
- rc = ldap_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN,
- BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
-# endif /* LDAP_API_VERSION > 3000 */
-
- if (rc != LDAP_SUCCESS)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LDAP bind failed with error %d: %s",
- rc, ldap_err2string(rc));
-# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
- if (ldap_ssl && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR)))
- {
- ssl_err = PORT_GetError();
- if (ssl_err != 0)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LDAP SSL error %d: %s",
- ssl_err, ldapssl_err2string(ssl_err));
- }
-# endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
- ldap_disconnect(TempBrowseLDAPHandle);
- TempBrowseLDAPHandle = NULL;
- }
- else
- {
- cupsdLogMessage(CUPSD_LOG_INFO,
- "LDAP connection established");
- }
-
- }
- return (TempBrowseLDAPHandle);
-}
-
-
-/*
- * 'ldap_reconnect()' - Reconnect to LDAP Server
- */
-
-static void
-ldap_reconnect(void)
-{
- LDAP *TempBrowseLDAPHandle = NULL; /* Temp Handle to LDAP server */
-
- cupsdLogMessage(CUPSD_LOG_INFO,
- "Try LDAP reconnect...");
-
- /*
- * Get a new LDAP Handle and replace the global Handle
- * if the new connection was successful
- */
-
- TempBrowseLDAPHandle = ldap_connect();
-
- if (TempBrowseLDAPHandle != NULL)
- {
- if (BrowseLDAPHandle != NULL)
- {
- ldap_disconnect(BrowseLDAPHandle);
- }
- BrowseLDAPHandle = TempBrowseLDAPHandle;
- }
-}
-
-
-/*
- * 'ldap_disconnect()' - Disconnect from LDAP Server
- */
-
-static void
-ldap_disconnect(LDAP *ld) /* I - LDAP handle */
-{
- int rc; /* return code */
-
- /*
- * Close LDAP handle...
- */
-
-# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
- rc = ldap_unbind_ext_s(ld, NULL, NULL);
-# else
- rc = ldap_unbind_s(ld);
-# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
- if (rc != LDAP_SUCCESS)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unbind from LDAP server failed with status %d: %s",
- rc, ldap_err2string(rc));
-}
-#endif /* HAVE_LDAP */
-
-
-/*
- * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
- */
-
-void
-cupsdStartBrowsing(void)
-{
- int val; /* Socket option value */
- struct sockaddr_in addr; /* Broadcast address */
- cupsd_printer_t *p; /* Current printer */
-
-
- BrowseNext = NULL;
-
- if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
- return;
-
- if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
- {
- if (BrowseSocket < 0)
- {
- /*
- * Create the broadcast socket...
- */
-
- 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;
-
- if (FatalErrors & CUPSD_FATAL_BROWSE)
- cupsdEndProcess(getpid(), 0);
- }
- }
-
- if (BrowseSocket >= 0)
- {
- /*
- * 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);
-
- 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 /* WIN32 */
-
- BrowseSocket = -1;
- BrowseLocalProtocols &= ~BROWSE_CUPS;
- BrowseRemoteProtocols &= ~BROWSE_CUPS;
-
- if (FatalErrors & CUPSD_FATAL_BROWSE)
- cupsdEndProcess(getpid(), 0);
- }
- }
-
- if (BrowseSocket >= 0)
- {
- /*
- * Set the "broadcast" flag...
- */
-
- 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 /* WIN32 */
-
- BrowseSocket = -1;
- BrowseLocalProtocols &= ~BROWSE_CUPS;
- BrowseRemoteProtocols &= ~BROWSE_CUPS;
-
- if (FatalErrors & CUPSD_FATAL_BROWSE)
- cupsdEndProcess(getpid(), 0);
- }
- }
-
- if (BrowseSocket >= 0)
- {
- /*
- * Close the socket on exec...
- */
-
- fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
-
- /*
- * Finally, add the socket to the input selection set as needed...
- */
-
- if (BrowseRemoteProtocols & BROWSE_CUPS)
- {
- /*
- * We only listen if we want remote printers...
- */
-
- cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
- NULL, NULL);
- }
- }
- }
- else
- BrowseSocket = -1;
-
-#ifdef HAVE_DNSSD
- if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
- {
- DNSServiceErrorType error; /* Error from service creation */
- cupsd_listener_t *lis; /* Current listening socket */
-
-
- /*
- * First create a "master" connection for all registrations...
- */
-
- if ((error = DNSServiceCreateConnection(&DNSSDRef))
- != kDNSServiceErr_NoError)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to create master DNS-SD reference: %d", error);
-
- if (FatalErrors & CUPSD_FATAL_BROWSE)
- cupsdEndProcess(getpid(), 0);
- }
- else
- {
- /*
- * Add the master connection to the select list...
- */
-
- cupsdAddSelect(DNSServiceRefSockFD(DNSSDRef),
- (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
-
- /*
- * Then get the port we use for registrations. If we are not listening
- * on any non-local ports, there is no sense sharing local printers via
- * Bonjour...
- */
-
- DNSSDPort = 0;
-
- for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
- lis;
- lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
- {
- if (httpAddrLocalhost(&(lis->address)))
- continue;
-
- if (lis->address.addr.sa_family == AF_INET)
- {
- DNSSDPort = ntohs(lis->address.ipv4.sin_port);
- break;
- }
- else if (lis->address.addr.sa_family == AF_INET6)
- {
- DNSSDPort = ntohs(lis->address.ipv6.sin6_port);
- break;
- }
- }
-
- /*
- * Create an array to track the printers we share...
- */
-
- if (BrowseRemoteProtocols & BROWSE_DNSSD)
- DNSSDPrinters = cupsArrayNew((cups_array_func_t)dnssdComparePrinters,
- NULL);
-
- /*
- * Set the computer name and register the web interface...
- */
-
- cupsdUpdateDNSSDName();
- }
- }
-#endif /* HAVE_DNSSD */
-
-#ifdef HAVE_LIBSLP
- if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
- {
- /*
- * 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;
- BrowseSLPHandle = NULL;
-
- if (FatalErrors & CUPSD_FATAL_BROWSE)
- cupsdEndProcess(getpid(), 0);
- }
-
- BrowseSLPRefresh = 0;
- }
- else
- BrowseSLPHandle = NULL;
-#endif /* HAVE_LIBSLP */
-
-#ifdef HAVE_LDAP
- 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;
-
- if (FatalErrors & CUPSD_FATAL_BROWSE)
- cupsdEndProcess(getpid(), 0);
- }
- else
- {
- /*
- * Open LDAP handle...
- */
-
- if ((BrowseLDAPHandle = ldap_connect()) == NULL &&
- (FatalErrors & CUPSD_FATAL_BROWSE))
- cupsdEndProcess(getpid(), 0);
- }
-
- BrowseLDAPRefresh = 0;
- }
-#endif /* HAVE_LDAP */
-
- /*
- * Enable LPD and SMB printer sharing as needed through external programs...
- */
-
- if (BrowseLocalProtocols & BROWSE_LPD)
- update_lpd(1);
-
- if (BrowseLocalProtocols & BROWSE_SMB)
- update_smb(1);
-
- /*
- * Register the individual printers
- */
-
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
- p;
- p = (cupsd_printer_t *)cupsArrayNext(Printers))
- if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
- cupsdRegisterPrinter(p);
-}
-
-
-/*
- * '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[255]; /* Server port */
- char bport[255]; /* Browser port */
- char interval[255]; /* Poll interval */
- int statusfds[2]; /* Status pipe */
- char *argv[6]; /* Arguments */
- char *envp[100]; /* Environment */
-
-
- /*
- * Don't do anything if we aren't polling...
- */
-
- if (NumPolled == 0 || BrowseSocket < 0)
- {
- PollPipe = -1;
- PollStatusBuffer = NULL;
- return;
- }
-
- /*
- * Setup string arguments for polld, port and interval options.
- */
-
- 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])));
-
- /*
- * Create a pipe that receives the status messages from each
- * polling daemon...
- */
-
- 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]");
-
- /*
- * Run each polling daemon, redirecting stderr to the polling pipe...
- */
-
- 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, DefaultProfile, &(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]);
-
- /*
- * Finally, add the pipe to the input selection set...
- */
-
- cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
-}
-
-
-/*
- * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
- */
-
-void
-cupsdStopBrowsing(void)
-{
- cupsd_printer_t *p; /* Current printer */
-
-
- if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
- return;
-
- /*
- * De-register the individual printers
- */
-
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
- p;
- p = (cupsd_printer_t *)cupsArrayNext(Printers))
- if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
- cupsdDeregisterPrinter(p, 1);
-
- /*
- * Shut down browsing sockets...
- */
-
- if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
- BrowseSocket >= 0)
- {
- /*
- * Close the socket and remove it from the input selection set.
- */
-
-#ifdef WIN32
- closesocket(BrowseSocket);
-#else
- close(BrowseSocket);
-#endif /* WIN32 */
-
- cupsdRemoveSelect(BrowseSocket);
- BrowseSocket = -1;
- }
-
-#ifdef HAVE_DNSSD
- if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
- {
- if (WebIFRef)
- {
- DNSServiceRefDeallocate(WebIFRef);
- WebIFRef = NULL;
- }
-
- if (RemoteRef)
- {
- DNSServiceRefDeallocate(RemoteRef);
- RemoteRef = NULL;
- }
-
- cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef));
-
- DNSServiceRefDeallocate(DNSSDRef);
- DNSSDRef = NULL;
-
- cupsArrayDelete(DNSSDPrinters);
- DNSSDPrinters = NULL;
-
- DNSSDPort = 0;
- }
-#endif /* HAVE_DNSSD */
-
-#ifdef HAVE_LIBSLP
- if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
- BrowseSLPHandle)
- {
- /*
- * Close SLP handle...
- */
-
- SLPClose(BrowseSLPHandle);
- BrowseSLPHandle = NULL;
- }
-#endif /* HAVE_LIBSLP */
-
-#ifdef HAVE_LDAP
- if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
- BrowseLDAPHandle)
- {
- ldap_dereg_ou(ServerName, BrowseLDAPDN);
- ldap_disconnect(BrowseLDAPHandle);
- BrowseLDAPHandle = NULL;
- }
-#endif /* HAVE_OPENLDAP */
-
- /*
- * Disable LPD and SMB printer sharing as needed through external programs...
- */
-
- if (BrowseLocalProtocols & BROWSE_LPD)
- update_lpd(0);
-
- if (BrowseLocalProtocols & BROWSE_SMB)
- update_smb(0);
-}
-
-
-/*
- * 'cupsdStopPolling()' - Stop polling servers as needed.
- */
-
-void
-cupsdStopPolling(void)
-{
- int i; /* Looping var */
- cupsd_dirsvc_poll_t *pollp; /* Current polling server */
-
-
- 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
-/*
- * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
- */
-
-void
-cupsdUpdateDNSSDName(void)
-{
- DNSServiceErrorType error; /* Error from service creation */
- char webif[1024]; /* Web interface share name */
-#ifdef HAVE_COREFOUNDATION_H
- CFStringRef nameRef; /* Computer name CFString */
- char nameBuffer[1024]; /* C-string buffer */
- CFStringEncoding nameEncoding; /* Computer name encoding */
-#endif /* HAVE_COREFOUNDATION_H */
-
-
- /*
- * Only share the web interface and printers when non-local listening is
- * enabled...
- */
-
- if (!DNSSDPort)
- return;
-
- /*
- * Get the computer name as a c-string...
- */
-
-#ifdef HAVE_COREFOUNDATION_H
- cupsdClearString(&DNSSDName);
-
- if ((nameRef = SCDynamicStoreCopyComputerName(NULL,
- &nameEncoding)) != NULL)
- {
- if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
- kCFStringEncodingUTF8))
- cupsdSetString(&DNSSDName, nameBuffer);
-
- CFRelease(nameRef);
- }
-
-#else
- cupsdSetString(&DNSSDName, ServerName);
-#endif /* HAVE_COREFOUNDATION_H */
-
- /*
- * Then (re)register the web interface...
- */
-
- if (DNSSDName)
- snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDName);
- else
- strlcpy(webif, "CUPS Web Interface", sizeof(webif));
-
- if (WebIFRef)
- DNSServiceRefDeallocate(WebIFRef);
-
- WebIFRef = DNSSDRef;
- if ((error = DNSServiceRegister(&WebIFRef,
- kDNSServiceFlagsShareConnection,
- 0, webif, "_http._tcp", NULL,
- NULL, htons(DNSSDPort), 7,
- "\006path=/", dnssdRegisterCallback,
- NULL)) != kDNSServiceErr_NoError)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "DNS-SD web interface registration failed: %d", error);
-}
-#endif /* HAVE_DNSSD */
-
-
-#ifdef HAVE_LDAP
-/*
- * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
- */
-
-void
-cupsdUpdateLDAPBrowse(void)
-{
- char uri[HTTP_MAX_URI], /* Printer URI */
- host[HTTP_MAX_URI], /* Hostname */
- resource[HTTP_MAX_URI], /* Resource path */
- location[1024], /* Printer location */
- info[1024], /* Printer information */
- make_model[1024], /* Printer make and model */
- type_num[30]; /* Printer type number */
- int type; /* Printer type */
- int rc; /* LDAP status */
- int limit; /* Size limit */
- LDAPMessage *res, /* LDAP search results */
- *e; /* Current entry from search */
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
-
- BrowseLDAPRefresh = time(NULL) + BrowseInterval;
-
- /*
- * Reconnect if LDAP Handle is invalid...
- */
-
- if (! BrowseLDAPHandle)
- {
- ldap_reconnect();
- return;
- }
-
- /*
- * Search for cups printers in LDAP directory...
- */
-
- rc = ldap_search_rec(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
- "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
-
- /*
- * If ldap search was successfull then exit function
- * and temporary disable LDAP updates...
- */
-
- if (rc != LDAP_SUCCESS)
- {
- if (BrowseLDAPUpdate && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR)))
- {
- BrowseLDAPUpdate = FALSE;
- cupsdLogMessage(CUPSD_LOG_INFO,
- "LDAP update temporary disabled");
- }
- return;
- }
-
- /*
- * If LDAP updates were disabled, we will reenable them...
- */
-
- if (! BrowseLDAPUpdate)
- {
- BrowseLDAPUpdate = TRUE;
- cupsdLogMessage(CUPSD_LOG_INFO,
- "LDAP update enabled");
- }
-
- /*
- * Count LDAP entries and return if no entry exist...
- */
-
- limit = ldap_count_entries(BrowseLDAPHandle, res);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
- if (limit < 1)
- {
- ldap_freeres(res);
- return;
- }
-
- /*
- * Loop through the available printers...
- */
-
- for (e = ldap_first_entry(BrowseLDAPHandle, res);
- e;
- e = ldap_next_entry(BrowseLDAPHandle, e))
- {
- /*
- * Get the required values from this entry...
- */
-
- if (ldap_getval_firststring(BrowseLDAPHandle, e,
- "printerDescription", info, sizeof(info)) == -1)
- continue;
-
- if (ldap_getval_firststring(BrowseLDAPHandle, e,
- "printerLocation", location, sizeof(location)) == -1)
- continue;
-
- if (ldap_getval_firststring(BrowseLDAPHandle, e,
- "printerMakeAndModel", make_model, sizeof(make_model)) == -1)
- continue;
-
- if (ldap_getval_firststring(BrowseLDAPHandle, e,
- "printerType", type_num, sizeof(type_num)) == -1)
- continue;
-
- type = atoi(type_num);
-
- if (ldap_getval_firststring(BrowseLDAPHandle, e,
- "printerURI", uri, sizeof(uri)) == -1)
- continue;
-
- /*
- * Process the entry as browse data...
- */
-
- 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);
-
- }
-
- ldap_freeres(res);
-}
-#endif /* HAVE_LDAP */
-
-
-#ifdef HAVE_LIBSLP
-/*
- * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
- */
-
-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 host[HTTP_MAX_URI], /* Host portion of URI */
- resource[HTTP_MAX_URI]; /* Resource portion of URI */
-
-
- /*
- * Reset the refresh time...
- */
-
- 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...
- */
-
- 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);
- }
-
- /*
- * Free this listing...
- */
-
- cupsdClearString(&p.info);
- cupsdClearString(&p.location);
- cupsdClearString(&p.make_model);
-
- free(s);
- }
-}
-#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';
-
- return (d);
-}
-
-
-#ifdef HAVE_DNSSD
-/*
- * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
- */
-
-static char * /* O - TXT record */
-dnssdBuildTxtRecord(
- int *txt_len, /* O - TXT record length */
- cupsd_printer_t *p, /* I - Printer information */
- int for_lpd) /* I - 1 = LPD, 0 = IPP */
-{
- int i, j; /* Looping vars */
- char type_str[32], /* Type to string buffer */
- state_str[32], /* State to string buffer */
- rp_str[1024], /* Queue name string buffer */
- air_str[1024], /* auth-info-required string buffer */
- *keyvalue[32][2]; /* Table of key/value pairs */
-
-
- /*
- * Load up the key value pairs...
- */
-
- 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;
- if (for_lpd)
- strlcpy(rp_str, p->name, sizeof(rp_str));
- else
- snprintf(rp_str, sizeof(rp_str), "%s/%s",
- (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
-
- 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] = "priority";
- keyvalue[i++][1] = for_lpd ? "100" : "0";
-
- keyvalue[i ][0] = "product";
- keyvalue[i++][1] = p->product ? p->product : "Unknown";
-
- snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
- snprintf(state_str, sizeof(state_str), "%d", p->state);
-
- 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; /* Pointer into string */
-
-
- for (j = 0; j < p->num_auth_info_required; j ++)
- {
- if (air >= (air_str + sizeof(air_str) - 2))
- break;
-
- if (j)
- *air++ = ',';
-
- strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str));
- air += strlen(air);
- }
-
- keyvalue[i ][0] = "air";
- keyvalue[i++][1] = air_str;
- }
-
- /*
- * Then pack them into a proper txt record...
- */
-
- return (dnssdPackTxtRecord(txt_len, keyvalue, i));
-}
-
-
-/*
- * 'dnssdComparePrinters()' - Compare the registered names of two printers.
- */
-
-static int /* O - Result of comparison */
-dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */
- cupsd_printer_t *b)/* I - Second printer */
-{
- return (strcasecmp(a->reg_name, b->reg_name));
-}
-
-
-/*
- * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
- * printer.
- */
-
-static void
-dnssdDeregisterPrinter(
- cupsd_printer_t *p) /* I - Printer */
-{
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
-
- /*
- * Closing the socket deregisters the service
- */
-
- if (p->ipp_ref)
- {
- DNSServiceRefDeallocate(p->ipp_ref);
- p->ipp_ref = NULL;
- }
-
- cupsArrayRemove(DNSSDPrinters, p);
- cupsdClearString(&p->reg_name);
-
- if (p->ipp_txt)
- {
- /*
- * p->ipp_txt is malloc'd, not _cupsStrAlloc'd...
- */
-
- free(p->ipp_txt);
- p->ipp_txt = NULL;
- }
-}
-
-
-/*
- * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
- * TXT record format.
- */
-
-static char * /* O - TXT record */
-dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
- char *keyvalue[][2], /* I - Table of key value pairs */
- int count) /* I - Items in table */
-{
- int i; /* Looping var */
- int length; /* Length of TXT record */
- int length2; /* Length of value */
- char *txtRecord; /* TXT record buffer */
- char *cursor; /* Looping pointer */
-
-
- /*
- * Calculate the buffer size
- */
-
- for (length = i = 0; i < count; i++)
- length += 1 + strlen(keyvalue[i][0]) +
- (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
-
- /*
- * Allocate and fill it
- */
-
- txtRecord = malloc(length);
- if (txtRecord)
- {
- *txt_len = length;
-
- for (cursor = txtRecord, i = 0; i < count; i++)
- {
- /*
- * Drop in the p-string style length byte followed by the data
- */
-
- 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);
-}
-
-
-/*
- * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
- */
-
-static void
-dnssdRegisterCallback(
- DNSServiceRef sdRef, /* I - DNS Service reference */
- DNSServiceFlags flags, /* I - Reserved for future use */
- DNSServiceErrorType errorCode, /* I - Error code */
- const char *name, /* I - Service name */
- const char *regtype, /* I - Service type */
- const char *domain, /* I - Domain. ".local" for now */
- void *context) /* I - User-defined context */
-{
- cupsd_printer_t *p = (cupsd_printer_t *)context;
- /* Current printer */
-
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s",
- name, regtype, p ? p->name : "Web Interface");
-
- if (errorCode)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "DNSServiceRegister failed with error %d", (int)errorCode);
- return;
- }
- else if (p && strcasecmp(name, p->reg_name))
- {
- cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
- name, p->name);
-
- cupsArrayRemove(DNSSDPrinters, p);
- cupsdSetString(&p->reg_name, name);
- cupsArrayAdd(DNSSDPrinters, p);
-
- LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
- }
-}
-
-
-/*
- * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
- * or update the broadcast contents.
- */
-
-static void
-dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
-{
- DNSServiceErrorType se; /* dnssd errors */
- char *ipp_txt, /* IPP TXT record buffer */
- *printer_txt, /* LPD TXT record buffer */
- name[1024], /* Service name */
- *nameptr; /* Pointer into name */
- int ipp_len, /* IPP TXT record length */
- printer_len; /* LPD TXT record length */
- char resource[1024]; /* Resource path for printer */
- const char *regtype; /* Registration type */
- const char *domain; /* Registration domain */
- cupsd_location_t *location, /* Printer location */
- *policy; /* Operation policy for Print-Job */
- unsigned address[4]; /* INADDR_ANY address */
-
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
- !p->ipp_ref ? "new" : "update");
-
- /*
- * If per-printer sharing was just disabled make sure we're not
- * registered before returning.
- */
-
- if (!p->shared)
- {
- dnssdDeregisterPrinter(p);
- return;
- }
-
- /*
- * The registered name takes the form of "<printer-info> @ <computer name>"...
- */
-
- if (p->info && strlen(p->info) > 0)
- {
- if (DNSSDName)
- snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDName);
- else
- strlcpy(name, p->info, sizeof(name));
- }
- else if (DNSSDName)
- snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDName);
- else
- strlcpy(name, p->name, sizeof(name));
-
- /*
- * If an existing printer was renamed, unregister it and start over...
- */
-
- if (p->reg_name && strcmp(p->reg_name, name))
- dnssdDeregisterPrinter(p);
-
- if (!p->reg_name)
- {
- cupsdSetString(&p->reg_name, name);
- cupsArrayAdd(DNSSDPrinters, p);
- }
-
- /*
- * If 'Allow printing from the Internet' is enabled (i.e. from any address)
- * let dnssd decide on the domain, otherwise restrict it to ".local".
- */
-
- if (p->type & CUPS_PRINTER_CLASS)
- snprintf(resource, sizeof(resource), "/classes/%s", p->name);
- else
- snprintf(resource, sizeof(resource), "/printers/%s", p->name);
-
- address[0] = address[1] = address[2] = address[3] = 0;
- location = cupsdFindBest(resource, HTTP_POST);
- policy = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
-
- if ((location && !cupsdCheckAccess(address, "", 0, location)) ||
- (policy && !cupsdCheckAccess(address, "", 0, policy)))
- domain = "local.";
- else
- domain = NULL;
-
- /*
- * Register IPP and (optionally) LPD...
- */
-
- ipp_len = 0; /* anti-compiler-warning-code */
- ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
-
- if (!p->ipp_ref)
- {
- /*
- * Initial registration. Use the _fax subtype for fax queues...
- */
-
- regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" :
- "_ipp._tcp,_cups";
-
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "Registering DNS-SD printer %s with name \"%s\", "
- "type \"%s\", and domain \"%s\"", p->name, name, regtype,
- domain ? domain : "(null)");
-
- /*
- * Register the queue, dropping characters as needed until we succeed...
- */
-
- nameptr = name + strlen(name);
-
- do
- {
- p->ipp_ref = DNSSDRef;
- if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection,
- 0, name, regtype, domain, NULL,
- htons(DNSSDPort), ipp_len, ipp_txt,
- dnssdRegisterCallback,
- p)) == kDNSServiceErr_BadParam)
- {
- /*
- * Name is too long, drop trailing characters, taking into account
- * UTF-8 encoding...
- */
-
- nameptr --;
-
- while (nameptr > name && (*nameptr & 0xc0) == 0x80)
- nameptr --;
-
- if (nameptr > name)
- *nameptr = '\0';
- }
- }
- while (se == kDNSServiceErr_BadParam && nameptr > name);
-
- if (se == kDNSServiceErr_NoError)
- {
- p->ipp_txt = ipp_txt;
- p->ipp_len = ipp_len;
- ipp_txt = NULL;
- }
- else
- cupsdLogMessage(CUPSD_LOG_WARN,
- "DNS-SD IPP registration of \"%s\" failed: %d",
- p->name, se);
- }
- else if (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len))
- {
- /*
- * Update the existing registration...
- */
-
- /* A TTL of 0 means use record's original value (Radar 3176248) */
- DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt, 0);
-
- if (p->ipp_txt)
- free(p->ipp_txt);
-
- p->ipp_txt = ipp_txt;
- p->ipp_len = ipp_len;
- ipp_txt = NULL;
- }
-
- if (ipp_txt)
- free(ipp_txt);
-
- if (BrowseLocalProtocols & BROWSE_LPD)
- {
- printer_len = 0; /* anti-compiler-warning-code */
- printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1);
-
- if (!p->printer_ref)
- {
- /*
- * Initial registration...
- */
-
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "Registering DNS-SD printer %s with name \"%s\", "
- "type \"_printer._tcp\", and domain \"%s\"", p->name,
- name, domain ? domain : "(null)");
-
- p->printer_ref = DNSSDRef;
- if ((se = DNSServiceRegister(&p->printer_ref,
- kDNSServiceFlagsShareConnection,
- 0, name, "_printer._tcp", domain, NULL,
- htons(515), printer_len, printer_txt,
- dnssdRegisterCallback,
- p)) == kDNSServiceErr_NoError)
- {
- p->printer_txt = printer_txt;
- p->printer_len = printer_len;
- printer_txt = NULL;
- }
- else
- cupsdLogMessage(CUPSD_LOG_WARN,
- "DNS-SD LPD registration of \"%s\" failed: %d",
- p->name, se);
- }
- else if (printer_len != p->printer_len ||
- memcmp(printer_txt, p->printer_txt, printer_len))
- {
- /*
- * Update the existing registration...
- */
-
- /* A TTL of 0 means use record's original value (Radar 3176248) */
- DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len,
- printer_txt, 0);
-
- if (p->printer_txt)
- free(p->printer_txt);
-
- p->printer_txt = printer_txt;
- p->printer_len = printer_len;
- printer_txt = NULL;
- }
-
- if (printer_txt)
- free(printer_txt);
- }
-}
-
-
-/*
- * 'dnssdUpdate()' - Handle DNS-SD queries.
- */
-
-static void
-dnssdUpdate(void)
-{
- DNSServiceErrorType sdErr; /* Service discovery error */
-
-
- if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "DNS Service Discovery registration error %d!",
- sdErr);
-}
-#endif /* HAVE_DNSSD */
-
-
-#ifdef __APPLE__
-/*
- * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
- */
-
-static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
-get_hostconfig(const char *name) /* I - Name of service */
-{
- cups_file_t *fp; /* Hostconfig file */
- char line[1024], /* Line from file */
- *ptr; /* Pointer to value */
- int state = 1; /* State of service */
-
-
- /*
- * Try opening the /etc/hostconfig file; if we can't open it, assume that
- * the service is enabled/auto.
- */
-
- if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
- {
- /*
- * Read lines from the file until we find the service...
- */
-
- while (cupsFileGets(fp, line, sizeof(line)))
- {
- if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
- continue;
-
- *ptr++ = '\0';
-
- if (!strcasecmp(line, name))
- {
- /*
- * Found the service, see if it is set to "-NO-"...
- */
-
- if (!strncasecmp(ptr, "-NO-", 4))
- state = 0;
- break;
- }
- }
-
- cupsFileClose(fp);
- }
-
- return (state);
-}
-#endif /* __APPLE__ */
-
-
-/*
- * 'is_local_queue()' - Determine whether the URI points at a local queue.
- */
-
-static int /* O - 1 = local, 0 = remote, -1 = bad URI */
-is_local_queue(const char *uri, /* I - Printer URI */
- char *host, /* O - Host string */
- int hostlen, /* I - Length of host buffer */
- char *resource, /* O - Resource string */
- int resourcelen) /* I - Length of resource buffer */
-{
- char scheme[32], /* Scheme portion of URI */
- username[HTTP_MAX_URI]; /* Username portion of URI */
- int port; /* Port portion of URI */
- cupsd_netif_t *iface; /* Network interface */
-
-
- /*
- * Pull the URI apart to see if this is a local or remote printer...
- */
-
- 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));
-
- /*
- * Check for local server addresses...
- */
-
- 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);
-
- /*
- * If we get here, the printer is remote...
- */
-
- return (0);
-}
-
-
-/*
- * 'process_browse_data()' - Process new browse data.
- */
-
-static void
-process_browse_data(
- const char *uri, /* I - URI of printer/class */
- const char *host, /* I - Hostname */
- const char *resource, /* I - Resource path */
- cups_ptype_t type, /* I - Printer type */
- ipp_pstate_t state, /* I - Printer state */
- const char *location, /* I - Printer location */
- const char *info, /* I - Printer information */
- const char *make_model, /* I - Printer make and model */
- int num_attrs, /* I - Number of attributes */
- cups_option_t *attrs) /* I - Attributes */
-{
- int i; /* Looping var */
- int update; /* Update printer attributes? */
- char finaluri[HTTP_MAX_URI], /* Final URI for printer */
- name[IPP_MAX_NAME], /* Name of printer */
- newname[IPP_MAX_NAME], /* New name of printer */
- *hptr, /* Pointer into hostname */
- *sptr; /* Pointer into ServerName */
- const char *shortname; /* Short queue name (queue) */
- char local_make_model[IPP_MAX_NAME];
- /* Local make and model */
- cupsd_printer_t *p; /* Printer information */
- const char *ipp_options, /* ipp-options value */
- *lease_duration; /* lease-duration value */
- int is_class; /* Is this queue a 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);
-
- /*
- * 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)))
- {
- 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;
- }
-
- /*
- * OK, this isn't a local printer; add any remote options...
- */
-
- 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...
- */
-
- snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
- }
-
- uri = finaluri;
- }
- else if (ipp_options)
- {
- /*
- * Just use the server-supplied options...
- */
-
- snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
- uri = finaluri;
- }
-
- /*
- * See if we already have it listed in the Printers list, and add it if not...
- */
-
- type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
- type &= ~CUPS_PRINTER_IMPLICIT;
- update = 0;
- hptr = strchr(host, '.');
- sptr = strchr(ServerName, '.');
- is_class = type & CUPS_PRINTER_CLASS;
-
- if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
- {
- /*
- * Strip the common domain name components...
- */
-
- while (hptr != NULL)
- {
- if (!strcasecmp(hptr, sptr))
- {
- *hptr = '\0';
- break;
- }
- else
- hptr = strchr(hptr + 1, '.');
- }
- }
-
- if (is_class)
- {
- /*
- * Remote destination is a class...
- */
-
- if (!strncmp(resource, "/classes/", 9))
- snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
- else
- return;
-
- shortname = resource + 9;
- }
- else
- {
- /*
- * Remote destination is a printer...
- */
-
- if (!strncmp(resource, "/printers/", 10))
- snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
- else
- return;
-
- shortname = resource + 10;
- }
-
- if (hptr && !*hptr)
- *hptr = '.'; /* Resource FQDN */
-
- if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
- {
- /*
- * Long name doesn't exist, try short name...
- */
-
- cupsdLogMessage(CUPSD_LOG_DEBUG, "process_browse_data: %s not found...",
- name);
-
- if ((p = cupsdFindDest(shortname)) == NULL)
- {
- /*
- * Short name doesn't exist, use it for this shared queue.
- */
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_browse_data: %s not found...",
- shortname);
- strlcpy(name, shortname, sizeof(name));
- }
- else
- {
- /*
- * Short name exists...
- */
-
- 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; /* Don't replace implicit classes */
- else if (p->hostname && strcasecmp(p->hostname, host))
- {
- /*
- * Short name exists but is for a different host. If this is a remote
- * queue, rename it and use the long name...
- */
-
- 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);
- }
-
- /*
- * Force creation with long 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)
- {
- /*
- * Queue doesn't exist; add it...
- */
-
- 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);
-
- /*
- * Force the URI to point to the real server...
- */
-
- p->type = type & ~CUPS_PRINTER_REJECTING;
- p->accepting = 1;
-
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
- }
-
- if (!p)
- return;
-
- 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;
-
- cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
- }
-
- /*
- * Update the state...
- */
-
- p->state = state;
- p->browse_time = time(NULL);
-
- if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
- attrs)) != NULL)
- {
- /*
- * Grab the lease-duration for the browse data; anything less then 1
- * second or more than 1 week gets the default BrowseTimeout...
- */
-
- i = atoi(lease_duration);
- if (i < 1 || i > 604800)
- i = BrowseTimeout;
-
- p->browse_expire = p->browse_time + i;
- }
- else
- p->browse_expire = p->browse_time + BrowseTimeout;
-
- if (type & CUPS_PRINTER_REJECTING)
- {
- type &= ~CUPS_PRINTER_REJECTING;
-
- if (p->accepting)
- {
- update = 1;
- p->accepting = 0;
- }
- }
- else if (!p->accepting)
- {
- update = 1;
- p->accepting = 1;
- }
-
- if (p->type != type)
- {
- p->type = type;
- update = 1;
- }
-
- if (location && (!p->location || strcmp(p->location, location)))
- {
- cupsdSetString(&p->location, location);
- update = 1;
- }
-
- if (info && (!p->info || strcmp(p->info, info)))
- {
- cupsdSetString(&p->info, info);
- update = 1;
-
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
- }
-
- if (!make_model || !make_model[0])
- {
- if (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))
- {
- /*
- * See if we need to update the attributes...
- */
-
- if (p->num_options != num_attrs)
- update = 1;
- else
- {
- for (i = 0; i < num_attrs; i ++)
- if (strcmp(attrs[i].name, p->options[i].name) ||
- (!attrs[i].value != !p->options[i].value) ||
- (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
- {
- update = 1;
- break;
- }
- }
- }
-
- /*
- * Free the old options...
- */
-
- cupsFreeOptions(p->num_options, p->options);
- }
-
- p->num_options = num_attrs;
- p->options = attrs;
-
- if (type & CUPS_PRINTER_DELETE)
- {
- cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
- "%s \'%s\' deleted by directory services.",
- is_class ? "Class" : "Printer", p->name);
-
- cupsdExpireSubscriptions(p, NULL);
-
- cupsdDeletePrinter(p, 1);
- cupsdUpdateImplicitClasses();
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
- }
- else if (update)
- {
- cupsdSetPrinterAttrs(p);
- cupsdUpdateImplicitClasses();
- }
-
- /*
- * See if we have a default printer... If not, make the first network
- * default printer the default.
- */
-
- if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
- {
- /*
- * Find the first network default printer and use it...
- */
-
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
- p;
- p = (cupsd_printer_t *)cupsArrayNext(Printers))
- if (p->type & CUPS_PRINTER_DEFAULT)
- {
- DefaultPrinter = p;
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
- break;
- }
- }
-
- /*
- * Do auto-classing if needed...
- */
-
- process_implicit_classes();
-}
-
-
-/*
- * 'process_implicit_classes()' - Create/update implicit classes as needed.
- */
-
-static void
-process_implicit_classes(void)
-{
- int i; /* Looping var */
- int update; /* Update printer attributes? */
- char name[IPP_MAX_NAME], /* Name of printer */
- *hptr; /* Pointer into hostname */
- cupsd_printer_t *p, /* Printer information */
- *pclass, /* Printer class */
- *first; /* First printer in class */
- int offset, /* Offset of name */
- len; /* Length of name */
-
-
- if (!ImplicitClasses || !Printers)
- return;
-
- /*
- * Loop through all available printers and create classes as needed...
- */
-
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
- update = 0, pclass = NULL, first = NULL;
- p != NULL;
- p = (cupsd_printer_t *)cupsArrayNext(Printers))
- {
- /*
- * Skip implicit classes...
- */
-
- if (p->type & CUPS_PRINTER_IMPLICIT)
- {
- len = 0;
- continue;
- }
-
- /*
- * If len == 0, get the length of this printer name up to the "@"
- * sign (if any).
- */
-
- cupsArraySave(Printers);
-
- if (len > 0 &&
- !strncasecmp(p->name, name + offset, len) &&
- (p->name[len] == '\0' || p->name[len] == '@'))
- {
- /*
- * We have more than one printer with the same name; see if
- * we have a class, and if this printer is a member...
- */
-
- if (pclass && strcasecmp(pclass->name, name))
- {
- if (update)
- cupsdSetPrinterAttrs(pclass);