CHANGES IN CUPS V1.3.9
+ - Refined the cupstestppd utility.
- ppdEmit*() did not support custom JCL options (STR #2889)
- The cupstestppd utility incorrectly reported missing
"en" base translations (STR #2887)
-CHANGES.txt - 2008-07-23
+CHANGES.txt - 2008-07-28
------------------------
CHANGES IN CUPS V1.4b1
+ - Added support for a device-location attribute which provides
+ the physical location of a printer device.
+ - Added a cupsBackendReport() API which handles quoting of the
+ device data by a backend.
+ - Added support for custom options in the web interface
+ (STR #1729)
+ - Added support for Mozilla LDAP, reconnection to LDAP servers,
+ and improved LDAP performance (STR #1962)
+ - Added Solaris SMF support (STR #1477)
+ - Added optional support for using TCP wrappers to limit access
+ to CUPS (STR #263)
- Added ppdPageSizeLimits API.
- Added support for new cupsMediaQualifier2, cupsMediaQualifier3,
cupsMinSize, and cupsMaxSize attributes.
LIBGSSAPI = @LIBGSSAPI@
LIBTIFF = @LIBTIFF@
LIBUSB = @LIBUSB@
+LIBWRAP = @LIBWRAP@
LIBZ = @LIBZ@
#
SBINDIR = $(BUILDROOT)@sbindir@
SERVERBIN = $(BUILDROOT)@CUPS_SERVERBIN@
SERVERROOT = $(BUILDROOT)@CUPS_SERVERROOT@
+SMFMANIFESTDIR = @SMFMANIFESTDIR@
STATEDIR = $(BUILDROOT)@CUPS_STATEDIR@
XINETD = @XINETD@
$(INSTALL_SCRIPT) init/cups.sh $(BUILDROOT)$(INITDDIR)/cups; \
fi \
fi
+ if test "x$(SMFMANIFESTDIR)" != x; then \
+ echo Installing SMF manifest in $(SMFMANIFESTDIR)...;\
+ $(INSTALL_DIR) $(BUILDROOT)/$(SMFMANIFESTDIR); \
+ $(INSTALL_SCRIPT) init/cups.xml $(BUILDROOT)$(SMFMANIFESTDIR)/cups.xml; \
+ fi
if test "x$(DBUSDIR)" != x; then \
echo Installing cups.conf in $(DBUSDIR)...;\
$(INSTALL_DIR) -m 755 $(BUILDROOT)$(DBUSDIR)/system.d; \
/* Host MIB */
#define CUPS_OID_mib2 1,3,6,1,2,1
+#define CUPS_OID_system CUPS_OID_mib2,1
+#define CUPS_OID_sysLocation CUPS_OID_system,6
+
#define CUPS_OID_host CUPS_OID_mib2,25
#define CUPS_OID_hrSystem CUPS_OID_host,1
schemes[best->type], NULL, best->fullName, 0,
best->cups_shared ? "/cups" : "/");
- printf("network %s \"%s\" \"%s\"\n", device_uri,
- best->make_and_model ? best->make_and_model : "Unknown",
- best->name);
- fflush(stdout);
-
+ cupsBackendReport("network", device_uri, best->make_and_model,
+ best->name, NULL, NULL);
best->sent = 1;
best = device;
}
schemes[best->type], NULL, best->fullName, 0,
best->cups_shared ? "/cups" : "/");
- printf("network %s \"%s\" \"%s\"\n", device_uri,
- best->make_and_model ? best->make_and_model : "Unknown",
- best->name);
- fflush(stdout);
-
+ cupsBackendReport("network", device_uri, best->make_and_model,
+ best->name, NULL, NULL);
best->sent = 1;
}
}
basedevice[255], /* Base device filename for ports */
device_id[1024], /* Device ID string */
make_model[1024], /* Make and model */
+ info[1024], /* Info string */
uri[1024]; /* Device URI */
if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
make_model, sizeof(make_model),
NULL, uri, sizeof(uri)))
- printf("direct %s \"%s\" \"%s LPT #%d\" \"%s\"\n", uri,
- make_model, make_model, i + 1, device_id);
+ {
+ snprintf(info, sizeof(info), "%s LPT #%d", make_model, i + 1);
+ cupsBackendReport("direct", uri, make_model, info, device_id, NULL);
+ }
else
- printf("direct %s \"Unknown\" \"LPT #%d\"\n", uri, i + 1);
+ {
+ snprintf(info, sizeof(info), "LPT #%d", i + 1);
+ cupsBackendReport("direct", uri, NULL, info, NULL, NULL);
+ }
close(fd);
}
* Types...
*/
+enum /**** Request IDs for each field ****/
+{
+ DEVICE_TYPE = 1,
+ DEVICE_DESCRIPTION,
+ DEVICE_LOCATION,
+ DEVICE_ID,
+ DEVICE_URI,
+ DEVICE_PRODUCT
+};
+
typedef struct device_uri_s /**** DeviceURI values ****/
{
regex_t re; /* Regular expression to match */
*uri, /* device-uri */
*id, /* device-id */
*info, /* device-info */
+ *location, /* device-location */
*make_and_model; /* device-make-and-model */
+ int sent; /* Has this device been listed? */
} snmp_cache_t;
static cups_array_t *Communities = NULL;
static cups_array_t *Devices = NULL;
static int DebugLevel = 0;
-static const int DeviceDescOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 };
-static unsigned DeviceDescRequest;
+static const int DescriptionOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 };
+static const int LocationOID[] = { CUPS_OID_sysLocation, 0, -1 };
static const int DeviceTypeOID[] = { CUPS_OID_hrDeviceType, 1, -1 };
-static unsigned DeviceTypeRequest;
static const int DeviceIdOID[] = { CUPS_OID_ppmPrinterIEEE1284DeviceId, 1, -1 };
-static unsigned DeviceIdRequest;
-static const int DeviceUriOID[] = { CUPS_OID_ppmPortServiceNameOrURI, 1, 1, -1 };
-static unsigned DeviceUriRequest;
+static const int UriOID[] = { CUPS_OID_ppmPortServiceNameOrURI, 1, 1, -1 };
+static const int LexmarkProductOID[] = { 1,3,6,1,4,1,641,2,1,2,1,2,1,-1 };
+static const int LexmarkProductOID2[] = { 1,3,6,1,4,1,674,10898,100,2,1,2,1,2,1,-1 };
+static const int LexmarkDeviceIdOID[] = { 1,3,6,1,4,1,641,2,1,2,1,3,1,-1 };
+static const int XeroxProductOID[] = { 1,3,6,1,4,1,128,2,1,3,1,2,0,-1 };
static cups_array_t *DeviceURIs = NULL;
static int HostNameLookups = 0;
static int MaxRunTime = 120;
list_device(snmp_cache_t *cache) /* I - Cached device */
{
if (cache->uri)
- {
- printf("network %s \"%s\" \"%s %s\" \"%s\"\n",
- cache->uri,
- cache->make_and_model ? cache->make_and_model : "Unknown",
- cache->info ? cache->info : "Unknown",
- cache->addrname,
- cache->id ? cache->id : "");
- fflush(stdout);
- }
+ cupsBackendReport("network", cache->uri, cache->make_and_model,
+ cache->info, cache->id, cache->location);
}
* Process the message...
*/
- if (packet.request_id == DeviceTypeRequest)
+ switch (packet.request_id)
{
- /*
- * Got the device type response...
- */
-
- if (device)
- {
- debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
- addrname);
- return;
- }
-
- /*
- * Add the device and request the device description...
- */
-
- add_cache(&(packet.address), addrname, NULL, NULL, NULL);
+ case DEVICE_TYPE :
+ /*
+ * Got the device type response...
+ */
+
+ if (device)
+ {
+ debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
+ addrname);
+ return;
+ }
+
+ /*
+ * Add the device and request the device data...
+ */
+
+ add_cache(&(packet.address), addrname, NULL, NULL, NULL);
+
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_DESCRIPTION, DescriptionOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_ID, DeviceIdOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_URI, UriOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_LOCATION, LocationOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, LexmarkProductOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, LexmarkProductOID2);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_URI, LexmarkDeviceIdOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, XeroxProductOID);
+ break;
+
+ case DEVICE_DESCRIPTION :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING)
+ {
+ /*
+ * Update an existing cache entry...
+ */
+
+ char make_model[256]; /* Make and model */
+
+
+ if (strchr(packet.object_value.string, ':') &&
+ strchr(packet.object_value.string, ';'))
+ {
+ /*
+ * Description is the IEEE-1284 device ID...
+ */
- _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community,
- CUPS_ASN1_GET_REQUEST, DeviceDescRequest, DeviceDescOID);
- _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community,
- CUPS_ASN1_GET_REQUEST, DeviceIdRequest, DeviceIdOID);
- _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community,
- CUPS_ASN1_GET_REQUEST, DeviceUriRequest, DeviceUriOID);
- }
- else if (packet.request_id == DeviceDescRequest &&
- packet.object_type == CUPS_ASN1_OCTET_STRING)
- {
- /*
- * Update an existing cache entry...
- */
+ if (!device->id)
+ device->id = strdup(packet.object_value.string);
- char make_model[256]; /* Make and model */
+ backendGetMakeModel(packet.object_value.string, make_model,
+ sizeof(make_model));
+ if (device->info)
+ free(device->info);
- if (!device)
- {
- debug_printf("DEBUG: Discarding device description for \"%s\"...\n",
- addrname);
- return;
- }
-
- if (strchr(packet.object_value.string, ':') &&
- strchr(packet.object_value.string, ';'))
- {
- /*
- * Description is the IEEE-1284 device ID...
- */
-
- if (!device->id)
- device->id = strdup(packet.object_value.string);
-
- backendGetMakeModel(packet.object_value.string, make_model,
- sizeof(make_model));
- device->info = strdup(make_model);
- }
- else
- {
- /*
- * Description is plain text...
- */
+ device->info = strdup(make_model);
+ }
+ else
+ {
+ /*
+ * Description is plain text...
+ */
- fix_make_model(make_model, packet.object_value.string,
- sizeof(make_model));
+ fix_make_model(make_model, packet.object_value.string,
+ sizeof(make_model));
- device->info = strdup(packet.object_value.string);
- }
+ if (device->info)
+ free(device->info);
- if (!device->make_and_model)
- device->make_and_model = strdup(make_model);
+ device->info = strdup(packet.object_value.string);
+ }
- /*
- * List the device now if we have all the info...
- */
+ if (!device->make_and_model)
+ device->make_and_model = strdup(make_model);
+ }
+ break;
- if (device->id && device->info && device->make_and_model && device->uri)
- list_device(device);
- }
- else if (packet.request_id == DeviceIdRequest &&
- packet.object_type == CUPS_ASN1_OCTET_STRING)
- {
- /*
- * Update an existing cache entry...
- */
+ case DEVICE_ID :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING)
+ {
+ /*
+ * Update an existing cache entry...
+ */
- char make_model[256]; /* Make and model */
+ char make_model[256]; /* Make and model */
- if (!device)
- {
- debug_printf("DEBUG: Discarding device ID for \"%s\"...\n",
- addrname);
- return;
- }
+ if (device->id)
+ free(device->id);
- if (device->id)
- free(device->id);
+ device->id = strdup(packet.object_value.string);
- device->id = strdup(packet.object_value.string);
+ /*
+ * Convert the ID to a make and model string...
+ */
- /*
- * Convert the ID to a make and model string...
- */
+ backendGetMakeModel(packet.object_value.string, make_model,
+ sizeof(make_model));
+ if (device->make_and_model)
+ free(device->make_and_model);
- backendGetMakeModel(packet.object_value.string, make_model,
- sizeof(make_model));
- if (device->make_and_model)
- free(device->make_and_model);
+ device->make_and_model = strdup(make_model);
+ }
+ break;
- device->make_and_model = strdup(make_model);
+ case DEVICE_LOCATION :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->location)
+ device->location = strdup(packet.object_value.string);
+ break;
- /*
- * List the device now if we have all the info...
- */
+ case DEVICE_PRODUCT :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->id)
+ {
+ /*
+ * Update an existing cache entry...
+ */
- if (device->id && device->info && device->make_and_model && device->uri)
- list_device(device);
- }
- else if (packet.request_id == DeviceUriRequest &&
- packet.object_type == CUPS_ASN1_OCTET_STRING)
- {
- /*
- * Update an existing cache entry...
- */
+ if (!device->info)
+ device->info = strdup(packet.object_value.string);
- if (!device)
- {
- debug_printf("DEBUG: Discarding device URI for \"%s\"...\n",
- addrname);
- return;
- }
+ if (device->make_and_model)
+ free(device->make_and_model);
- if (!strncmp(packet.object_value.string, "lpr:", 4))
- {
- /*
- * We want "lpd://..." for the URI...
- */
+ device->make_and_model = strdup(packet.object_value.string);
+ }
+ break;
- packet.object_value.string[2] = 'd';
- }
+ case DEVICE_URI :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->uri)
+ {
+ /*
+ * Update an existing cache entry...
+ */
- device->uri = strdup(packet.object_value.string);
+ if (!strncmp(packet.object_value.string, "lpr:", 4))
+ {
+ /*
+ * We want "lpd://..." for the URI...
+ */
- /*
- * List the device now if we have all the info...
- */
+ packet.object_value.string[2] = 'd';
+ }
- if (device->id && device->info && device->make_and_model && device->uri)
- list_device(device);
+ device->uri = strdup(packet.object_value.string);
+ }
+ break;
}
}
snmp_cache_t *device; /* Current device */
- /*
- * Setup the request IDs...
- */
-
gettimeofday(&StartTime, NULL);
- DeviceTypeRequest = StartTime.tv_sec;
- DeviceDescRequest = StartTime.tv_sec + 1;
-
/*
* First send all of the broadcast queries...
*/
for (addr = addrs; addr; addr = addr->next)
_cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community,
- CUPS_ASN1_GET_REQUEST, DeviceTypeRequest, DeviceTypeOID);
+ CUPS_ASN1_GET_REQUEST, DEVICE_TYPE, DeviceTypeOID);
}
httpAddrFreeList(addrs);
if (FD_ISSET(fd, &input))
read_snmp_response(fd);
else
- break;
- }
+ {
+ /*
+ * List devices with complete information...
+ */
- /*
- * Finally, probe all of the printers we discovered to see how they are
- * connected...
- */
+ int sent_something = 0;
- for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
- device;
- device = (snmp_cache_t *)cupsArrayNext(Devices))
- if (MaxRunTime > 0 && run_time() >= MaxRunTime)
- break;
- else if (!device->uri)
- probe_device(device);
+ for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
+ device;
+ device = (snmp_cache_t *)cupsArrayNext(Devices))
+ if (!device->sent && device->info && device->make_and_model)
+ {
+ if (device->uri)
+ list_device(device);
+ else
+ probe_device(device);
+
+ device->sent = sent_something = 1;
+ }
+
+ if (!sent_something)
+ break;
+ }
+ }
debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
}
* cfstr_create_trim() - Create CFString and trim whitespace characters.
* parse_options() - Parse uri options.
* setup_cfLanguage() - Create AppleLanguages array from LANG environment var.
-* run_ppc_backend() - Re-exec i386 backend as ppc.
+* run_legacy_backend() - Re-exec backend as ppc or i386.
* sigterm_handler() - SIGTERM handler.
* next_line() - Find the next line in a buffer.
* parse_pserror() - Scan the backchannel data for postscript errors.
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/IOCFPlugIn.h>
+#include <spawn.h>
#include <pthread.h>
+extern char **environ;
+
/*
* WAIT_EOF_DELAY is number of seconds we'll wait for responses from
static void soft_reset();
static void status_timer_cb(CFRunLoopTimerRef timer, void *info);
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
static pid_t child_pid; /* Child PID */
-static void run_ppc_backend(int argc, char *argv[], int fd); /* Starts child backend process running as a ppc executable */
+static void run_legacy_backend(int argc, char *argv[], int fd); /* Starts child backend process running as a ppc executable */
static void sigterm_handler(int sig); /* SIGTERM handler */
-#endif /* __i386__ */
+#endif /* __i386__ || __x86_64__ */
#ifdef PARSE_PS_ERRORS
static const char *next_line (const char *buffer);
status = registry_open(&driverBundlePath);
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
/*
- * If we were unable to load the class drivers for this printer it's probably because they're ppc-only.
- * In this case try to fork & exec this backend as a ppc executable so we can use them...
+ * If we were unable to load the class drivers for this printer it's
+ * probably because they're ppc or i386. In this case try to run this
+ * backend as i386 or ppc executables so we can use them...
*/
if (status == -2)
{
- run_ppc_backend(argc, argv, print_fd);
+ run_legacy_backend(argc, argv, print_fd);
/* Never returns here */
}
-#endif /* __i386__ */
+#endif /* __i386__ || __x86_64__ */
if (status == -2)
{
if (print_fd != STDIN_FILENO)
{
- fputs("PAGE: 1 1", stderr);
+ fputs("PAGE: 1 1\n", stderr);
lseek(print_fd, 0, SEEK_SET);
}
httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
strncat(uristr, optionsstr, sizeof(uristr));
- printf("direct %s \"%s\" \"%s USB\" \"%s\"\n", uristr, make_modelstr,
- make_modelstr, idstr);
+ cupsBackendReport("direct", uristr, make_modelstr, make_modelstr, idstr,
+ NULL);
release_deviceinfo(&make, &model, &serial);
CFRelease(deviceIDString);
void *info)
{
fputs("STATE: +offline-error\n", stderr);
- _cupsLangPuts(stderr, _("INFO: Printer is currently offline.\n"));
+ _cupsLangPuts(stderr, _("INFO: Printer is offline.\n"));
if (getenv("CLASS") != NULL)
{
}
#pragma mark -
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
/*!
- * @function run_ppc_backend
+ * @function run_legacy_backend
*
- * @abstract Starts child backend process running as a ppc executable.
+ * @abstract Starts child backend process running as a ppc or i386 executable.
*
* @result Never returns; always calls exit().
*
* @discussion
*/
-static void run_ppc_backend(int argc,
- char *argv[],
- int fd)
+static void run_legacy_backend(int argc,
+ char *argv[],
+ int fd)
{
int i;
int exitstatus = 0;
int childstatus;
pid_t waitpid_status;
char *my_argv[32];
- char *usb_ppc_status;
+ char *usb_legacy_status;
- /*
- * If we're running as i386 and couldn't load the class driver (because they'it's
- * ppc-only) then try to re-exec ourselves in ppc mode to try again. If we don't have
- * a ppc architecture we may be running i386 again so guard against this by setting
- * and testing an environment variable...
- */
- usb_ppc_status = getenv("USB_PPC_STATUS");
+ /*
+ * If we're running as x86_64 or i386 and couldn't load the class driver
+ * (because it's ppc or i386), then try to re-exec ourselves in ppc or i386
+ * mode to try again. If we don't have a ppc or i386 architecture we may be
+ * running with the same architecture again so guard against this by setting
+ * and testing an environment variable...
+ */
- if (usb_ppc_status == NULL)
+# ifdef __x86_64__
+ usb_legacy_status = getenv("USB_I386_STATUS");
+# else
+ usb_legacy_status = getenv("USB_PPC_STATUS");
+# endif /* __x86_64__ */
+
+ if (!usb_legacy_status)
{
/*
* Setup a SIGTERM handler then block it before forking...
sigaddset(&newmask, SIGTERM);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
- if ((child_pid = fork()) == 0)
- {
- /*
- * Child comes here...
- */
-
- setenv("USB_PPC_STATUS", "1", false);
-
- /*
- * Unblock signals before doing the exec...
- */
-
- memset(&action, 0, sizeof(action));
- sigemptyset(&action.sa_mask);
- action.sa_handler = SIG_DFL;
- sigaction(SIGTERM, &action, NULL);
+ /*
+ * Set the environment variable...
+ */
- sigprocmask(SIG_SETMASK, &oldmask, NULL);
+# ifdef __x86_64__
+ setenv("USB_I386_STATUS", "1", false);
+# else
+ setenv("USB_PPC_STATUS", "1", false);
+# endif /* __x86_64__ */
- /*
- * Tell the kernel the next exec call should favor the ppc architecture...
- */
+ /*
+ * Tell the kernel to use the specified CPU architecture...
+ */
- int mib[] = { CTL_KERN, KERN_AFFINITY, 1, 1 };
- int namelen = 4;
- sysctl(mib, namelen, NULL, NULL, NULL, 0);
+# ifdef __x86_64__
+ cpu_type_t cpu = CPU_TYPE_I386;
+# else
+ cpu_type_t cpu = CPU_TYPE_POWERPC;
+# endif /* __x86_64__ */
+ size_t ocount = 0;
+ posix_spawnattr_t attrs;
- /*
- * Set up the arguments and call exec...
- */
+ if (!posix_spawnattr_init(&attrs))
+ {
+ posix_spawnattr_setsigdefault(attrs, &oldmask);
+ posix_spawnattr_setbinpref_np(attrs, 1, &cpu, &ocount);
+ }
- for (i = 0; i < argc && i < (sizeof(my_argv)/sizeof(my_argv[0])) - 1; i++)
- my_argv[i] = argv[i];
+ /*
+ * Set up the arguments and call posix_spawn...
+ */
- my_argv[i] = NULL;
+ for (i = 0; i < argc && i < (sizeof(my_argv) / sizeof(my_argv[0])) - 1; i ++)
+ my_argv[i] = argv[i];
- execv("/usr/libexec/cups/backend/usb", my_argv);
+ my_argv[i] = NULL;
- _cupsLangPrintf(stderr, _("Unable to use legacy USB class driver!\n"));
- perror("DEBUG: Unable to exec /usr/libexec/cups/backend/usb");
- exit(errno);
- }
- else if (child_pid < 0)
+ if (posix_spawn(&child_pid, "/usr/libexec/cups/backend/usb", NULL, &attrs,
+ my_argv, environ))
{
- /*
- * Error - couldn't fork a new process!
- */
-
_cupsLangPrintf(stderr, _("Unable to use legacy USB class driver!\n"));
- perror("DEBUG: Unable to fork");
- exit(errno);
+ perror("DEBUG: Unable to exec /usr/libexec/cups/backend/usb");
+ exit(CUPS_BACKEND_STOP);
}
/*
if (WIFSIGNALED(childstatus))
{
- exitstatus = WTERMSIG(childstatus);
+ exitstatus = CUPS_BACKEND_STOP;
fprintf(stderr, "DEBUG: usb(legacy) backend %d crashed on signal %d!\n",
- child_pid, exitstatus);
+ child_pid, WTERMSIG(childstatus));
}
else
{
else
{
fputs("DEBUG: usb(legacy) backend running native again\n", stderr);
- exitstatus = ENOENT;
+ exitstatus = CUPS_BACKEND_STOP;
}
exit(exitstatus);
exit(1);
}
-#endif /* __i386__ */
+#endif /* __i386__ || __x86_64__ */
#ifdef PARSE_PS_ERRORS
* Report the printer...
*/
- printf("direct %s \"%s\" \"%s USB\" \"%s\"\n", device_uri, make_model,
- make_model, device_id);
- fflush(stdout);
+ cupsBackendReport("direct", device_uri, make_model, make_model, device_id,
+ NULL);
/*
* Keep going...
device_uri[1024], /* Device URI string */
make_model[1024]; /* Make and model */
+
/*
* Try to open each USB device...
*/
if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
make_model, sizeof(make_model),
"usb", device_uri, sizeof(device_uri)))
- printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
- make_model, make_model, i + 1, device_id);
+ cupsBackendReport("direct", device_uri, make_model, make_model,
+ device_id, NULL);
close(fd);
}
if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
make_model, sizeof(make_model),
"usb", device_uri, sizeof(device_uri)))
- printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
- make_model, make_model, i + 1, device_id);
+ cupsBackendReport("direct", device_uri, make_model, make_model,
+ device_id, NULL);
close(fd);
}
* do_am_printer() - Add or modify a printer.
* do_cancel_subscription() - Cancel a subscription.
* do_config_server() - Configure server settings.
- * do_delete_class() - Delete a class...
- * do_delete_printer() - Delete a printer...
- * do_export() - Export printers to Samba...
- * do_list_printers() - List available printers...
- * do_menu() - Show the main menu...
+ * do_delete_class() - Delete a class.
+ * do_delete_printer() - Delete a printer.
+ * do_export() - Export printers to Samba.
+ * do_list_printers() - List available printers.
+ * do_menu() - Show the main menu.
* do_printer_op() - Do a printer operation.
* do_set_allowed_users() - Set the allowed/denied users for a queue.
* do_set_options() - Configure the default options for a queue.
- * do_set_sharing() - Set printer-is-shared value...
+ * do_set_sharing() - Set printer-is-shared value.
+ * get_option_value() - Return the value of an option.
+ * get_points() - Get a value in points.
* match_string() - Return the number of matching characters.
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
+#include <limits.h>
/*
ipp_op_t op, const char *title);
static void do_set_allowed_users(http_t *http);
static void do_set_sharing(http_t *http);
+static char *get_option_value(ppd_file_t *ppd, const char *name,
+ char *buffer, size_t bufsize);
+static double get_points(double number, const char *uval);
static int match_string(const char *a, const char *b);
else
{
/*
- * Bad operation code... Display an error...
+ * Bad operation code - display an error...
*/
cgiStartHTML(cgiText(_("Administration")));
else
{
/*
- * Form data but no operation code... Display an error...
+ * Form data but no operation code - display an error...
*/
cgiStartHTML(cgiText(_("Administration")));
/*
- * 'do_delete_class()' - Delete a class...
+ * 'do_delete_class()' - Delete a class.
*/
static void
/*
- * 'do_delete_printer()' - Delete a printer...
+ * 'do_delete_printer()' - Delete a printer.
*/
static void
/*
- * 'do_export()' - Export printers to Samba...
+ * 'do_export()' - Export printers to Samba.
*/
static void
/*
- * 'do_list_printers()' - List available printers...
+ * 'do_list_printers()' - List available printers.
*/
static void
/*
- * 'do_menu()' - Show the main menu...
+ * 'do_menu()' - Show the main menu.
*/
static void
char tempfile[1024]; /* Temporary filename */
cups_file_t *in, /* Input file */
*out; /* Output file */
- char line[1024]; /* Line from PPD file */
- char keyword[1024], /* Keyword from Default line */
+ char line[1024], /* Line from PPD file */
+ value[1024], /* Option value */
+ keyword[1024], /* Keyword from Default line */
*keyptr; /* Pointer into keyword... */
ppd_file_t *ppd; /* PPD file */
ppd_group_t *group; /* Option group */
ppd_option_t *option; /* Option */
+ ppd_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Custom parameter */
ppd_attr_t *protocol; /* cupsProtocol attribute */
const char *title; /* Page title */
{
ppdMarkDefaults(ppd);
- DEBUG_printf(("<P>ppd->num_groups = %d\n"
- "<UL>\n", ppd->num_groups));
-
- for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
- {
- DEBUG_printf(("<LI>%s<UL>\n", group->text));
-
- for (j = group->num_options, option = group->options;
- j > 0;
- j --, option ++)
- if ((var = cgiGetVariable(option->keyword)) != NULL)
- {
- DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option->keyword, var));
- have_options = 1;
- ppdMarkOption(ppd, option->keyword, var);
- }
-#ifdef DEBUG
- else
- printf("<LI>%s not defined!</LI>\n", option->keyword);
-#endif /* DEBUG */
-
- DEBUG_puts("</UL></LI>");
- }
-
- DEBUG_printf(("</UL>\n"
- "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd)));
+ for (option = ppdFirstOption(ppd);
+ option;
+ option = ppdNextOption(ppd))
+ if ((var = cgiGetVariable(option->keyword)) != NULL)
+ {
+ have_options = 1;
+ ppdMarkOption(ppd, option->keyword, var);
+ }
}
if (!have_options || ppdConflicts(ppd))
cgiSetVariable("KEYWORD", option->keyword);
cgiSetVariable("KEYTEXT", option->text);
-
+
if (option->conflicted)
cgiSetVariable("CONFLICTED", "1");
else
cgiSetSize("TEXT", 0);
for (k = 0, m = 0; k < option->num_choices; k ++)
{
- /*
- * Hide custom option values...
- */
-
- if (!strcmp(option->choices[k].choice, "Custom"))
- continue;
-
cgiSetArray("CHOICES", m, option->choices[k].choice);
cgiSetArray("TEXT", m, option->choices[k].text);
cgiSetVariable("DEFCHOICE", option->choices[k].choice);
}
+ cgiSetSize("PARAMS", 0);
+ cgiSetSize("PARAMTEXT", 0);
+ cgiSetSize("PARAMVALUE", 0);
+ cgiSetSize("INPUTTYPE", 0);
+
+ if ((coption = ppdFindCustomOption(ppd, option->keyword)))
+ {
+ const char *units = NULL; /* Units value, if any */
+
+
+ cgiSetVariable("ISCUSTOM", "1");
+
+ for (cparam = ppdFirstCustomParam(coption), m = 0;
+ cparam;
+ cparam = ppdNextCustomParam(coption), m ++)
+ {
+ if (!strcasecmp(option->keyword, "PageSize") &&
+ strcasecmp(cparam->name, "Width") &&
+ strcasecmp(cparam->name, "Height"))
+ {
+ m --;
+ continue;
+ }
+
+ cgiSetArray("PARAMS", m, cparam->name);
+ cgiSetArray("PARAMTEXT", m, cparam->text);
+ cgiSetArray("INPUTTYPE", m, "text");
+
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_POINTS :
+ if (!strncasecmp(option->defchoice, "Custom.", 7))
+ {
+ units = option->defchoice + strlen(option->defchoice) - 2;
+
+ if (strcmp(units, "mm") && strcmp(units, "cm") &&
+ strcmp(units, "in") && strcmp(units, "ft"))
+ {
+ if (units[1] == 'm')
+ units ++;
+ else
+ units = "pt";
+ }
+ }
+ else
+ units = "pt";
+
+ if (!strcmp(units, "mm"))
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points / 72.0 * 25.4);
+ else if (!strcmp(units, "cm"))
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points / 72.0 * 2.54);
+ else if (!strcmp(units, "in"))
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points / 72.0);
+ else if (!strcmp(units, "ft"))
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points / 72.0 / 12.0);
+ else if (!strcmp(units, "m"))
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points / 72.0 * 0.0254);
+ else
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_points);
+ cgiSetArray("PARAMVALUE", m, value);
+ break;
+
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_REAL :
+ snprintf(value, sizeof(value), "%g",
+ cparam->current.custom_real);
+ cgiSetArray("PARAMVALUE", m, value);
+ break;
+
+ case PPD_CUSTOM_INT:
+ snprintf(value, sizeof(value), "%d",
+ cparam->current.custom_int);
+ cgiSetArray("PARAMVALUE", m, value);
+ break;
+
+ case PPD_CUSTOM_PASSCODE:
+ case PPD_CUSTOM_PASSWORD:
+ if (cparam->current.custom_password)
+ cgiSetArray("PARAMVALUE", m,
+ cparam->current.custom_password);
+ else
+ cgiSetArray("PARAMVALUE", m, "");
+ cgiSetArray("INPUTTYPE", m, "password");
+ break;
+
+ case PPD_CUSTOM_STRING:
+ if (cparam->current.custom_string)
+ cgiSetArray("PARAMVALUE", m,
+ cparam->current.custom_string);
+ else
+ cgiSetArray("PARAMVALUE", m, "");
+ break;
+ }
+ }
+
+ if (units)
+ {
+ cgiSetArray("PARAMS", m, "Units");
+ cgiSetArray("PARAMTEXT", m, cgiText(_("Units")));
+ cgiSetArray("PARAMVALUE", m, units);
+ }
+ }
+ else
+ cgiSetVariable("ISCUSTOM", "0");
+
switch (option->ui)
{
case PPD_UI_BOOLEAN :
if (!strcmp(keyword, "PageRegion") ||
!strcmp(keyword, "PaperDimension") ||
!strcmp(keyword, "ImageableArea"))
- var = cgiGetVariable("PageSize");
+ var = get_option_value(ppd, "PageSize", value, sizeof(value));
else
- var = cgiGetVariable(keyword);
+ var = get_option_value(ppd, keyword, value, sizeof(value));
- if (var != NULL)
- cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
- else
+ if (!var)
cupsFilePrintf(out, "%s\n", line);
+ else
+ cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
}
}
+ /*
+ * TODO: We need to set the port-monitor attribute!
+ */
+
if ((var = cgiGetVariable("protocol")) != NULL)
cupsFilePrintf(out, "*cupsProtocol: %s\n", var);
/*
- * 'do_set_sharing()' - Set printer-is-shared value...
+ * 'do_set_sharing()' - Set printer-is-shared value.
*/
static void
}
+/*
+ * 'get_option_value()' - Return the value of an option.
+ *
+ * This function also handles generation of custom option values.
+ */
+
+static char * /* O - Value string or NULL on error */
+get_option_value(
+ ppd_file_t *ppd, /* I - PPD file */
+ const char *name, /* I - Option name */
+ char *buffer, /* I - String buffer */
+ size_t bufsize) /* I - Size of buffer */
+{
+ char *bufptr, /* Pointer into buffer */
+ *bufend; /* End of buffer */
+ ppd_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Current custom parameter */
+ char keyword[256]; /* Parameter name */
+ const char *val, /* Parameter value */
+ *uval; /* Units value */
+ long integer; /* Integer value */
+ double number, /* Number value */
+ number_points; /* Number in points */
+
+
+ /*
+ * See if we have a custom option choice...
+ */
+
+ if ((val = cgiGetVariable(name)) == NULL)
+ {
+ /*
+ * Option not found!
+ */
+
+ return (NULL);
+ }
+ else if (strcasecmp(val, "Custom") ||
+ (coption = ppdFindCustomOption(ppd, name)) == NULL)
+ {
+ /*
+ * Not a custom choice...
+ */
+
+ strlcpy(buffer, val, bufsize);
+ return (buffer);
+ }
+
+ /*
+ * OK, we have a custom option choice, format it...
+ */
+
+ *buffer = '\0';
+
+ if (!strcmp(coption->keyword, "PageSize"))
+ {
+ const char *lval; /* Length string value */
+ double width, /* Width value */
+ width_points, /* Width in points */
+ length, /* Length value */
+ length_points; /* Length in points */
+
+
+ val = cgiGetVariable("PageSize.Width");
+ lval = cgiGetVariable("PageSize.Height");
+ uval = cgiGetVariable("PageSize.Units");
+
+ if (!val || !lval || !uval ||
+ (width = strtod(val, NULL)) == 0.0 ||
+ (length = strtod(lval, NULL)) == 0.0 ||
+ (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
+ strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
+ return (NULL);
+
+ width_points = get_points(width, uval);
+ length_points = get_points(length, uval);
+
+ if (width_points < ppd->custom_min[0] ||
+ width_points > ppd->custom_max[0] ||
+ length_points < ppd->custom_min[1] ||
+ length_points > ppd->custom_max[1])
+ return (NULL);
+
+ snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
+ }
+ else if (cupsArrayCount(coption->params) == 1)
+ {
+ cparam = ppdFirstCustomParam(coption);
+ snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
+
+ if ((val = cgiGetVariable(keyword)) == NULL)
+ return (NULL);
+
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_REAL :
+ if ((number = strtod(val, NULL)) == 0.0 ||
+ number < cparam->minimum.custom_real ||
+ number > cparam->maximum.custom_real)
+ return (NULL);
+
+ snprintf(buffer, bufsize, "Custom.%g", number);
+ break;
+
+ case PPD_CUSTOM_INT :
+ if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
+ integer == LONG_MAX ||
+ integer < cparam->minimum.custom_int ||
+ integer > cparam->maximum.custom_int)
+ return (NULL);
+
+ snprintf(buffer, bufsize, "Custom.%ld", integer);
+ break;
+
+ case PPD_CUSTOM_POINTS :
+ snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
+
+ if ((number = strtod(val, NULL)) == 0.0 ||
+ (uval = cgiGetVariable(keyword)) == NULL ||
+ (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
+ strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
+ return (NULL);
+
+ number_points = get_points(number, uval);
+ if (number_points < cparam->minimum.custom_points ||
+ number_points > cparam->maximum.custom_points)
+ return (NULL);
+
+ snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ for (uval = val; *uval; uval ++)
+ if (!isdigit(*uval & 255))
+ return (NULL);
+
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ integer = (long)strlen(val);
+ if (integer < cparam->minimum.custom_string ||
+ integer > cparam->maximum.custom_string)
+ return (NULL);
+
+ snprintf(buffer, bufsize, "Custom.%s", val);
+ break;
+ }
+ }
+ else
+ {
+ const char *prefix = "{"; /* Prefix string */
+
+
+ bufptr = buffer;
+ bufend = buffer + bufsize;
+
+ for (cparam = ppdFirstCustomParam(coption);
+ cparam;
+ cparam = ppdNextCustomParam(coption))
+ {
+ snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
+ cparam->name);
+
+ if ((val = cgiGetVariable(keyword)) == NULL)
+ return (NULL);
+
+ snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name);
+ bufptr += strlen(bufptr);
+ prefix = " ";
+
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_REAL :
+ if ((number = strtod(val, NULL)) == 0.0 ||
+ number < cparam->minimum.custom_real ||
+ number > cparam->maximum.custom_real)
+ return (NULL);
+
+ snprintf(bufptr, bufend - bufptr, "%g", number);
+ break;
+
+ case PPD_CUSTOM_INT :
+ if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
+ integer == LONG_MAX ||
+ integer < cparam->minimum.custom_int ||
+ integer > cparam->maximum.custom_int)
+ return (NULL);
+
+ snprintf(bufptr, bufend - bufptr, "%ld", integer);
+ break;
+
+ case PPD_CUSTOM_POINTS :
+ snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
+
+ if ((number = strtod(val, NULL)) == 0.0 ||
+ (uval = cgiGetVariable(keyword)) == NULL ||
+ (strcmp(uval, "pt") && strcmp(uval, "in") &&
+ strcmp(uval, "ft") && strcmp(uval, "cm") &&
+ strcmp(uval, "mm") && strcmp(uval, "m")))
+ return (NULL);
+
+ number_points = get_points(number, uval);
+ if (number_points < cparam->minimum.custom_points ||
+ number_points > cparam->maximum.custom_points)
+ return (NULL);
+
+ snprintf(bufptr, bufend - bufptr, "%g%s", number, uval);
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ for (uval = val; *uval; uval ++)
+ if (!isdigit(*uval & 255))
+ return (NULL);
+
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ integer = (long)strlen(val);
+ if (integer < cparam->minimum.custom_string ||
+ integer > cparam->maximum.custom_string)
+ return (NULL);
+
+ if ((bufptr + 2) > bufend)
+ return (NULL);
+
+ bufend --;
+ *bufptr++ = '\"';
+
+ while (*val && bufptr < bufend)
+ {
+ if (*val == '\\' || *val == '\"')
+ {
+ if ((bufptr + 1) >= bufend)
+ return (NULL);
+
+ *bufptr++ = '\\';
+ }
+
+ *bufptr++ = *val++;
+ }
+
+ if (bufptr >= bufend)
+ return (NULL);
+
+ *bufptr++ = '\"';
+ *bufptr = '\0';
+ bufend ++;
+ break;
+ }
+
+ bufptr += strlen(bufptr);
+ }
+
+ if (bufptr == buffer || (bufend - bufptr) < 2)
+ return (NULL);
+
+ strcpy(bufptr, "}");
+ }
+
+ return (buffer);
+}
+
+
+/*
+ * 'get_points()' - Get a value in points.
+ */
+
+static double /* O - Number in points */
+get_points(double number, /* I - Original number */
+ const char *uval) /* I - Units */
+{
+ if (!strcmp(uval, "mm")) /* Millimeters */
+ return (number * 72.0 / 25.4);
+ else if (!strcmp(uval, "cm")) /* Centimeters */
+ return (number * 72.0 / 2.54);
+ else if (!strcmp(uval, "in")) /* Inches */
+ return (number * 72.0);
+ else if (!strcmp(uval, "ft")) /* Feet */
+ return (number * 72.0 * 12.0);
+ else if (!strcmp(uval, "m")) /* Meters */
+ return (number * 72.0 / 0.0254);
+ else /* Points */
+ return (number);
+}
+
+
/*
* 'match_string()' - Return the number of matching characters.
*/
LIBUSB="-lusb")])
fi
+dnl See if we have libwrap for TCP wrappers support...
+AC_ARG_ENABLE(tcp_wrappers, [ --enable-tcp-wrappers use libwrap for TCP wrappers support, default=no])
+
+LIBWRAP=""
+AC_SUBST(LIBWRAP)
+
+if test x$enable_tcp_wrappers = xyes; then
+ AC_CHECK_LIB(wrap, hosts_access,[
+ AC_CHECK_HEADER(tcpd.h,
+ AC_DEFINE(HAVE_TCPD_H)
+ LIBWRAP="-lwrap")])
+fi
+
dnl Flags for "ar" command...
case $uname in
Darwin* | *BSD*)
# Additional warning options for development testing...
if test -d .svn; then
OPTIM="-Wshadow -Wunused $OPTIM"
+ CFLAGS="-Werror-implicit-function-declaration $CFLAGS"
PHPOPTIONS="-Wno-shadow"
fi
fi
AC_ARG_WITH(rclevels, [ --with-rclevels set run levels for rc scripts],rclevels="$withval",rclevels="2 3 5")
AC_ARG_WITH(rcstart, [ --with-rcstart set start number for rc scripts],rcstart="$withval",rcstart="99")
AC_ARG_WITH(rcstop, [ --with-rcstop set stop number for rc scripts],rcstop="$withval",rcstop="00")
+AC_ARG_WITH(smfmanifestdir, [ --with-smfmanifestdir set path for Solaris SMF manifest],smfmanifestdir="$withval",smfmanifestdir="")
INITDIR=""
INITDDIR=""
RCLEVELS="$rclevels"
RCSTART="$rcstart"
RCSTOP="$rcstop"
+SMFMANIFESTDIR=""
if test x$rcdir = x; then
case "$uname" in
SunOS*)
# Solaris
- INITDIR="/etc"
- RCSTART="81"
+ if test "x$smfmanifestdir" != x; then
+ SMFMANIFESTDIR=$smfmanifestdir
+ else
+ INITDIR="/etc"
+ RCSTART="81"
+ fi
;;
*)
AC_SUBST(RCLEVELS)
AC_SUBST(RCSTART)
AC_SUBST(RCSTOP)
+AC_SUBST(SMFMANIFESTDIR)
dnl Xinetd support...
AC_ARG_WITH(xinetd, [ --with-xinetd set path for xinetd config files],XINETD="$withval",XINETD="")
dnl
AC_ARG_ENABLE(ldap, [ --enable-ldap turn on LDAP support, default=yes])
-AC_ARG_WITH(openldap-libs, [ --with-openldap-libs set directory for OpenLDAP library],
+AC_ARG_WITH(ldap-libs, [ --with-ldap-libs set directory for LDAP library],
LDFLAGS="-L$withval $LDFLAGS"
DSOFLAGS="-L$withval $DSOFLAGS",)
-AC_ARG_WITH(openldap-includes, [ --with-openldap-includes
- set directory for OpenLDAP includes],
+AC_ARG_WITH(ldap-includes, [ --with-ldap-includes set directory for LDAP includes],
CFLAGS="-I$withval $CFLAGS"
CPPFLAGS="-I$withval $CPPFLAGS",)
LIBLDAP=""
if test x$enable_ldap != xno; then
- AC_CHECK_HEADER(ldap.h,
+ AC_CHECK_HEADER(ldap.h, [
AC_CHECK_LIB(ldap, ldap_initialize,
- AC_DEFINE(HAVE_LDAP)
- AC_DEFINE(HAVE_OPENLDAP)
- LIBLDAP="-lldap"))
+ AC_DEFINE(HAVE_LDAP)
+ AC_DEFINE(HAVE_OPENLDAP)
+ LIBLDAP="-lldap"
+ AC_CHECK_LIB(ldap, ldap_start_tls,
+ AC_DEFINE(HAVE_LDAP_SSL)),
+
+ AC_CHECK_LIB(ldap, ldap_init,
+ AC_DEFINE(HAVE_LDAP)
+ AC_DEFINE(HAVE_MOZILLA_LDAP)
+ LIBLDAP="-lldap"
+ AC_CHECK_HEADER(ldap_ssl.h, AC_DEFINE(HAVE_LDAP_SSL_H),,[#include <ldap.h>])
+ AC_CHECK_LIB(ldap, ldapssl_init,
+ AC_DEFINE(HAVE_LDAP_SSL)))
+ )
+ AC_CHECK_LIB(ldap, ldap_set_rebind_proc, AC_DEFINE(HAVE_LDAP_REBIND_PROC))
+ ])
fi
AC_SUBST(LIBLDAP)
#undef HAVE_LDAP
#undef HAVE_OPENLDAP
+#undef HAVE_MOZILLA_LDAP
+#undef HAVE_LDAP_SSL_H
+#undef HAVE_LDAP_SSL
+#undef HAVE_LDAP_REBIND_PROC
/*
#undef HAVE_USB_H
+/*
+ * Do we have libwrap and tcpd.h?
+ */
+
+#undef HAVE_TCPD_H
+
+
#endif /* !_CUPS_CONFIG_H_ */
/*
AC_OUTPUT(Makedefs packaging/cups.list init/cups.sh init/cups-lpd cups-config
conf/cupsd.conf conf/mime.convs conf/pam.std conf/snmp.conf
doc/index.html doc/help/ref-cupsd-conf.html doc/help/standard.html
- init/org.cups.cups-lpd.plist
+ init/org.cups.cups-lpd.plist init/cups.xml
man/client.conf.man man/cups-deviced.man man/cups-driverd.man
man/cups-lpd.man man/cupsaddsmb.man man/cupsd.man
man/cupsd.conf.man man/drv.man man/lpoptions.man
if ((ptr = strchr(line, ':')) == NULL)
{
snprintf(line, sizeof(line),
- _cupsLangString(language, _("Missing value on line %d!")),
- linenum);
- _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
+ _cupsLangString(language, _("Missing value on line %d!")),
+ linenum);
+ _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line, 0);
cupsFileClose(srcfp);
cupsFileClose(dstfp);
_cupsLangString(language,
_("Missing double quote on line %d!")),
linenum);
- _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
+ _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line, 0);
cupsFileClose(srcfp);
cupsFileClose(dstfp);
_cupsLangString(language,
_("Bad option + choice on line %d!")),
linenum);
- _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
+ _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line, 0);
cupsFileClose(srcfp);
cupsFileClose(dstfp);
if (linenum == 0)
{
- snprintf(line, sizeof(line),
- _cupsLangString(language, _("Empty PPD file!")),
- linenum);
- _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
+ _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, _("Empty PPD file!"), 1);
cupsFileClose(dstfp);
unlink(buffer);
if (!dest || !ppd || !samba_server || !samba_user || !samba_password)
{
- _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
return (0);
}
if ((fp = cupsTempFile2(authfile, sizeof(authfile))) == NULL)
{
- _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
return (0);
}
_("Unable to copy Windows 2000 printer "
"driver files (%d)!")), status);
- _cupsSetError(IPP_INTERNAL_ERROR, message);
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
if (logfile)
_cupsLangPrintf(logfile, "%s\n", message);
_("Unable to copy CUPS printer driver "
"files (%d)!")), status);
- _cupsSetError(IPP_INTERNAL_ERROR, message);
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
if (logfile)
_cupsLangPrintf(logfile, "%s\n", message);
_("Unable to install Windows 2000 printer "
"driver files (%d)!")), status);
- _cupsSetError(IPP_INTERNAL_ERROR, message);
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
if (logfile)
_cupsLangPrintf(logfile, "%s\n", message);
_("Unable to copy Windows 9x printer "
"driver files (%d)!")), status);
- _cupsSetError(IPP_INTERNAL_ERROR, message);
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
if (logfile)
_cupsLangPrintf(logfile, "%s\n", message);
_("Unable to install Windows 9x printer "
"driver files (%d)!")), status);
- _cupsSetError(IPP_INTERNAL_ERROR, message);
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
if (logfile)
_cupsLangPrintf(logfile, "%s\n", message);
_("Unable to copy 64-bit Windows printer "
"driver files (%d)!")), status);
- _cupsSetError(IPP_INTERNAL_ERROR, message);
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
if (logfile)
_cupsLangPrintf(logfile, "%s\n", message);
_("Unable to copy 64-bit CUPS printer driver "
"files (%d)!")), status);
- _cupsSetError(IPP_INTERNAL_ERROR, message);
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
if (logfile)
_cupsLangPrintf(logfile, "%s\n", message);
_("Unable to install Windows 2000 printer "
"driver files (%d)!")), status);
- _cupsSetError(IPP_INTERNAL_ERROR, message);
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
if (logfile)
_cupsLangPrintf(logfile, "%s\n", message);
"are installed!")),
sizeof(message));
- _cupsSetError(IPP_NOT_FOUND, message);
+ _cupsSetError(IPP_NOT_FOUND, message, 0);
_cupsLangPrintf(logfile, "%s\n", message);
}
if (have_drivers == 0)
{
- _cupsSetError(IPP_NOT_FOUND, message);
+ _cupsSetError(IPP_NOT_FOUND, message, 0);
unlink(authfile);
_("Unable to set Windows printer driver (%d)!")),
status);
- _cupsSetError(IPP_INTERNAL_ERROR, message);
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
if (logfile)
_cupsLangPrintf(logfile, "%s\n", message);
if (!http || !num_settings || !settings)
{
- _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
if (num_settings)
*num_settings = 0;
snprintf(message, sizeof(message),
- _cupsLangString(cupsLangDefault(), _("open of %s failed: %s")),
+ _cupsLangString(cupsLangDefault(), _("Open of %s failed: %s")),
cupsdconf, strerror(errno));
- _cupsSetError(IPP_INTERNAL_ERROR, message);
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
}
}
else
if (!http || !num_settings || !settings)
{
- _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
return (0);
}
{
if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL)
{
- _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
return (0);
}
}
if (remote)
unlink(cupsdconf);
- _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
return (0);
}
snprintf(message, sizeof(message),
_cupsLangString(cupsLangDefault(), _("stat of %s failed: %s")),
name, strerror(errno));
- _cupsSetError(IPP_INTERNAL_ERROR, message);
+ _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
*name = '\0';
{
*name = '\0';
- _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
invalidate_cupsd_cache(cg);
/*
- * "$Id: backend.c 7583 2008-05-16 17:47:16Z mike $"
+ * "$Id: backend.c 7810 2008-07-29 01:11:15Z mike $"
*
* Backend functions for the Common UNIX Printing System (CUPS).
*
* Contents:
*
* cupsBackendDeviceURI() - Get the device URI for a backend.
+ * cupsBackendReport() - Write a device line from a backend.
+ * quote_string() - Write a quoted string to stdout, escaping \ and ".
*/
/*
#include "globals.h"
+/*
+ * Local functions...
+ */
+
+static void quote_string(const char *s);
+
+
/*
* 'cupsBackendDeviceURI()' - Get the device URI for a backend.
*
/*
- * End of "$Id: backend.c 7583 2008-05-16 17:47:16Z mike $".
+ * 'cupsBackendReport()' - Write a device line from a backend.
+ *
+ * This function writes a single device line to stdout for a backend.
+ * It handles quoting of special characters in the device-make-and-model,
+ * device-info, device-id, and device-location strings.
+ */
+
+void
+cupsBackendReport(
+ const char *device_scheme, /* I - device-scheme string */
+ const char *device_uri, /* I - device-uri string */
+ const char *device_make_and_model, /* I - device-make-and-model string or @code NULL@ */
+ const char *device_info, /* I - device-info string or @code NULL@ */
+ const char *device_id, /* I - device-id string or @code NULL@ */
+ const char *device_location) /* I - device-location string or @code NULL@ */
+{
+ if (!device_scheme || !device_uri)
+ return;
+
+ printf("%s %s", device_scheme, device_uri);
+ if (device_make_and_model && *device_make_and_model)
+ quote_string(device_make_and_model);
+ else
+ quote_string("unknown");
+ quote_string(device_info);
+ quote_string(device_id);
+ quote_string(device_location);
+ putchar('\n');
+ fflush(stdout);
+}
+
+
+/*
+ * 'quote_string()' - Write a quoted string to stdout, escaping \ and ".
+ */
+
+static void
+quote_string(const char *s) /* I - String to write */
+{
+ fputs(" \"", stdout);
+
+ if (s)
+ {
+ while (*s)
+ {
+ if (*s == '\\' || *s == '\"')
+ putchar('\\');
+
+ putchar(*s);
+
+ s ++;
+ }
+ }
+
+ putchar('\"');
+}
+
+
+/*
+ * End of "$Id: backend.c 7810 2008-07-29 01:11:15Z mike $".
*/
*/
extern const char *cupsBackendDeviceURI(char **argv) _CUPS_API_1_2;
-
+extern void cupsBackendReport(const char *device_scheme,
+ const char *device_uri,
+ const char *device_make_and_model,
+ const char *device_info,
+ const char *device_id,
+ const char *device_location)
+ _CUPS_API_1_4;
+
#endif /* !_CUPS_BACKEND_H_ */
typedef void (*cups_device_cb_t)(const char *device_class,
const char *device_id, const char *device_info,
const char *device_make_and_model,
- const char *device_uri, void *user_data);
+ const char *device_uri,
+ const char *device_location, void *user_data);
/**** Device callback @since CUPS 1.4@ ****/
typedef struct cups_option_s /**** Printer Options ****/
* server.
* cupsSetDests2() - Save the list of destinations for the specified
* server.
+ * appleCopyNetwork() - Get the network ID for the current location.
* appleGetDefault() - Get the default printer for this location.
* appleGetLocations() - Get the location history array.
- * appleGetNetwork() - Get the network ID for the current location.
* appleGetPrinter() - Get a printer from the history array.
* appleSetDefault() - Set the default printer for this location.
* appleUseLastPrinter() - Get the default printer preference value.
*/
#ifdef __APPLE__
+static CFStringRef appleCopyNetwork(void);
static char *appleGetDefault(char *name, int namesize);
static CFArrayRef appleGetLocations(void);
-static CFStringRef appleGetNetwork(void);
static CFStringRef appleGetPrinter(CFArrayRef locations, CFStringRef network,
CFIndex *locindex);
static void appleSetDefault(const char *name);
#ifdef __APPLE__
+/*
+ * 'appleCopyNetwork()' - Get the network ID for the current location.
+ */
+
+static CFStringRef /* O - Network ID */
+appleCopyNetwork(void)
+{
+ SCDynamicStoreRef dynamicStore; /* System configuration data */
+ CFStringRef key; /* Current network configuration key */
+ CFDictionaryRef ip_dict; /* Network configuration data */
+ CFStringRef network = NULL; /* Current network ID */
+
+
+ if ((dynamicStore = SCDynamicStoreCreate(NULL, CFSTR("Printing"), NULL,
+ NULL)) != NULL)
+ {
+ if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(
+ NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4)) != NULL)
+ {
+ if ((ip_dict = SCDynamicStoreCopyValue(dynamicStore, key)) != NULL)
+ {
+ if ((network = CFDictionaryGetValue(ip_dict,
+ kSCPropNetIPv4Router)) != NULL)
+ CFRetain(network);
+
+ CFRelease(ip_dict);
+ }
+
+ CFRelease(key);
+ }
+
+ CFRelease(dynamicStore);
+ }
+
+ return (network);
+}
+
+
/*
* 'appleGetDefault()' - Get the default printer for this location.
*/
* Get the current location...
*/
- if ((network = appleGetNetwork()) == NULL)
+ if ((network = appleCopyNetwork()) == NULL)
{
DEBUG_puts("appleGetDefault: Unable to get current network...");
return (NULL);
DEBUG_puts("appleGetDefault: Missing or bad location history array...");
+ CFRelease(network);
+
return (NULL);
}
else
name[0] = '\0';
+ CFRelease(network);
+
DEBUG_printf(("appleGetDefault: Returning \"%s\"...\n", name));
return (*name ? name : NULL);
}
-/*
- * 'appleGetNetwork()' - Get the network ID for the current location.
- */
-
-static CFStringRef /* O - Network ID */
-appleGetNetwork(void)
-{
- SCDynamicStoreRef dynamicStore; /* System configuration data */
- CFStringRef key; /* Current network configuration key */
- CFDictionaryRef ip_dict; /* Network configuration data */
- CFStringRef network = NULL; /* Current network ID */
-
-
- if ((dynamicStore = SCDynamicStoreCreate(NULL, CFSTR("Printing"), NULL,
- NULL)) != NULL)
- {
- if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(
- NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4)) != NULL)
- {
- if ((ip_dict = SCDynamicStoreCopyValue(dynamicStore, key)) != NULL)
- {
- if ((network = CFDictionaryGetValue(ip_dict,
- kSCPropNetIPv4Router)) != NULL)
- CFRetain(network);
-
- CFRelease(ip_dict);
- }
-
- CFRelease(key);
- }
-
- CFRelease(dynamicStore);
- }
-
- return (network);
-}
-
-
/*
* 'appleGetPrinter()' - Get a printer from the history array.
*/
* Get the current location...
*/
- if ((network = appleGetNetwork()) == NULL)
+ if ((network = appleCopyNetwork()) == NULL)
{
DEBUG_puts("appleSetDefault: Unable to get current network...");
return;
CFRelease(newlocation);
}
+ CFRelease(network);
CFRelease(newprinter);
}
*
* Contents:
*
+ * cupsGetDevices() - Get available printer devices.
*/
/*
const char *device_class, /* device-class value */
*device_id, /* device-id value */
*device_info, /* device-info value */
+ *device_location, /* device-location value */
*device_make_and_model, /* device-make-and-model value */
*device_uri; /* device-uri value */
int blocking; /* Current blocking-IO mode */
device_class = NULL;
device_id = NULL;
device_info = NULL;
+ device_location = "";
device_make_and_model = NULL;
device_uri = NULL;
attr = NULL;
if (device_class && device_id && device_info && device_make_and_model &&
device_uri)
(*callback)(device_class, device_id, device_info,
- device_make_and_model, device_uri, user_data);
+ device_make_and_model, device_uri, device_location,
+ user_data);
device_class = NULL;
device_id = NULL;
device_info = NULL;
+ device_location = "";
device_make_and_model = NULL;
device_uri = NULL;
}
else if (!strcmp(attr->name, "device-info") &&
attr->value_tag == IPP_TAG_TEXT)
device_info = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "device-location") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_location = attr->values[0].string.text;
else if (!strcmp(attr->name, "device-make-and-model") &&
attr->value_tag == IPP_TAG_TEXT)
device_make_and_model = attr->values[0].string.text;
if (device_class && device_id && device_info && device_make_and_model &&
device_uri)
(*callback)(device_class, device_id, device_info,
- device_make_and_model, device_uri, user_data);
+ device_make_and_model, device_uri, device_location, user_data);
/*
* Set the IPP status and return...
httpFlush(http);
if (status == IPP_ERROR)
- _cupsSetError(IPP_ERROR, NULL);
+ _cupsSetError(IPP_ERROR, NULL, 0);
else
{
attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
attr ? attr->values[0].string.text : ""));
_cupsSetError(response->request.status.status_code,
- attr ? attr->values[0].string.text :
- ippErrorString(response->request.status.status_code));
+ attr ? attr->values[0].string.text :
+ ippErrorString(response->request.status.status_code), 0);
}
ippDelete(response);
extern http_t *_cupsConnect(void);
extern const char *_cupsGetPassword(const char *prompt);
extern _cups_globals_t *_cupsGlobals(void);
-extern void _cupsSetError(ipp_status_t status, const char *message);
+extern void _cupsSetError(ipp_status_t status, const char *message,
+ int localize);
extern void _cupsSetHTTPError(http_status_t status);
*
* Contents:
*
- * _cupsLangPrintf() - Print a formatted message string to a file.
- * _cupsLangPuts() - Print a static message string to a file.
- * _cupsSetLocale() - Set the current locale and transcode the command-line.
+ * _cupsLangPrintError() - Print a message followed by a standard error.
+ * _cupsLangPrintf() - Print a formatted message string to a file.
+ * _cupsLangPuts() - Print a static message string to a file.
+ * _cupsSetLocale() - Set the current locale and transcode the
+ * command-line.
*/
/*
_cupsBackChannelRead
_cupsBackChannelWrite
_cupsBackendDeviceURI
+_cupsBackendReport
_cupsCancelJob
_cupsCancelJob2
_cupsCharsetToUTF8
* Add the "custom" option...
*/
- if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
- {
- DEBUG_puts("Unable to add Custom choice!");
+ if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
+ {
+ DEBUG_puts("Unable to add Custom choice!");
- cg->ppd_status = PPD_ALLOC_ERROR;
+ cg->ppd_status = PPD_ALLOC_ERROR;
- goto error;
- }
+ goto error;
+ }
strlcpy(choice->text, text[0] ? text : _("Custom"),
sizeof(choice->text));
if (custom_option)
{
- if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
- {
- DEBUG_puts("Unable to add Custom choice!");
+ if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
+ {
+ DEBUG_puts("Unable to add Custom choice!");
- cg->ppd_status = PPD_ALLOC_ERROR;
+ cg->ppd_status = PPD_ALLOC_ERROR;
- goto error;
- }
+ goto error;
+ }
strlcpy(choice->text, text[0] ? text : _("Custom"),
sizeof(choice->text));
if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
{
- if ((choice = ppd_add_choice(option, "Custom")) == NULL)
- {
- DEBUG_puts("Unable to add Custom choice!");
+ if ((choice = ppdFindChoice(option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+ {
+ DEBUG_puts("Unable to add Custom choice!");
- cg->ppd_status = PPD_ALLOC_ERROR;
+ cg->ppd_status = PPD_ALLOC_ERROR;
- goto error;
- }
+ goto error;
+ }
strlcpy(choice->text,
custom_attr->text[0] ? custom_attr->text : _("Custom"),
*/
_cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
- strerror(errno));
+ NULL, 0);
ippDelete(request);
{
ippDelete(request);
- _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL));
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
return (NULL);
}
*/
_cupsSetError(errno == EBADF ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
- strerror(errno));
+ NULL, 0);
ippDelete(request);
ippDelete(request);
- _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR));
+ _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR), 0);
return (NULL);
}
ippDelete(response);
response = NULL;
- _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno));
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
}
}
else if (status != HTTP_ERROR)
attr ? attr->values[0].string.text : ""));
_cupsSetError(response->request.status.status_code,
- attr ? attr->values[0].string.text :
- ippErrorString(response->request.status.status_code));
+ attr ? attr->values[0].string.text :
+ ippErrorString(response->request.status.status_code), 0);
}
else if (status != HTTP_OK)
_cupsSetHTTPError(status);
if ((http = cg->http) == NULL)
{
- _cupsSetError(IPP_INTERNAL_ERROR, "No active connection");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1);
return (-1);
}
}
if (!request || !resource)
{
- _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL));
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
return (HTTP_ERROR);
}
if ((http = cg->http) == NULL)
{
- _cupsSetError(IPP_INTERNAL_ERROR, "No active connection");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1);
return (HTTP_ERROR);
}
}
void
_cupsSetError(ipp_status_t status, /* I - IPP status code */
- const char *message) /* I - status-message value */
+ const char *message, /* I - status-message value */
+ int localize) /* I - Localize the message? */
{
_cups_globals_t *cg; /* Global data */
+ if (!message && errno)
+ {
+ message = strerror(errno);
+ localize = 0;
+ }
+
cg = _cupsGlobals();
cg->last_error = status;
if (cg->last_status_message)
{
- free(cg->last_status_message);
+ _cupsStrFree(cg->last_status_message);
cg->last_status_message = NULL;
}
if (message)
- cg->last_status_message = strdup(message);
+ {
+ if (localize)
+ {
+ /*
+ * Get the message catalog...
+ */
+
+ if (!cg->lang_default)
+ cg->lang_default = cupsLangDefault();
+
+ cg->last_status_message = _cupsStrAlloc(_cupsLangString(cg->lang_default,
+ message));
+ }
+ else
+ cg->last_status_message = _cupsStrAlloc(message);
+ }
DEBUG_printf(("_cupsSetError: last_error=%s, last_status_message=\"%s\"\n",
- ippErrorString(cg->last_error), message ? message : ""));
+ ippErrorString(cg->last_error),
+ cg->last_status_message ? cg->last_status_message : ""));
}
switch (status)
{
case HTTP_NOT_FOUND :
- _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
+ _cupsSetError(IPP_NOT_FOUND, httpStatus(status), 0);
break;
case HTTP_UNAUTHORIZED :
- _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
+ _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status), 0);
break;
case HTTP_FORBIDDEN :
- _cupsSetError(IPP_FORBIDDEN, httpStatus(status));
+ _cupsSetError(IPP_FORBIDDEN, httpStatus(status), 0);
break;
case HTTP_BAD_REQUEST :
- _cupsSetError(IPP_BAD_REQUEST, httpStatus(status));
+ _cupsSetError(IPP_BAD_REQUEST, httpStatus(status), 0);
break;
case HTTP_REQUEST_TOO_LARGE :
- _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status));
+ _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status), 0);
break;
case HTTP_NOT_IMPLEMENTED :
- _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status));
+ _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status), 0);
break;
case HTTP_NOT_SUPPORTED :
- _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status));
+ _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status), 0);
break;
default :
DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
status));
- _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status), 0);
break;
}
}
if (!strncmp(argv[1], "-d", 2))
+ {
filename = cupsGetPPD(argv[1] + 2);
+ if (!filename)
+ {
+ printf("%s: %s\n", argv[1], cupsLastErrorString());
+ return (1);
+ }
+ }
else
filename = argv[1];
if (job_id < -1 || (!name && job_id == 0))
{
- _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL));
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
return (0);
}
if (!name)
{
- _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
return (0);
}
if ((request = ippNewRequest(IPP_CREATE_JOB)) == NULL)
{
- _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(ENOMEM), 0);
return (0);
}
if (!classes)
{
- _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
return (0);
}
if (!jobs)
{
- _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
return (-1);
}
if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
"localhost", 0, "/printers/%s", name) != HTTP_URI_OK)
{
- _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Unable to create printer-uri!"), 1);
return (-1);
}
* Ran out of memory!
*/
- _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
cupsFreeJobs(n, *jobs);
*jobs = NULL;
if (!name)
{
- _cupsSetError(IPP_INTERNAL_ERROR, "No printer name!");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No printer name!"), 1);
return (HTTP_NOT_ACCEPTABLE);
}
if (!modtime)
{
- _cupsSetError(IPP_INTERNAL_ERROR, "No modification time!");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No modification time!"), 1);
return (HTTP_NOT_ACCEPTABLE);
}
if (!buffer || bufsize <= 1)
{
- _cupsSetError(IPP_INTERNAL_ERROR, "Bad filename buffer!");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad filename buffer!"), 1);
return (HTTP_NOT_ACCEPTABLE);
}
* Can't open file; close the server connection and return NULL...
*/
- _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
if (http2 != http)
httpClose(http2);
switch (status)
{
case HTTP_NOT_FOUND :
- _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
+ _cupsSetError(IPP_NOT_FOUND, httpStatus(status), 0);
break;
case HTTP_UNAUTHORIZED :
- _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
+ _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status), 0);
break;
default :
DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
status));
- _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status), 0);
break;
}
if (!printers)
{
- _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
return (0);
}
if (!name)
{
- _cupsSetError(IPP_INTERNAL_ERROR, "No PPD name!");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No PPD name!"), 1);
return (NULL);
}
* Can't open file; close the server connection and return NULL...
*/
- _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
return (NULL);
}
if (!name || num_files < 1 || !files)
{
- _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
return (0);
}
if ((request = ippNewRequest(IPP_SEND_DOCUMENT)) == NULL)
{
- _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(ENOMEM), 0);
return (0);
}
{
if ((cg->http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption())) == NULL)
- _cupsSetError(IPP_SERVICE_UNAVAILABLE,
- errno ? strerror(errno) : "Unable to connect to host.");
+ {
+ if (errno)
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+ else
+ _cupsSetError(IPP_SERVICE_UNAVAILABLE,
+ _("Unable to connect to host."), 1);
+ }
}
/*
if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
"localhost", 0, "/printers/%s", name) != HTTP_URI_OK)
{
- _cupsSetError(IPP_INTERNAL_ERROR, "Unable to create printer-uri!");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Unable to create printer-uri!"), 1);
*host = '\0';
*resource = '\0';
if (!strncmp(resource, "/classes/", 9))
{
- _cupsSetError(IPP_INTERNAL_ERROR, _("No printer-uri found for class!"));
+ _cupsSetError(IPP_INTERNAL_ERROR,
+ _("No printer-uri found for class!"), 1);
*host = '\0';
*resource = '\0';
}
if (cupsLastError() != IPP_NOT_FOUND)
- _cupsSetError(IPP_INTERNAL_ERROR, _("No printer-uri found!"));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("No printer-uri found!"), 1);
*host = '\0';
*resource = '\0';
*
* API versioning definitions for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
*
* These coded instructions, statements, and computer programs are the
* property of Apple Inc. and are protected by Federal copyright
* _CUPS_API_1_1, _CUPS_API_1_1_19, _CUPS_API_1_1_20, _CUPS_API_1_1_21,
* _CUPS_API_1_2, _CUPS_API_1_3, _CUPS_API_1_4 - which add compiler-
* specific attributes that flag functions that are deprecated or added
- * in particular releases. On Mac OS X, the _CUPS_API_* constants are
- * defined based on the value of the MAC_OS_X_VERSION_MAX_ALLOWED constant
+ * in particular releases.
+ *
+ * On Mac OS X, the _CUPS_API_* constants are defined based on the values of
+ * the MAC_OS_X_VERSION_MIN_ALLOWED and MAC_OS_X_VERSION_MAX_ALLOWED constants
* provided by the compiler.
*/
# if defined(__APPLE__) && !defined(_CUPS_SOURCE)
-# if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3
-# define _CUPS_API_1_1_19 __attribute__((unavailable))
-# define _CUPS_API_1_1_20 __attribute__((unavailable))
-# define _CUPS_API_1_1_21 __attribute__((unavailable))
-# define _CUPS_API_1_2 __attribute__((unavailable))
-# define _CUPS_API_1_3 __attribute__((unavailable))
-# define _CUPS_API_1_4 __attribute__((unavailable))
-# elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
-# define _CUPS_API_1_1_19
-# define _CUPS_API_1_1_20 __attribute__((unavailable))
-# define _CUPS_API_1_1_21 __attribute__((unavailable))
-# define _CUPS_API_1_2 __attribute__((unavailable))
-# define _CUPS_API_1_3 __attribute__((unavailable))
-# define _CUPS_API_1_4 __attribute__((unavailable))
-# elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
-# define _CUPS_API_1_1_19
-# define _CUPS_API_1_1_20
-# define _CUPS_API_1_1_21
-# define _CUPS_API_1_2 __attribute__((unavailable))
-# define _CUPS_API_1_3 __attribute__((unavailable))
-# define _CUPS_API_1_4 __attribute__((unavailable))
-# elif MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5
-# define _CUPS_API_1_1_19
-# define _CUPS_API_1_1_20
-# define _CUPS_API_1_1_21
-# define _CUPS_API_1_2
-# define _CUPS_API_1_3
-# define _CUPS_API_1_4 __attribute__((unavailable))
-# else
-# define _CUPS_API_1_1_19
-# define _CUPS_API_1_1_20
-# define _CUPS_API_1_1_21
-# define _CUPS_API_1_2
-# define _CUPS_API_1_3
-# define _CUPS_API_1_4
-# endif /* MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_x */
+# include <AvailabilityMacros.h>
+# ifndef AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+# define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER __attribute__((unavailable))
+# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER */
+# ifndef AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+# define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER __attribute__((unavailable))
+# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER */
+# ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+# define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER __attribute__((unavailable))
+# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER */
+# ifndef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+# define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER __attribute__((unavailable))
+# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER */
+# define _CUPS_API_1_1_19 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+# define _CUPS_API_1_1_20 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+# define _CUPS_API_1_1_21 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+# define _CUPS_API_1_2 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+# define _CUPS_API_1_3 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+# define _CUPS_API_1_4 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
# else
# define _CUPS_API_1_1_19
# define _CUPS_API_1_1_20
vertical-align: top;
}
+TH.sublabel {
+ padding-top: 0pt;
+ text-align: right;
+ font-weight: normal;
+}
+
HR {
border: solid thin;
}
</HEAD>
<BODY>
-<P>CUPS 1.3 adds Kerberos support which allows you to use a Key Distribution
-Center (KDC) for authentication on your local CUPS server and when printing
-to a remote authenticated queue. This document describes how to configure
-CUPS to use Kerberos authentication and provides helpful links to the MIT
-help pages for configuring Kerberos on your systems and network.</P>
+<P>CUPS allows you to use a Key Distribution Center (KDC) for authentication
+on your local CUPS server and when printing to a remote authenticated queue.
+This document describes how to configure CUPS to use Kerberos authentication
+and provides links to the MIT help pages for configuring Kerberos on your
+systems and network.</P>
-<BLOCKQUOTE><B>Note:</B>
-<P>In order to use Kerberos-authenticated shared printers, you <EM>must</EM> be
-running a version of MIT Kerberos with the <TT>krb5_cc_new_unique()</TT>
-function or Heimdal Kerberos. Otherwise, only local Kerberos authentication
-is supported.</P>
+<H2 CLASS="title"><A NAME="REQUIREMENTS">System Requirements</A></H2>
-</BLOCKQUOTE>
+<p>The following are required to use Kerberos with CUPS:</p>
+
+<ol>
+
+ <li>Heimdal Kerberos (any version) or MIT Kerberos (1.6.3 or newer)</li>
+
+ <li>Properly configured Domain Name System (DNS)
+ infrastructure:<ol type='a'>
+ <li>DNS server(s) with static IP addresses for all CUPS clients
+ and servers or configured to allow DHCP updates to the host
+ addresses</li>
+ <li>All CUPS clients and servers configured to use the same
+ DNS server(s)</li>
+ </ol></li>
+
+ <li>Properly configured Kerberos infrastructure:<ol type='a'>
+ <li>KDC configured to allow CUPS clients and servers to obtain
+ Service Granting Tickets (SGTs) for the "ipp" service</li>
+ <li>LDAP-based user accounts - both OpenDirectory and
+ ActiveDirectory provide this with the KDC</li>
+ <li>CUPS clients and servers bound to the KDC and LDAP
+ server(s)</li>
+ </ol></li>
+
+ <li>An "ipp" Service Granting Ticket (SGT) for every CUPS client and
+ server</li>
+
+</ol>
<H2 CLASS="title"><A NAME="KRB5">Configuring Kerberos on Your System</A></H2>
http://localhost:631/admin
</PRE>
-<P>After you have enabled Kerberos authentication, add <tt>AuthType Default</tt>
-lines to the policies you want to protect with authentication, for example:</P>
-
-<PRE CLASS="command">
-<EM>Listing 1: <A NAME="LISTING01">Remote Printer Operation Policy</A></EM>
-
- 1 <Policy remote>
- 2 # Job-related operations must be done by the owner or an
- administrator...
- 3 <Limit Send-Document Send-URI Hold-Job Release-Job
- Restart-Job Purge-Jobs Set-Job-Attributes
- Create-Job-Subscription Renew-Subscription
- Cancel-Subscription Get-Notifications Reprocess-Job
- Cancel-Current-Job Suspend-Current-Job Resume-Job
- CUPS-Move-Job>
- 4 AuthType Default
- 5 Require user @OWNER @SYSTEM
- 6 Order deny,allow
- 7 </Limit>
- 8
- 9 # Require authentication when creating jobs
-10 <Limit Create-Job Print-Job Print-URI>
-11 AuthType Default
-12 Require valid-user
-13 Order deny,allow
-14 </Limit>
-15
-16 # All administration operations require an administrator
- to authenticate...
-17 <Limit CUPS-Add-Printer CUPS-Delete-Printer
- CUPS-Add-Class CUPS-Delete-Class CUPS-Set-Default>
-18 AuthType Default
-19 Require user @SYSTEM
-20 Order deny,allow
-21 </Limit>
-22
-23 # All printer operations require a printer operator
- to authenticate...
-24 <Limit Pause-Printer Resume-Printer
- Set-Printer-Attributes Enable-Printer Disable-Printer
- Pause-Printer-After-Current-Job Hold-New-Jobs
- Release-Held-New-Jobs Deactivate-Printer Activate-Printer
- Restart-Printer Shutdown-Printer Startup-Printer
- Promote-Job Schedule-Job-After CUPS-Accept-Jobs
- CUPS-Reject-Jobs>
-25 AuthType Default
-26 Require user <em>varies by OS</em>
-27 Order deny,allow
-28 </Limit>
-29
-30 # Only the owner or an administrator can cancel or
- authenticate a job...
-31 <Limit Cancel-Job CUPS-Authenticate-Job>
-32 Require user @OWNER @SYSTEM
-33 Order deny,allow
-34 </Limit>
-35
-36 <Limit All>
-37 Order deny,allow
-38 </Limit>
-39 </Policy>
-</PRE>
+<P>After you have enabled Kerberos authentication, use the built-in
+"authenticated" policy or your own custom policies with the printers you
+will be sharing. See <a href="policies.html">Managing Operation Policies</a>
+for more information.</P>
<H2 CLASS="title"><A NAME="IMPLEMENT">Implementation Information</A></H2>
-<P>CUPS implements Kerberos over HTTP using GSS API and the service name
-"ipp". Delegation of credentials, which is needed when printing to a
-remote/shared printer with Kerberos authentication, is currently only supported
-when using a single KDC on your network.</P>
-
-<P>After getting a user's Kerberos credentials, CUPS strips the "@KDC"
-portion of the username so that it can check the group membership locally,
-effectively treating the Kerberos account as a local user account.</P>
+<P>CUPS implements Kerberos over HTTP using GSSAPI and the service name
+"ipp". Because of limitations in the HTTP GSSAPI protocol extension, only
+a single domain/KDC is supported for authentication.</P>
+
+<P>When doing printing tasks that require authentication, CUPS requests a
+single-use "ticket" from your login session to authenticate who you are.
+This ticket gives CUPS a username of the form "user@REALM", which is then
+converted to just "user" for purposes of user and group checks.</P>
+
+<P>In order to support printing to a shared printer, CUPS has to ask the KDC
+for a copy of your credentials (this is called delegation) that can be sent to
+the remote server for authenticatation. Delegation only works when the system
+has a stable hostname which maps to the current address of the system, which
+is why you need a static IP address or DHCP that updates the DNS entry for your
+system.</P>
</BODY>
</HTML>
image larger than the page, multiple pages will be printed to
satisfy the request.
-<H3><A NAME="hue">Adjusting Image Hue (Tint)</A></H3>
-
-<P>The <CODE>-o hue=value</CODE> option will adjust the hue of the
-printed image, much like the tint control on your television:
-
-<PRE CLASS="command">
-lp -o hue=<EM>value</EM> filename
-lpr -o hue=<EM>value</EM> filename
-</PRE>
-
-<P>The <CODE>value</CODE> argument is a number from -360 to 360 and represents
-the color hue rotation. The following table summarizes the change you'll see
-with different colors:</P>
-
-<DIV CLASS="table"><TABLE SUMMARY="Hue Values">
-<TR>
- <TH>Original</TH>
- <TH>hue=-45</TH>
- <TH>hue=45</TH>
-</TR>
-<TR>
- <TD>Red</TD>
- <TD>Purple</TD>
- <TD>Yellow-orange</TD>
-</TR>
-<TR>
- <TD>Green</TD>
- <TD>Yellow-green</TD>
- <TD>Blue-green</TD>
-</TR>
-<TR>
- <TD>Yellow</TD>
- <TD>Orange</TD>
- <TD>Green-yellow</TD>
-</TR>
-<TR>
- <TD>Blue</TD>
- <TD>Sky-blue</TD>
- <TD>Purple</TD>
-</TR>
-<TR>
- <TD>Magenta</TD>
- <TD>Indigo</TD>
- <TD>Crimson</TD>
-</TR>
-<TR>
- <TD>Cyan</TD>
- <TD>Blue-green</TD>
- <TD>Light-navy-blue</TD>
-</TR>
-</TABLE></DIV>
-
-<P>The default hue adjustment is 0.
-
-<H3><A NAME="saturation">Adjusting Image Saturation (Color)</A></H3>
-
-<P>The <CODE>-o saturation=percent</CODE> option adjusts the saturation
-of the colors in an image, much like the color control on your television:</P>
-
-<PRE CLASS="command">
-lp -o saturation=<EM>percent</EM> filename
-lpr -o saturation=<EM>percent</EM> filename
-</PRE>
-
-<P>The <CODE>percent</CODE> argument specifies the color saturation
-from 0 to 200. A color saturation of 0 produces a black-and-white
-print, while a value of 200 will make the colors extremely intense.</P>
-
-<P>The default saturation is 100.</P>
-
<H2 CLASS="title"><A NAME="HPGL2OPTIONS">HP-GL/2 Options</A></H2>
default is undefined.</P>
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.4</SPAN><A NAME="BrowseLDAPCACertFile">BrowseLDAPCACertFile</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseLDAPCACertFile /etc/cups/ssl/certs
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseLDAPCACertFile</CODE> directive specifies the SSL certificate
+authority file to use for LDAP + SSL. The default is undefined.</P>
+
+
<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="BrowseLDAPDN">BrowseLDAPDN</A></H2>
<H3>Examples</H3>
<p>The device-info attribute specifies a human-readable string describing
the device, e.g. "Parallel Port #1".
+<h4><a name="device-location">device-location (text(127))</a><span class="info">CUPS 1.4</span></h4>
+
+<p>The device-location attribute specifies the physical location of the
+printer.
+
<h4><a name="device-make-and-model">device-make-and-model (text(127))</a></h4>
-<p>The device-makr-and-model attribute specifies a device
+<p>The device-make-and-model attribute specifies a device
identification string provided by the printer connected to the device.
If the device or printer does not support identification then this
attribute contains the string "unknown".
rendered entirely in black ink (blackplot=true) or using the colors and shades
specified in the file (blackplot=false). The default value is false.
-<h4><a name="brightness">brightness (integer(0:200))</a></h4>
+<h4><a name="brightness">brightness (integer(0:200))</a><span class="info">Deprecated</span></h4>
<p>The brightness attribute specifies the overall brightness of the printed
output in percent. A brightness of 100 is normal, while 200 is twice as
<p>Brightness is applied to the Cyan, Magenta, Yellow, and Black values using
the function "f(x) = brightness / 100 * x".
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
+
+</blockquote>
+
<h4><a name="columns">columns (integer(1:4))</a></h4>
<p>The columns attribute specifies the number of columns to generate when
fit on the selected media (fitplot=true) or use the physical scale specified
in the plot file (fitplot=false). The default value is false.
-<h4><a name="gamma">gamma (integer(1:10000))</a></h4>
+<h4><a name="gamma">gamma (integer(1:10000))</a><span class="info">Deprecated</span></h4>
<p>The gamma attribute specifies the luminance correction for the output.
A value of 1000 specifies no correction, while values of 2000 and 500 will
1000.
<p>Gamma is applied to the Red, Green, and Blue values (or luminance for
-grayscale output) using the function "f(x) = x<SUp>(1000/gamma)</SUp>".
+grayscale output) using the function "f(x) = x<sup>(1000/gamma)</sup>".
+
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
-<h4><a name="hue">hue (integer(-180:180))</a></h4>
+</blockquote>
+
+<h4><a name="hue">hue (integer(-180:180))</a><span class="info">Deprecated</span></h4>
<p>The hue attribute specifies a color hue rotation when printing image
files. The default value is 0.
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
+
+</blockquote>
+
<h4><a name="job-billing">job-billing (text(MAX))</a><span class='info'>CUPS 1.1</span></h4>
<p>The job-billing attribute provides a text value to associate with a job
with a shaded header and keyword highlighting (prettyprint=true) or without
additional formatting (prettyprint=false). The default value is false.
-<h4><a name="saturation">saturation (integer(0:200))</a></h4>
+<h4><a name="saturation">saturation (integer(0:200))</a><span class="info">Deprecated</span></h4>
<p>The saturation attribute specifies the color saturation when
printing image files. A saturation of 100 is normal, while values of 50
and 200 will be half and twice as colorful, respectively. The default
value is 100.
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
+
+</blockquote>
+
<h4><a name="scaling">scaling (integer(1:1000))</a></h4>
<p>The scaling attribute specifies the scaling of image files with
</table></div>
+<h2 class='title'><a name='MEDIA'>Media Attributes</a></h2>
+
+<p>The CUPS media attributes allow drivers to specify alternate custom page
+size limits based on up to two options.</p>
+
+<h3><span class='info'>CUPS 1.4</span><a name='cupsMediaQualifier2'>cupsMediaQualifier2</a></h3>
+
+<p class='summary'>*cupsMediaQualifier2: MainKeyword</p>
+
+<p>This attribute specifies the second option to use for overriding the
+custom page size limits.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4</span><a name='cupsMediaQualifier3'>cupsMediaQualifier3</a></h3>
+
+<p class='summary'>*cupsMediaQualifier3: MainKeyword</p>
+
+<p>This attribute specifies the third option to use for overriding the
+custom page size limits.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4</span><a name='cupsMinSize'>cupsMinSize</a></h3>
+
+<p class='summary'>*cupsMinSize .Qualifier2.Qualifier3: "width length"<br>
+*cupsMinSize .Qualifier2.: "width length"<br>
+*cupsMinSize ..Qualifier3: "width length"</p>
+
+<p>This attribute specifies alternate minimum custom page sizes in points.
+The <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a> and
+<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> attributes
+are used to identify options to use for matching.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4</span><a name='cupsMaxSize'>cupsMaxSize</a></h3>
+
+<p class='summary'>*cupsMaxSize .Qualifier2.Qualifier3: "width length"<br>
+*cupsMaxSize .Qualifier2.: "width length"<br>
+*cupsMaxSize ..Qualifier3: "width length"</p>
+
+<p>This attribute specifies alternate maximum custom page sizes in points.
+The <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a> and
+<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> attributes
+are used to identify options to use for matching.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+
<h2 class='title'><a name='ATTRIBUTES'>General Attributes</a></h2>
<h3><span class='info'>CUPS 1.3</span><a name='cupsBackSide'>cupsBackSide</a></h3>
<ul>
- <li>Added <tt>cupsCommands</tt> attribute.</li>
+ <li>Added <a href='#cupsCommands'><tt>cupsCommands</tt></a>
+ attribute.</li>
- <li>Added <tt>cupsMarkerName</tt> attribute.</li>
+ <li>Added <a href='#cupsMarkerName'><tt>cupsMarkerName</tt></a>
+ attribute.</li>
- <li>Added <tt>cupsMarkerNotice</tt> attribute.</li>
+ <li>Added <a href='#cupsMarkerNotice'><tt>cupsMarkerNotice</tt></a>
+ attribute.</li>
- <li>Added <tt>cupsPJLDisplay</tt> attribute.</li>
+ <li>Added <a href='#cupsPJLDisplay'><tt>cupsPJLDisplay</tt></a>
+ attribute.</li>
- <li>Added <tt>cupsUIResolver</tt> and <tt>cupsUIConstraints</tt>
+ <li>Added <a href='#cupsUIResolver'><tt>cupsUIResolver</tt></a> and
+ <a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>
attributes.</li>
+ <li>Added
+ <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a>,
+ <a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a>,
+ <a href='#cupsMinSize'><tt>cupsMinSize</tt></a>, and
+ <a href='#cupsMaxSize'><tt>cupsMaxSize</tt></a> attributes.</li>
+
</ul>
<ul>
- <li>Added <tt>cupsBackSide</tt> and deprecated <tt>cupsFlipDuplex</tt>.</li>
+ <li>Added <a href='#cupsBackSide'><tt>cupsBackSide</tt></a> and
+ deprecated <a href='#cupsFlipDuplex'><tt>cupsFlipDuplex</tt></a>.</li>
- <li>Added text URI information to <tt>cupsIPPReason</tt> documentation.</li>
+ <li>Added text URI information to
+ <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> documentation.</li>
- <li>Added <tt>APPrinterPreset</tt>, <tt>cupsIPPFinishings</tt>, and <tt>cupsPreFilter</tt> attributes.</li>
+ <li>Added <a href='#APPrinterPreset'><tt>APPrinterPreset</tt></a>,
+ <a href='#cupsIPPFinishings'><tt>cupsIPPFinishings</tt></a>, and
+ <a href='#cupsPreFilter'><tt>cupsPreFilter</tt></a> attributes.</li>
- <li>Added discussion of custom option code, sample <tt>CustomPageSize</tt> code, and "do not use dict and put" note.</li>
+ <li>Added discussion of custom option code, sample
+ <tt>CustomPageSize</tt> code, and "do not use dict and put" note.</li>
</ul>
<li>Added custom option values support</li>
- <li>Added <tt>APHelpBook</tt> attribute</li>
+ <li>Added <a href='#APHelpBook'><tt>APHelpBook</tt></a> attribute</li>
- <li>Added <tt>APDuplexRequiresFlippedMargin</tt> attribute</li>
+ <li>Added <a href='#APDuplexRequiresFlippedMargin'><tt>APDuplexRequiresFlippedMargin</tt></a>
+ attribute</li>
- <li>Added <tt>cupsICCProfile</tt> attribute</li>
+ <li>Added <a href='#cupsICCProfile'><tt>cupsICCProfile</tt></a> attribute</li>
- <li>Added <tt>cupsIPPReason</tt> attribute</li>
+ <li>Added <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> attribute</li>
- <li>Added <tt>cupsLanguages</tt> attribute</li>
+ <li>Added <a href='#cupsLanguages'><tt>cupsLanguages</tt></a> attribute</li>
- <li>Added <tt>cupsPortMonitor</tt> attribute</li>
+ <li>Added <a href='#cupsPortMonitor'><tt>cupsPortMonitor</tt></a> attribute</li>
<li>Removed <tt>cupsProtocol</tt> attribute</li>
<ul>
- <li>Added <tt>cupsFlipDuplex</tt> attribute</li>
+ <li>Added <a href='#cupsFlipDuplex'><tt>cupsFlipDuplex</tt></a> attribute</li>
<li>Added <tt>cupsProtocol</tt> attribute</li>
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Service manifest for CUPS.
+
+ This service manifest introduces smf(5) services for CUPS. The services
+ described in this file are as follows:
+
+ svc:/application/cups/scheduler:default
+ svc:/application/cups/in-lpd:default
+
+ NOTE: This service manifest is not editable; its contents will be
+ overwritten by package or patch operations, including operating system
+ upgrade. Make customizations in a different file.
+
+ Norm.Jacobs@Sun.COM
+
+ $Id$
+-->
+
+<service_bundle type='manifest' name='SUNWcups:services'>
+
+<service
+ name='application/cups/scheduler'
+ type='service'
+ version='1'>
+
+ <dependency
+ name='filesystem_minimal'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <dependency
+ name='loopback'
+ grouping='optional_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/network/loopback' />
+ </dependency>
+
+
+ <dependency
+ name='network'
+ grouping='optional_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/milestone/network' />
+ </dependency>
+
+ <dependency
+ name='lpsched'
+ grouping='exclude_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/application/print/server' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='60' />
+
+ <instance name='default' enabled='false' >
+
+ <dependency
+ name='config_data'
+ grouping='require_all'
+ restart_on='none'
+ type='path'>
+ <service_fmri value='file://localhost@sysconfdir@/cups/cupsd.conf' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='@sbindir@/cupsd'
+ timeout_seconds='60' >
+ <method_context>
+ <method_credential user='root' group='@CUPS_GROUP@' />
+ </method_context>
+ </exec_method>
+
+ <property_group name='general' type='framework'>
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.cups' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.value.cups' />
+ </property_group>
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ CUPS Print Spooler
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='cupsd' section='8'
+ manpath='@mandir@' />
+ </documentation>
+ </template>
+
+ </instance>
+
+ <stability value='Stable' />
+
+</service>
+
+<service
+ name='application/cups/in-lpd'
+ type='service'
+ version='1'>
+
+ <dependency
+ name='filesystem_minimal'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <dependency
+ name='loopback'
+ grouping='require_any'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/network/loopback' />
+ </dependency>
+
+ <dependency
+ name='network'
+ grouping='optional_all'
+ restart_on='error'
+ type='service'>
+ <service_fmri value='svc:/milestone/network' />
+ </dependency>
+
+ <dependency
+ name='in-lpd'
+ grouping='exclude_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/application/print/rfc1179' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='60' />
+
+ <instance name='default' enabled='false' >
+ <restarter>
+ <service_fmri value='svc:/network/inetd:default' />
+ </restarter>
+
+ <dependency
+ name='cupsd'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/application/cups/scheduler' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='inetd_start'
+ exec='@CUPS_SERVERBIN@/daemon/cups-lpd -o document-format=application/octet-stream'
+ timeout_seconds='0'>
+ <method_context>
+ <method_credential user='@CUPS_USER@' group='@CUPS_GROUP@' />
+ </method_context>
+ </exec_method>
+
+ <property_group name='inetd' type='framework'>
+ <stability value='Evolving' />
+ <propval name='endpoint_type' type='astring' value='stream' />
+ <propval name='name' type='astring' value='printer' />
+ <propval name='wait' type='boolean' value='false' />
+ <propval name='isrpc' type='boolean' value='false' />
+ <propval name='proto' type='astring' value='tcp6' />
+ </property_group>
+
+ <property_group name='general' type='framework'>
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.cups' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.value.cups' />
+ </property_group>
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ CUPS Line Printer Daemon mini-server
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='cups-lpd' section='8'
+ manpath='@mandir@' />
+ </documentation>
+ </template>
+
+ </instance>
+
+ <stability value='Stable' />
+
+</service>
+
+</service_bundle>
.\"
.\" Backend man page for the Common UNIX Printing System (CUPS).
.\"
-.\" Copyright 2007 by Apple Inc.
+.\" Copyright 2007-2008 by Apple Inc.
.\" Copyright 1997-2006 by Easy Software Products.
.\"
.\" These coded instructions, statements, and computer programs are the
.\" which should have been included with this file. If this file is
.\" file is missing or damaged, see the license at "http://www.cups.org/".
.\"
-.TH backend 7 "Common UNIX Printing System" "20 March 2006" "Apple Inc."
+.TH backend 7 "Common UNIX Printing System" "28 July 2008" "Apple Inc."
.SH NAME
backend \- cups backend transmission interfaces
device-class scheme "Unknown" "device-info"
device-class device-uri "device-make-and-model" "device-info"
device-class device-uri "device-make-and-model" "device-info" "device-id"
+ device-class device-uri "device-make-and-model" "device-info" "device-id" "device-location"
.fi
.LP
ID string for the device, which is used to select a matching
driver.
+.LP
+The optional \fIdevice-location\fR field specifies the physical location of
+the device, which is often used to pre-populate the printer-location attribute
+when adding a printer.
+
.SH PERMISSIONS
Backends without world execute permissions are run as the root
user. Otherwise, the backend is run using the unprivileged user
http://localhost:631/help
.SH COPYRIGHT
-Copyright 2007 by Apple Inc.
+Copyright 2007-2008 by Apple Inc.
.\"
.\" End of "$Id: backend.man 7600 2008-05-20 21:06:23Z mike $".
.\"
.br
Specifies the maximum interval between printer information broadcasts.
.TP 5
+BrowseLDAPBindDN
+.br
+Specifies the LDAP domain name to use when registering printers.
+.TP 5
+BrowseLDAPCACertFile
+.br
+Specifies the SSL certificate authority file to use.
+.TP 5
+BrowseLDAPDN
+.br
+Specifies the LDAP domain name to use when discovering printers.
+.TP 5
+BrowseLDAPPassword
+.br
+Specifies the password to use when accessing the LDAP server.
+.TP 5
+BrowseLDAPServer
+.br
+Specifies the LDAP server to use.
+.TP 5
BrowseOrder allow,deny
.TP 5
BrowseOrder deny,allow
-chgrp $(CUPS_GROUP) $(CACHEDIR)/rss
if test "x$(SYMROOT)" != "x"; then \
$(INSTALL_DIR) $(SYMROOT); \
- for file in $(TARGETS); do \
- cp $$file $(SYMROOT); \
- done \
+ cp mailto rss $(SYMROOT); \
fi
install-exec:
$(INSTALL_DIR) -m 755 $(SERVERBIN)/notifier
- for file in $(TARGETS); do \
- $(INSTALL_BIN) $$file $(SERVERBIN)/notifier; \
- done
+ $(INSTALL_BIN) mailto $(SERVERBIN)/notifier
+ $(INSTALL_BIN) rss $(SERVERBIN)/notifier
#
$(CC) $(LDFLAGS) -o cupsd $(CUPSDOBJS) -L. -lcupsmime \
$(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \
$(LIBPAPER) $(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBS) \
- $(LIBGSSAPI)
+ $(LIBGSSAPI) $(LIBWRAP)
cupsd-static: $(CUPSDOBJS) libcupsmime.a ../cups/libcups.a
echo Linking $@...
$(CC) $(LDFLAGS) -o cupsd-static $(CUPSDOBJS) libcupsmime.a \
$(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \
../cups/libcups.a $(COMMONLIBS) $(LIBZ) $(LIBPAPER) \
- $(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBGSSAPI)
+ $(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBGSSAPI) \
+ $(LIBWRAP)
#
# include <gnutls/x509.h>
#endif /* HAVE_GNUTLS */
+#ifdef HAVE_TCPD_H
+# include <tcpd.h>
+#endif /* HAVE_TCPD_H */
+
/*
* Local functions...
char *hostname; /* Hostname for address */
http_addr_t temp; /* Temporary address variable */
static time_t last_dos = 0; /* Time of last DoS attack */
+#ifdef HAVE_TCPD_H
+ struct request_info wrap_req; /* TCP wrappers request information */
+#endif /* HAVE_TCPD_H */
cupsdLogMessage(CUPSD_LOG_DEBUG2,
cupsdLogMessage(CUPSD_LOG_WARN,
"Possible DoS attack - more than %d clients connecting "
"from %s!",
- MaxClientsPerHost, con->http.hostname);
+ MaxClientsPerHost,
+ httpAddrString(con->http.hostaddr, con->http.hostname,
+ sizeof(con->http.hostname)));
}
#ifdef WIN32
* Do double lookups as needed...
*/
- if ((addrlist = httpAddrGetList(con->http.hostname, AF_UNSPEC, NULL)) != NULL)
+ if ((addrlist = httpAddrGetList(con->http.hostname, AF_UNSPEC, NULL))
+ != NULL)
{
/*
* See if the hostname maps to the same IP address...
}
}
+#ifdef HAVE_TCPD_H
+ /*
+ * See if the connection is denied by TCP wrappers...
+ */
+
+ request_init(&wrap_req, RQ_DAEMON, "cupsd", RQ_FILE, con->http.fd, NULL);
+ fromhost(&wrap_req);
+
+ if (!hosts_access(&wrap_req))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdAcceptClient: Closing connection %d...",
+ con->http.fd);
+
+#ifdef WIN32
+ closesocket(con->http.fd);
+#else
+ close(con->http.fd);
+#endif /* WIN32 */
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Connection from %s refused by /etc/hosts.allow and "
+ "/etc/hosts.deny rules.", con->http.hostname);
+ free(con);
+ return;
+ }
+#endif /* HAVE_TCPD_H */
+
#ifdef AF_INET6
if (con->http.hostaddr->addr.sa_family == AF_INET6)
cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s:%d (IPv6)",
typedef struct
{
char device_class[128], /* Device class */
- device_make_and_model[128], /* Make and model, if known */
device_info[128], /* Device info/description */
- device_uri[1024], /* Device URI */
- device_id[1024]; /* 1284 Device ID */
+ device_uri[1024]; /* Device URI */
} cupsd_device_t;
send_make_and_model,
/* Send device-make-and-model attribute? */
send_uri, /* Send device-uri attribute? */
- send_id; /* Send device-id attribute? */
+ send_id, /* Send device-id attribute? */
+ send_location; /* Send device-location attribute? */
static int dead_children = 0;
/* Dead children? */
const char *device_make_and_model,
const char *device_info,
const char *device_uri,
- const char *device_id);
+ const char *device_id,
+ const char *device_location);
static int compare_devices(cupsd_device_t *p0,
cupsd_device_t *p1);
static cups_array_t *create_strings_array(const char *s);
num_options, options));
if (!requested || cupsArrayFind(requested, "all") != NULL)
- send_class = send_info = send_make_and_model = send_uri = send_id = 1;
+ {
+ send_class = send_info = send_make_and_model = send_uri = send_id =
+ send_location = 1;
+ }
else
{
send_class = cupsArrayFind(requested, "device-class") != NULL;
send_make_and_model = cupsArrayFind(requested, "device-make-and-model") != NULL;
send_uri = cupsArrayFind(requested, "device-uri") != NULL;
send_id = cupsArrayFind(requested, "device-id") != NULL;
+ send_location = cupsArrayFind(requested, "device-location") != NULL;
}
/*
const char *device_make_and_model, /* I - Device make and model */
const char *device_info, /* I - Device information */
const char *device_uri, /* I - Device URI */
- const char *device_id) /* I - 1284 device ID */
+ const char *device_id, /* I - 1284 device ID */
+ const char *device_location) /* I - Physical location */
{
cupsd_device_t *device; /* New device */
*/
strlcpy(device->device_class, device_class, sizeof(device->device_class));
- strlcpy(device->device_make_and_model, device_make_and_model,
- sizeof(device->device_make_and_model));
strlcpy(device->device_info, device_info, sizeof(device->device_info));
strlcpy(device->device_uri, device_uri, sizeof(device->device_uri));
- strlcpy(device->device_id, device_id, sizeof(device->device_id));
/*
* Add the device to the array and return...
cupsdSendIPPGroup(IPP_TAG_PRINTER);
if (send_class)
cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class",
- device->device_class);
+ device_class);
if (send_info)
- cupsdSendIPPString(IPP_TAG_TEXT, "device-info", device->device_info);
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-info", device_info);
if (send_make_and_model)
cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model",
- device->device_make_and_model);
+ device_make_and_model);
if (send_uri)
- cupsdSendIPPString(IPP_TAG_URI, "device-uri", device->device_uri);
+ cupsdSendIPPString(IPP_TAG_URI, "device-uri", device_uri);
if (send_id)
- cupsdSendIPPString(IPP_TAG_TEXT, "device-id", device->device_id);
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-id",
+ device_id ? device_id : "");
+ if (send_location)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-location",
+ device_location ? device_location : "");
fflush(stdout);
fputs("DEBUG: Flushed attributes...\n", stderr);
get_device(cupsd_backend_t *backend) /* I - Backend to read from */
{
char line[2048], /* Line from backend */
- dclass[64], /* Device class */
- uri[1024], /* Device URI */
- info[128], /* Device info */
- make_model[256], /* Make and model */
- device_id[1024]; /* 1284 device ID */
+ temp[2048], /* Copy of line */
+ *ptr, /* Pointer into line */
+ *dclass, /* Device class */
+ *uri, /* Device URI */
+ *make_model, /* Make and model */
+ *info, /* Device info */
+ *device_id, /* 1284 device ID */
+ *location; /* Physical location */
if (cupsFileGets(backend->pipe, line, sizeof(line)))
/*
* Each line is of the form:
*
- * class URI "make model" "name" ["1284 device ID"]
+ * class URI "make model" "name" ["1284 device ID"] ["location"]
+ */
+
+ strlcpy(temp, line, sizeof(temp));
+
+ /*
+ * device-class
+ */
+
+ dclass = temp;
+
+ for (ptr = temp; *ptr; ptr ++)
+ if (isspace(*ptr & 255))
+ break;
+
+ while (isspace(*ptr & 255))
+ *ptr++ = '\0';
+
+ /*
+ * device-uri
+ */
+
+ if (!*ptr)
+ goto error;
+
+ for (uri = ptr; *ptr; ptr ++)
+ if (isspace(*ptr & 255))
+ break;
+
+ while (isspace(*ptr & 255))
+ *ptr++ = '\0';
+
+ /*
+ * device-make-and-model
*/
- device_id[0] = '\0';
+ if (*ptr != '\"')
+ goto error;
- if (sscanf(line,
- "%63s%1023s%*[ \t]\"%255[^\"]\"%*[ \t]\"%127[^\"]\""
- "%*[ \t]\"%1023[^\"]",
- dclass, uri, make_model, info, device_id) < 4)
+ for (ptr ++, make_model = ptr; *ptr && *ptr != '\"'; ptr ++)
{
- /*
- * Bad format; strip trailing newline and write an error message.
- */
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
+ /*
+ * device-info
+ */
- if (line[strlen(line) - 1] == '\n')
- line[strlen(line) - 1] = '\0';
+ if (*ptr != '\"')
+ goto error;
- fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n",
- backend->name, line);
+ for (ptr ++, info = ptr; *ptr && *ptr != '\"'; ptr ++)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
}
- else
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
+ /*
+ * device-id
+ */
+
+ if (*ptr == '\"')
{
+ for (ptr ++, device_id = ptr; *ptr && *ptr != '\"'; ptr ++)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+
+ if (*ptr != '\"')
+ goto error;
+
+ for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
/*
- * Add the device to the array of available devices...
+ * device-location
*/
- if (!add_device(dclass, make_model, info, uri, device_id))
- fprintf(stderr, "DEBUG: [cups-deviced] Found device \"%s\"...\n", uri);
+ if (*ptr == '\"')
+ {
+ for (ptr ++, location = ptr; *ptr && *ptr != '\"'; ptr ++)
+ {
+ if (*ptr == '\\' && ptr[1])
+ _cups_strcpy(ptr, ptr + 1);
+ }
+
+ if (*ptr != '\"')
+ goto error;
+
+ *ptr = '\0';
+ }
+ else
+ location = NULL;
}
+ else
+ {
+ device_id = NULL;
+ location = NULL;
+ }
+
+ /*
+ * Add the device to the array of available devices...
+ */
+
+ if (!add_device(dclass, make_model, info, uri, device_id, location))
+ fprintf(stderr, "DEBUG: [cups-deviced] Found device \"%s\"...\n", uri);
return (0);
}
backend->pipe = NULL;
return (-1);
+
+ /*
+ * Bad format; strip trailing newline and write an error message.
+ */
+
+ error:
+
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
+ fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n",
+ backend->name, line);
+ return (0);
}
typedef struct /**** PPD record ****/
{
time_t mtime; /* Modification time */
- size_t size; /* Size in bytes */
+ off_t size; /* Size in bytes */
int model_number; /* cupsModelNumber */
int type; /* ppd-type */
char filename[512], /* Filename */
*
* Contents:
*
- * cupsdDeregisterPrinter() - Stop sending broadcast information for a local
- * printer and remove any pending references to
- * remote printers.
- * cupsdLoadRemoteCache() - Load the remote printer cache.
- * cupsdRegisterPrinter() - Start sending broadcast information for a
- * printer or update the broadcast contents.
- * cupsdRestartPolling() - Restart polling servers as needed.
- * cupsdSaveRemoteCache() - Save the remote printer cache.
- * cupsdSendBrowseList() - Send new browsing information as necessary.
- * cupsdStartBrowsing() - Start sending and receiving broadcast
- * information.
- * cupsdStartPolling() - Start polling servers as needed.
- * cupsdStopBrowsing() - Stop sending and receiving broadcast
- * information.
- * cupsdStopPolling() - Stop polling servers as needed.
- * cupsdUpdateDNSSDName() - Update the computer name we use for
- * browsing...
- * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
- * cupsdUpdateSLPBrowse() - Get browsing information via SLP.
- * dequote() - Remote quotes from a string.
- * dnssdBuildTxtRecord() - Build a TXT record from printer info.
- * dnssdComparePrinters() - Compare the registered names of two printers.
- * dnssdDeregisterPrinter() - Stop sending broadcast information for a
- * printer.
- * dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT
- * record format.
- * dnssdRegisterCallback() - DNSServiceRegister callback.
- * dnssdRegisterPrinter() - Start sending broadcast information for a
- * printer or update the broadcast contents.
- * dnssdUpdate() - Handle DNS-SD queries.
- * get_hostconfig() - Get an /etc/hostconfig service setting.
- * is_local_queue() - Determine whether the URI points at a local
- * queue.
- * process_browse_data() - Process new browse data.
- * process_implicit_classes() - Create/update implicit classes as needed.
- * send_cups_browse() - Send new browsing information using the CUPS
- * protocol.
- * send_ldap_browse() - Send LDAP printer registrations.
- * send_slp_browse() - Register the specified printer with SLP.
- * slp_attr_callback() - SLP attribute callback
- * slp_dereg_printer() - SLPDereg() the specified printer
- * slp_get_attr() - Get an attribute from an SLP registration.
- * slp_reg_callback() - Empty SLPRegReport.
- * slp_url_callback() - SLP service url callback
- * update_cups_browse() - Update the browse lists using the CUPS
- * protocol.
- * update_lpd() - Update the LPD configuration as needed.
- * update_polling() - Read status messages from the poll daemons.
- * update_smb() - Update the SMB configuration as needed.
*/
/*
static void process_implicit_classes(void);
static void send_cups_browse(cupsd_printer_t *p);
#ifdef HAVE_LDAP
+static LDAP *ldap_connect(void);
+static void ldap_reconnect(void);
+static void ldap_disconnect(LDAP *ld);
+static int ldap_search_rec(LDAP *ld, char *base, int scope,
+ char *filter, char *attrs[],
+ int attrsonly, LDAPMessage **res);
+static int ldap_getval_firststring(LDAP *ld, LDAPMessage *entry,
+ char *attr, char *retval,
+ unsigned long maxsize);
+static void ldap_freeres(LDAPMessage *entry);
+static void send_ldap_ou(char *ou, char *basedn, char *descstring);
static void send_ldap_browse(cupsd_printer_t *p);
+static void ldap_dereg_printer(cupsd_printer_t *p);
+static void ldap_dereg_ou(char *ou, char *basedn);
+# ifdef HAVE_LDAP_REBIND_PROC
+# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+static int ldap_rebind_proc(LDAP *RebindLDAPHandle,
+ LDAP_CONST char *refsp,
+ ber_tag_t request,
+ ber_int_t msgid,
+ void *params);
+# else
+static int ldap_rebind_proc(LDAP *RebindLDAPHandle,
+ char **dnp,
+ char **passwdp,
+ int *authmethodp,
+ int freeit,
+ void *arg);
+# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+# endif /* HAVE_LDAP_REBIND_PROC */
#endif /* HAVE_LDAP */
#ifdef HAVE_LIBSLP
static void send_slp_browse(cupsd_printer_t *p);
static void dnssdUpdate(void);
#endif /* HAVE_DNSSD */
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
{
"printerDescription",
"printerURI",
NULL
};
-#endif /* HAVE_OPENLDAP */
+#endif /* HAVE_LDAP */
#ifdef HAVE_LIBSLP
/*
slp_dereg_printer(p);
#endif /* HAVE_LIBSLP */
+#ifdef HAVE_LDAP
+ if (BrowseLocalProtocols & BROWSE_LDAP)
+ ldap_dereg_printer(p);
+#endif /* HAVE_LDAP */
+
#ifdef HAVE_DNSSD
if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
dnssdDeregisterPrinter(p);
}
+#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.
*/
BrowseSLPHandle = NULL;
#endif /* HAVE_LIBSLP */
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
{
if (!BrowseLDAPDN)
}
else
{
- /*
- * Open LDAP handle...
- */
-
- int rc; /* LDAP API status */
- int version = 3; /* LDAP version */
- struct berval bv = {0, ""}; /* SASL bind value */
-
-
- /*
- * Set the certificate file to use for encrypted LDAP sessions...
- */
-
- if (BrowseLDAPCACertFile)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "cupsdStartBrowsing: Setting CA certificate file \"%s\"",
- BrowseLDAPCACertFile);
-
- if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
- (void *)BrowseLDAPCACertFile))
- != LDAP_SUCCESS)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to set CA certificate file for LDAP "
- "connections: %d - %s", rc, ldap_err2string(rc));
- }
-
- /*
- * LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
- */
-
- if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
- rc = ldap_initialize(&BrowseLDAPHandle, "ldapi:///");
- else
- rc = ldap_initialize(&BrowseLDAPHandle, BrowseLDAPServer);
-
- if (rc != LDAP_SUCCESS)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to initialize LDAP; disabling LDAP browsing!");
- BrowseLocalProtocols &= ~BROWSE_LDAP;
- BrowseRemoteProtocols &= ~BROWSE_LDAP;
- }
- else if (ldap_set_option(BrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
- (const void *)&version) != LDAP_SUCCESS)
- {
- ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
- BrowseLDAPHandle = NULL;
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to set LDAP protocol version; "
- "disabling LDAP browsing!");
- BrowseLocalProtocols &= ~BROWSE_LDAP;
- BrowseRemoteProtocols &= ~BROWSE_LDAP;
- }
- else
- {
- if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
- rc = ldap_sasl_bind_s(BrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
- NULL, NULL);
- else
- rc = ldap_bind_s(BrowseLDAPHandle, BrowseLDAPBindDN,
- BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
-
- if (rc != LDAP_SUCCESS)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to bind to LDAP server; "
- "disabling LDAP browsing!");
- ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
- BrowseLocalProtocols &= ~BROWSE_LDAP;
- BrowseRemoteProtocols &= ~BROWSE_LDAP;
- }
- }
+ /* Open LDAP handle... */
+ BrowseLDAPHandle = ldap_connect();
}
BrowseLDAPRefresh = 0;
}
-#endif /* HAVE_OPENLDAP */
+#endif /* HAVE_LDAP */
/*
* Enable LPD and SMB printer sharing as needed through external programs...
}
#endif /* HAVE_LIBSLP */
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
BrowseLDAPHandle)
{
- ldap_unbind(BrowseLDAPHandle);
+ ldap_dereg_ou(ServerName, BrowseLDAPDN);
+ ldap_disconnect(BrowseLDAPHandle);
BrowseLDAPHandle = NULL;
}
#endif /* HAVE_OPENLDAP */
#endif /* HAVE_DNSSD */
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
/*
* 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
*/
location[1024], /* Printer location */
info[1024], /* Printer information */
make_model[1024], /* Printer make and model */
- **value; /* Holds the returned data from LDAP */
+ 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 */
-
- /*
- * Search for printers...
- */
-
cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
BrowseLDAPRefresh = time(NULL) + BrowseInterval;
- rc = ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
- "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
- if (rc != LDAP_SUCCESS)
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (! BrowseLDAPHandle)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LDAP search returned error %d: %s", rc,
- ldap_err2string(rc));
+ 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...
* Get the required values from this entry...
*/
- if ((value = ldap_get_values(BrowseLDAPHandle, e,
- "printerDescription")) == NULL)
+ if (ldap_getval_firststring(BrowseLDAPHandle, e,
+ "printerDescription", info, sizeof(info)) == -1)
continue;
- strlcpy(info, *value, sizeof(info));
- ldap_value_free(value);
-
- if ((value = ldap_get_values(BrowseLDAPHandle, e,
- "printerLocation")) == NULL)
+ if (ldap_getval_firststring(BrowseLDAPHandle, e,
+ "printerLocation", location, sizeof(location)) == -1)
continue;
- strlcpy(location, *value, sizeof(location));
- ldap_value_free(value);
-
- if ((value = ldap_get_values(BrowseLDAPHandle, e,
- "printerMakeAndModel")) == NULL)
+ if (ldap_getval_firststring(BrowseLDAPHandle, e,
+ "printerMakeAndModel", make_model, sizeof(make_model)) == -1)
continue;
- strlcpy(make_model, *value, sizeof(make_model));
- ldap_value_free(value);
-
- if ((value = ldap_get_values(BrowseLDAPHandle, e,
- "printerType")) == NULL)
+ if (ldap_getval_firststring(BrowseLDAPHandle, e,
+ "printerType", type_num, sizeof(type_num)) == -1)
continue;
- type = atoi(*value);
- ldap_value_free(value);
+ type = atoi(type_num);
- if ((value = ldap_get_values(BrowseLDAPHandle, e,
- "printerURI")) == NULL)
+ if (ldap_getval_firststring(BrowseLDAPHandle, e,
+ "printerURI", uri, sizeof(uri)) == -1)
continue;
- strlcpy(uri, *value, sizeof(uri));
- ldap_value_free(value);
-
/*
* Process the entry as browse data...
*/
location, info, make_model, 0, NULL);
}
+
+ ldap_freeres(res);
}
-#endif /* HAVE_OPENLDAP */
+#endif /* HAVE_LDAP */
#ifdef HAVE_LIBSLP
}
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
+/*
+ * 'ldap_search_rec()' - LDAP Search with reconnect
+ */
+
+static int
+ldap_search_rec(LDAP *ld, /* I - LDAP handler */
+ char *base, /* I - Base dn */
+ int scope, /* I - LDAP search scope */
+ char *filter, /* I - Filter string */
+ char *attrs[], /* I - Requested attributes */
+ int attrsonly, /* I - Return only attributes? */
+ LDAPMessage **res) /* I - LDAP handler */
+{
+ int rc; /* Return code */
+
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL, NULL,
+ NULL, LDAP_NO_LIMIT, res);
+# else
+ rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res);
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+
+ /*
+ * If we have a connection problem try again...
+ */
+
+ if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP search failed with status %d: %s",
+ rc, ldap_err2string(rc));
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "We try the LDAP search once again after reconnecting to "
+ "the server");
+ ldap_freeres(*res);
+ ldap_reconnect();
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL,
+ NULL, NULL, LDAP_NO_LIMIT, res);
+# else
+ rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res);
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ }
+
+ if (rc == LDAP_NO_SUCH_OBJECT)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "ldap_search_rec: LDAP entry/object not found");
+ else if (rc != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "ldap_search_rec: LDAP search failed with status %d: %s",
+ rc, ldap_err2string(rc));
+
+ if (rc != LDAP_SUCCESS)
+ ldap_freeres(*res);
+
+ return (rc);
+}
+
+
+/*
+ * 'ldap_freeres()' - Free LDAPMessage
+ */
+
+static void
+ldap_freeres(LDAPMessage *entry) /* I - LDAP handler */
+{
+ int rc; /* Return value */
+
+
+ rc = ldap_msgfree(entry);
+ if (rc == -1)
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Can't free LDAPMessage!");
+ else if (rc == 0)
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "Freeing LDAPMessage was unnecessary");
+}
+
+
+/*
+ * 'ldap_getval_char()' - Get first LDAP value and convert to string
+ */
+
+static int
+ldap_getval_firststring(
+ LDAP *ld, /* I - LDAP handler */
+ LDAPMessage *entry, /* I - LDAP message or search result */
+ char *attr, /* I - the wanted attribute */
+ char *retval, /* O - String to return */
+ unsigned long maxsize) /* I - Max string size */
+{
+ char *dn; /* LDAP DN */
+ int rc = 0; /* Return code */
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ struct berval **bval; /* LDAP value array */
+ unsigned long size; /* String size */
+
+
+ /*
+ * Get value from LDAPMessage...
+ */
+
+ if ((bval = ldap_get_values_len(ld, entry, attr)) == NULL)
+ {
+ rc = -1;
+ dn = ldap_get_dn(ld, entry);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Failed to get LDAP value %s for %s!",
+ attr, dn);
+ ldap_memfree(dn);
+ }
+ else
+ {
+
+ /*
+ * Check size and copy value into our string...
+ */
+
+ size = maxsize;
+ if (size < bval[0]->bv_len)
+ {
+ rc = -1;
+ dn = ldap_get_dn(ld, entry);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Attribute %s is too big! (dn: %s)",
+ attr, dn);
+ ldap_memfree(dn);
+ }
+ else
+ size = bval[0]->bv_len;
+
+ strlcpy(retval, bval[0]->bv_val, size);
+ ldap_value_free_len(bval);
+ }
+# else
+ char **value; /* LDAP value */
+
+ /*
+ * Get value from LDAPMessage...
+ */
+
+ if ((value = (char **)ldap_get_values(ld, entry, attr)) == NULL)
+ {
+ rc = -1;
+ dn = ldap_get_dn(ld, entry);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Failed to get LDAP value %s for %s!",
+ attr, dn);
+ ldap_memfree(dn);
+ }
+ else
+ {
+ strlcpy(retval, *value, maxsize);
+ ldap_value_free(value);
+ }
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+
+ return (rc);
+}
+
+
+/*
+ * 'send_ldap_ou()' - Send LDAP ou registrations.
+ */
+
+static void
+send_ldap_ou(char *ou, /* I - Servername/ou to register */
+ char *basedn, /* I - Our base dn */
+ char *descstring) /* I - Description for ou */
+{
+ int i; /* Looping var... */
+ LDAPMod mods[3]; /* The 3 attributes we will be adding */
+ LDAPMod *pmods[4]; /* Pointers to the 3 attributes + NULL */
+ LDAPMessage *res, /* Search result token */
+ *e; /* Current entry from search */
+ int rc; /* LDAP status */
+ char dn[1024], /* DN of the organizational unit we are adding */
+ *desc[2], /* Change records */
+ *ou_value[2];
+ char old_desc[1024]; /* Old description */
+ static const char * const objectClass_values[] =
+ { /* The 2 objectClass's we use in */
+ "top", /* our LDAP entries */
+ "organizationalUnit",
+ NULL
+ };
+ static const char * const ou_attrs[] =/* CUPS LDAP attributes */
+ {
+ "description",
+ NULL
+ };
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: %s", ou);
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (! BrowseLDAPHandle)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: LDAP Handle is invalid. Try "
+ "reconnecting...");
+ ldap_reconnect();
+ return;
+ }
+
+ /*
+ * Prepare ldap search...
+ */
+
+ snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: dn=\"%s\"", dn);
+
+ ou_value[0] = ou;
+ ou_value[1] = NULL;
+ desc[0] = descstring;
+ desc[1] = NULL;
+
+ mods[0].mod_type = "ou";
+ mods[0].mod_values = ou_value;
+ mods[1].mod_type = "description";
+ mods[1].mod_values = desc;
+ mods[2].mod_type = "objectClass";
+ mods[2].mod_values = (char **)objectClass_values;
+
+ rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
+ (char **)ou_attrs, 0, &res);
+
+ /*
+ * If ldap search was not successfull then exit function...
+ */
+
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
+ return;
+
+ /*
+ * Check if we need to insert or update the LDAP entry...
+ */
+
+ if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
+ rc != LDAP_NO_SUCH_OBJECT)
+ {
+ /*
+ * Printserver has already been registered, check if
+ * modification is required...
+ */
+
+ e = ldap_first_entry(BrowseLDAPHandle, res);
+
+ /*
+ * Get the required values from this entry...
+ */
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "description", old_desc,
+ sizeof(old_desc)) == -1)
+ old_desc[0] = '\0';
+
+ /*
+ * Check if modification is required...
+ */
+
+ if ( strcmp(desc[0], old_desc) == 0 )
+ {
+ /*
+ * LDAP entry for the printer exists.
+ * Printer has already been registered,
+ * no modifications required...
+ */
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: No updates required for %s", ou);
+ }
+ else
+ {
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: Replace entry for %s", ou);
+
+ for (i = 0; i < 3; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_REPLACE;
+ }
+ pmods[i] = NULL;
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP modify for %s failed with status %d: %s",
+ ou, rc, ldap_err2string(rc));
+ if ( LDAP_SERVER_DOWN == rc )
+ ldap_reconnect();
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Printserver has never been registered,
+ * add registration...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: Add entry for %s", ou);
+
+ for (i = 0; i < 3; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_ADD;
+ }
+ pmods[i] = NULL;
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP add for %s failed with status %d: %s",
+ ou, rc, ldap_err2string(rc));
+ if ( LDAP_SERVER_DOWN == rc )
+ ldap_reconnect();
+ }
+ }
+
+ ldap_freeres(res);
+}
+
+
/*
* 'send_ldap_browse()' - Send LDAP printer registrations.
*/
int i; /* Looping var... */
LDAPMod mods[7]; /* The 7 attributes we will be adding */
LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
- LDAPMessage *res; /* Search result token */
+ LDAPMessage *res, /* Search result token */
+ *e; /* Current entry from search */
char *cn_value[2], /* Change records */
*uri[2],
*info[2],
*make_model[2],
*type[2],
typestring[255], /* String to hold printer-type */
- filter[256], /* Search filter for possible UPDATEs */
dn[1024]; /* DN of the printer we are adding */
int rc; /* LDAP status */
+ char old_uri[HTTP_MAX_URI], /* Printer URI */
+ old_location[1024], /* Printer location */
+ old_info[1024], /* Printer information */
+ old_make_model[1024], /* Printer make and model */
+ old_type_string[30]; /* Temporary type number */
+ int old_type; /* Printer type */
static const char * const objectClass_values[] =
{ /* The 3 objectClass's we use in */
"top", /* our LDAP entries */
NULL
};
+
cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s", p->name);
+ /*
+ * Exit function if LDAP updates has been disabled...
+ */
+
+ if (!BrowseLDAPUpdate)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: Updates temporary disabled; "
+ "skipping...");
+ return;
+ }
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (!BrowseLDAPHandle)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: LDAP Handle is invalid. Try "
+ "reconnecting...");
+ ldap_reconnect();
+ return;
+ }
+
/*
* Everything in ldap is ** so we fudge around it...
*/
uri[0] = p->uri;
uri[1] = NULL;
- snprintf(filter, sizeof(filter),
- "(&(objectclass=cupsPrinter)(printerURI=%s))", p->uri);
+ /*
+ * Get ldap entry for printer ...
+ */
- ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
- filter, (char **)ldap_attrs, 0, &res);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: Searching \"%s\"",
- filter);
+ snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
+ BrowseLDAPDN);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
- mods[0].mod_type = "cn";
+ rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
+ (char **)ldap_attrs, 0, &res);
+
+ /*
+ * If ldap search was not successfull then exit function
+ * and temporary disable LDAP updates...
+ */
+
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
+ {
+ if (BrowseLDAPUpdate &&
+ (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
+ {
+ BrowseLDAPUpdate = FALSE;
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "LDAP update temporary disabled");
+ }
+
+ return;
+ }
+
+ /*
+ * Fill modification array...
+ */
+
+ mods[0].mod_type = "cn";
mods[0].mod_values = cn_value;
- mods[1].mod_type = "printerDescription";
+ mods[1].mod_type = "printerDescription";
mods[1].mod_values = info;
- mods[2].mod_type = "printerURI";
+ mods[2].mod_type = "printerURI";
mods[2].mod_values = uri;
- mods[3].mod_type = "printerLocation";
+ mods[3].mod_type = "printerLocation";
mods[3].mod_values = location;
- mods[4].mod_type = "printerMakeAndModel";
+ mods[4].mod_type = "printerMakeAndModel";
mods[4].mod_values = make_model;
- mods[5].mod_type = "printerType";
+ mods[5].mod_type = "printerType";
mods[5].mod_values = type;
- mods[6].mod_type = "objectClass";
+ mods[6].mod_type = "objectClass";
mods[6].mod_values = (char **)objectClass_values;
- snprintf(dn, sizeof(dn), "cn=%s,ou=printers,%s", p->name, BrowseLDAPDN);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
+ /*
+ * Check if we need to insert or update the LDAP entry...
+ */
- if (ldap_count_entries(BrowseLDAPHandle, res) > 0)
+ if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
+ rc != LDAP_NO_SUCH_OBJECT)
{
/*
- * Printer has already been registered, modify the current
- * registration...
+ * Printer has already been registered, check if
+ * modification is required...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "send_ldap_browse: Replacing entry...");
+ e = ldap_first_entry(BrowseLDAPHandle, res);
- for (i = 0; i < 7; i ++)
+ /*
+ * Get the required values from this entry...
+ */
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerDescription",
+ old_info, sizeof(old_info)) == -1)
+ old_info[0] = '\0';
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerLocation",
+ old_location, sizeof(old_location)) == -1)
+ old_info[0] = '\0';
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerMakeAndModel",
+ old_make_model, sizeof(old_make_model)) == -1)
+ old_info[0] = '\0';
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerType",
+ old_type_string, sizeof(old_type_string)) == -1)
+ old_info[0] = '\0';
+
+ old_type = atoi(old_type_string);
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerURI", old_uri,
+ sizeof(old_uri)) == -1)
+ old_info[0] = '\0';
+
+ /*
+ * Check if modification is required...
+ */
+
+ if (!strcmp(info[0], old_info) && !strcmp(uri[0], old_uri) &&
+ !strcmp(location[0], old_location) &&
+ !strcmp(make_model[0], old_make_model) && p->type == old_type)
{
- pmods[i] = mods + i;
- pmods[i]->mod_op = LDAP_MOD_REPLACE;
+ /*
+ * LDAP entry for the printer exists. Printer has already been registered,
+ * no modifications required...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: No updates required for %s", p->name);
}
- pmods[i] = NULL;
+ else
+ {
+ /*
+ * LDAP entry for the printer exists. Printer has already been registered,
+ * modify the current registration...
+ */
- if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LDAP modify for %s failed with status %d: %s",
- p->name, rc, ldap_err2string(rc));
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: Replace entry for %s", p->name);
+
+ for (i = 0; i < 7; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_REPLACE;
+ }
+ pmods[i] = NULL;
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP modify for %s failed with status %d: %s",
+ p->name, rc, ldap_err2string(rc));
+ if (rc == LDAP_SERVER_DOWN)
+ ldap_reconnect();
+ }
+ }
}
else
{
/*
- * Printer has never been registered, add the current
- * registration...
+ * No LDAP entry exists for the printer. Printer has never been registered,
+ * add the current registration...
*/
+ send_ldap_ou(ServerName, BrowseLDAPDN, "CUPS Server");
+
cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "send_ldap_browse: Adding entry...");
+ "send_ldap_browse: Add entry for %s", p->name);
for (i = 0; i < 7; i ++)
{
}
pmods[i] = NULL;
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
cupsdLogMessage(CUPSD_LOG_ERROR,
"LDAP add for %s failed with status %d: %s",
p->name, rc, ldap_err2string(rc));
+ if (rc == LDAP_SERVER_DOWN)
+ ldap_reconnect();
+ }
}
+
+ ldap_freeres(res);
}
-#endif /* HAVE_OPENLDAP */
+
+
+/*
+ * 'ldap_dereg_printer()' - Delete printer from directory
+ */
+
+static void
+ldap_dereg_printer(cupsd_printer_t *p) /* I - Printer to deregister */
+{
+ char dn[1024]; /* DN of the printer */
+ int rc; /* LDAP status */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: Remove entry for %s",
+ p->name);
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (!BrowseLDAPHandle)
+ {
+ ldap_reconnect();
+ return;
+ }
+
+ /*
+ * Get dn for printer and delete LDAP entry...
+ */
+
+ snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
+ BrowseLDAPDN);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: dn=\"%s\"", dn);
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ p->name, rc, ldap_err2string(rc));
+
+ /*
+ * If we had a connection problem (connection timed out, etc.)
+ * we should reconnect and try again to delete the entry...
+ */
+
+ if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Retry deleting LDAP entry for %s after a reconnect...", p->name);
+ ldap_reconnect();
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ p->name, rc, ldap_err2string(rc));
+ }
+ }
+}
+
+
+static void
+ldap_dereg_ou(char *ou, /* I - Organizational unit (servername) */
+ char *basedn) /* I - Dase dn */
+{
+ char dn[1024]; /* DN of the printer */
+ int rc; /* LDAP status */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: Remove entry for %s", ou);
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (!BrowseLDAPHandle)
+ {
+ ldap_reconnect();
+ return;
+ }
+
+ /*
+ * Get dn for printer and delete LDAP entry...
+ */
+
+ snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: dn=\"%s\"", dn);
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ ou, rc, ldap_err2string(rc));
+
+ /*
+ * If we had a connection problem (connection timed out, etc.)
+ * we should reconnect and try again to delete the entry...
+ */
+
+ if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Retry deleting LDAP entry for %s after a reconnect...", ou);
+ ldap_reconnect();
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ ou, rc, ldap_err2string(rc));
+ }
+
+ }
+}
+#endif /* HAVE_LDAP */
#ifdef HAVE_LIBSLP
# include <slp.h>
#endif /* HAVE_LIBSLP */
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
# ifdef __sun
# include <lber.h>
# endif /* __sun */
# include <ldap.h>
-#endif /* HAVE_OPENLDAP */
+# ifdef HAVE_LDAP_SSL_H
+# include <ldap_ssl.h>
+# endif /* HAVE_LDAP_SSL_H */
+#endif /* HAVE_LDAP */
/*
* Browse protocols...
#endif /* HAVE_LIBSLP */
#ifdef HAVE_LDAP
-# ifdef HAVE_OPENLDAP
VAR LDAP *BrowseLDAPHandle VALUE(NULL);
/* Handle to LDAP server */
-# endif /* HAVE_OPENLDAP */
VAR time_t BrowseLDAPRefresh VALUE(0);
/* Next LDAP refresh time */
VAR char *BrowseLDAPBindDN VALUE(NULL),
/* LDAP login DN */
+ *BrowseLDAPCACertFile VALUE(NULL),
+ /* LDAP CA cert file */
*BrowseLDAPDN VALUE(NULL),
/* LDAP search DN */
*BrowseLDAPPassword VALUE(NULL),
/* LDAP login password */
- *BrowseLDAPServer VALUE(NULL),
+ *BrowseLDAPServer VALUE(NULL);
/* LDAP server to use */
- *BrowseLDAPCACertFile VALUE(NULL);
+VAR int BrowseLDAPUpdate VALUE(TRUE);
+ /* enables LDAP updates */
+# ifdef HAVE_LDAP_SSL
+VAR char *BrowseLDAPCACertFile VALUE(NULL);
/* LDAP CA CERT file to use */
+# endif /* HAVE_LDAP_SSL */
#endif /* HAVE_LDAP */
VAR char *LPDConfigFile VALUE(NULL),
/* LPD configuration file */
"launchd_checkin: launch_msg(\"" LAUNCH_KEY_CHECKIN
"\") IPC failure");
exit(EXIT_FAILURE);
+ return; /* anti-compiler-warning */
}
if (launch_data_get_type(ld_resp) == LAUNCH_DATA_ERRNO)
cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_checkin: Check-in failed: %s",
strerror(errno));
exit(EXIT_FAILURE);
+ return; /* anti-compiler-warning */
}
/*
* Get the sockets dictionary...
*/
- if (!(ld_sockets = launch_data_dict_lookup(ld_resp, LAUNCH_JOBKEY_SOCKETS)))
+ if ((ld_sockets = launch_data_dict_lookup(ld_resp, LAUNCH_JOBKEY_SOCKETS))
+ == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"launchd_checkin: No sockets found to answer requests on!");
exit(EXIT_FAILURE);
+ return; /* anti-compiler-warning */
}
/*
* Get the array of listener sockets...
*/
- if (!(ld_array = launch_data_dict_lookup(ld_sockets, "Listeners")))
+ if ((ld_array = launch_data_dict_lookup(ld_sockets, "Listeners")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"launchd_checkin: No sockets found to answer requests on!");
exit(EXIT_FAILURE);
+ return; /* anti-compiler-warning */
}
/*
* Get the launchd file descriptor and address...
*/
- tmp = launch_data_array_get_index(ld_array, i);
- fd = launch_data_get_fd(tmp);
- addrlen = sizeof(addr);
-
- if (getsockname(fd, (struct sockaddr *)&addr, &addrlen))
+ if ((tmp = launch_data_array_get_index(ld_array, i)) != NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "launchd_checkin: Unable to get local address - %s",
- strerror(errno));
- continue;
- }
+ fd = launch_data_get_fd(tmp);
+ addrlen = sizeof(addr);
- /*
- * Try to match the launchd socket address to one of the listeners...
- */
+ if (getsockname(fd, (struct sockaddr *)&addr, &addrlen))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: Unable to get local address - %s",
+ strerror(errno));
+ continue;
+ }
- for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
- lis;
- lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
- if (httpAddrEqual(&lis->address, &addr))
- break;
+ /*
+ * Try to match the launchd socket address to one of the listeners...
+ */
- /*
- * Add a new listener If there's no match...
- */
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ if (httpAddrEqual(&lis->address, &addr))
+ break;
- if (lis)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "launchd_checkin: Matched existing listener %s with fd %d...",
- httpAddrString(&(lis->address), s, sizeof(s)), fd);
- }
- else
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "launchd_checkin: Adding new listener %s with fd %d...",
- httpAddrString(&addr, s, sizeof(s)), fd);
+ /*
+ * Add a new listener If there's no match...
+ */
- if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "launchd_checkin: Unable to allocate listener - %s.",
- strerror(errno));
- exit(EXIT_FAILURE);
- }
+ if (lis)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_checkin: Matched existing listener %s with fd %d...",
+ httpAddrString(&(lis->address), s, sizeof(s)), fd);
+ }
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "launchd_checkin: Adding new listener %s with fd %d...",
+ httpAddrString(&addr, s, sizeof(s)), fd);
- cupsArrayAdd(Listeners, lis);
+ if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "launchd_checkin: Unable to allocate listener - %s.",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
- memcpy(&lis->address, &addr, sizeof(lis->address));
- }
+ cupsArrayAdd(Listeners, lis);
- lis->fd = fd;
+ memcpy(&lis->address, &addr, sizeof(lis->address));
+ }
+
+ lis->fd = fd;
# ifdef HAVE_SSL
- portnum = 0;
+ portnum = 0;
# ifdef AF_INET6
- if (lis->address.addr.sa_family == AF_INET6)
- portnum = ntohs(lis->address.ipv6.sin6_port);
- else
+ if (lis->address.addr.sa_family == AF_INET6)
+ portnum = ntohs(lis->address.ipv6.sin6_port);
+ else
# endif /* AF_INET6 */
- if (lis->address.addr.sa_family == AF_INET)
- portnum = ntohs(lis->address.ipv4.sin_port);
+ if (lis->address.addr.sa_family == AF_INET)
+ portnum = ntohs(lis->address.ipv4.sin_port);
- if (portnum == 443)
- lis->encryption = HTTP_ENCRYPT_ALWAYS;
+ if (portnum == 443)
+ lis->encryption = HTTP_ENCRYPT_ALWAYS;
# endif /* HAVE_SSL */
+ }
}
}
* main() - Main entry for test program.
* check_basics() - Check for CR LF, mixed line endings, and blank
* lines.
+ * check_case() - Check that there are no duplicate groups, options,
+ * or choices that differ only by case.
* check_constraints() - Check UIConstraints in the PPD file.
* check_defaults() - Check default option keywords in the PPD file.
+ * check_duplex() - Check duplex keywords in the PPD file.
* check_filters() - Check filters in the PPD file.
* check_profiles() - Check ICC color profiles in the PPD file.
* check_translations() - Check translations in the PPD file.
WARN_FILTERS = 4,
WARN_PROFILES = 8,
WARN_TRANSLATIONS = 16,
- WARN_ALL = 31
+ WARN_DUPLEX = 32,
+ WARN_ALL = 63
};
static void check_basics(const char *filename);
static int check_constraints(ppd_file_t *ppd, int errors, int verbose,
int warn);
+static int check_case(ppd_file_t *ppd, int errors, int verbose);
static int check_defaults(ppd_file_t *ppd, int errors, int verbose,
int warn);
+static int check_duplex(ppd_file_t *ppd, int errors, int verbose,
+ int warn);
static int check_filters(ppd_file_t *ppd, const char *root, int errors,
int verbose, int warn);
static int check_profiles(ppd_file_t *ppd, const char *root, int errors,
warn |= WARN_CONSTRAINTS;
else if (!strcmp(argv[i], "defaults"))
warn |= WARN_DEFAULTS;
+ else if (!strcmp(argv[i], "duplex"))
+ warn |= WARN_DUPLEX;
else if (!strcmp(argv[i], "filters"))
warn |= WARN_FILTERS;
else if (!strcmp(argv[i], "profiles"))
}
}
- /*
- * Check for a duplex option, and for standard values...
- */
-
- if ((option = ppdFindOption(ppd, "Duplex")) == NULL)
- if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
- if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
- option = ppdFindOption(ppd, "KD03Duplex");
-
- if (option != NULL)
- {
- if (ppdFindChoice(option, "None") == NULL)
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
- _cupsLangPrintf(stdout,
- _(" **FAIL** REQUIRED %s does not define "
- "choice None!\n"
- " REF: Page 122, section 5.17\n"),
- option->keyword);
- }
-
- errors ++;
- }
-
- for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
- if (strcmp(choice->choice, "None") &&
- strcmp(choice->choice, "DuplexNoTumble") &&
- strcmp(choice->choice, "DuplexTumble") &&
- strcmp(choice->choice, "SimplexTumble"))
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
- _cupsLangPrintf(stdout,
- _(" **FAIL** Bad %s choice %s!\n"
- " REF: Page 122, section 5.17\n"),
- option->keyword, choice->choice);
- }
-
- errors ++;
- }
- }
-
if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) &&
strcmp(attr->name, "1284DeviceID"))
{
errors ++;
}
+ errors = check_case(ppd, errors, verbose);
+
if (!(warn & WARN_CONSTRAINTS))
errors = check_constraints(ppd, errors, verbose, 0);
if (!(warn & WARN_TRANSLATIONS))
errors = check_translations(ppd, errors, verbose, 0);
+ if (!(warn & WARN_DUPLEX))
+ errors = check_duplex(ppd, errors, verbose, 0);
+
if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
attr->value)
{
if (warn & WARN_TRANSLATIONS)
errors = check_translations(ppd, errors, verbose, 1);
+ if (warn & WARN_DUPLEX)
+ errors = check_duplex(ppd, errors, verbose, 1);
+
+ /*
+ * Look for legacy duplex keywords...
+ */
+
+ if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
+ if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
+ option = ppdFindOption(ppd, "KD03Duplex");
+
+ if (option)
+ _cupsLangPrintf(stdout,
+ _(" WARN Duplex option keyword %s may not "
+ "work as expected and should be named Duplex!\n"
+ " REF: Page 122, section 5.17\n"),
+ option->keyword);
+
/*
* Look for default keywords with no corresponding option...
*/
attr->name);
}
- /*
- * Check for old Duplex option names...
- */
-
- if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
- option = ppdFindOption(ppd, "KD03Duplex");
-
- if (option)
- {
- _cupsLangPrintf(stdout,
- _(" WARN Duplex option keyword %s "
- "should be named Duplex or JCLDuplex!\n"
- " REF: Page 122, section 5.17\n"),
- option->keyword);
- }
-
ppdMarkDefaults(ppd);
if (ppdConflicts(ppd))
{
}
+/*
+ * 'check_case()' - Check that there are no duplicate groups, options,
+ * or choices that differ only by case.
+ */
+
+static int /* O - Errors found */
+check_case(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose) /* I - Verbosity level */
+{
+ int i, j; /* Looping vars */
+ ppd_group_t *groupa, /* First group */
+ *groupb; /* Second group */
+ ppd_option_t *optiona, /* First option */
+ *optionb; /* Second option */
+ ppd_choice_t *choicea, /* First choice */
+ *choiceb; /* Second choice */
+
+
+ /*
+ * Check that the groups do not have any duplicate names...
+ */
+
+ for (i = ppd->num_groups, groupa = ppd->groups; i > 1; i --, groupa ++)
+ for (j = i - 1, groupb = groupa + 1; j > 0; j --, groupb ++)
+ if (!strcasecmp(groupa->name, groupb->name))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Group names %s and %s differ only "
+ "by case!\n"),
+ groupa->name, groupb->name);
+
+ errors ++;
+ }
+
+ /*
+ * Check that the options do not have any duplicate names...
+ */
+
+ for (optiona = ppdFirstOption(ppd); optiona; optiona = ppdNextOption(ppd))
+ {
+ cupsArraySave(ppd->options);
+ for (optionb = ppdNextOption(ppd); optionb; optionb = ppdNextOption(ppd))
+ if (!strcasecmp(optiona->keyword, optionb->keyword))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Option names %s and %s differ only "
+ "by case!\n"),
+ optiona->keyword, optionb->keyword);
+
+ errors ++;
+ }
+ cupsArrayRestore(ppd->options);
+
+ /*
+ * Then the choices...
+ */
+
+ for (i = optiona->num_choices, choicea = optiona->choices;
+ i > 1;
+ i --, choicea ++)
+ for (j = i - 1, choiceb = choicea + 1; j > 0; j --, choiceb ++)
+ if (!strcmp(choicea->choice, choiceb->choice))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Multiple occurrences of %s "
+ "choice name %s!\n"),
+ optiona->keyword, choicea->choice);
+
+ errors ++;
+
+ choicea ++;
+ i --;
+ break;
+ }
+ else if (!strcasecmp(choicea->choice, choiceb->choice))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** %s choice names %s and %s "
+ "differ only by case!\n"),
+ optiona->keyword, choicea->choice, choiceb->choice);
+
+ errors ++;
+ }
+ }
+
+ /*
+ * Return the number of errors found...
+ */
+
+ return (errors);
+}
+
+
/*
* 'check_defaults()' - Check default option keywords in the PPD file.
*/
}
+/*
+ * 'check_duplex()' - Check duplex keywords in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_duplex(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Error found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int i; /* Looping var */
+ ppd_option_t *option; /* PPD option */
+ ppd_choice_t *choice; /* Current choice */
+ const char *prefix; /* Message prefix */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ /*
+ * Check for a duplex option, and for standard values...
+ */
+
+ if ((option = ppdFindOption(ppd, "Duplex")) != NULL)
+ {
+ if (!ppdFindChoice(option, "None"))
+ {
+ if (verbose >= 0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s REQUIRED %s does not define "
+ "choice None!\n"
+ " REF: Page 122, section 5.17\n"),
+ prefix, option->keyword);
+ }
+
+ if (!warn)
+ errors ++;
+ }
+
+ for (i = option->num_choices, choice = option->choices;
+ i > 0;
+ i --, choice ++)
+ if (strcmp(choice->choice, "None") &&
+ strcmp(choice->choice, "DuplexNoTumble") &&
+ strcmp(choice->choice, "DuplexTumble") &&
+ strcmp(choice->choice, "SimplexTumble"))
+ {
+ if (verbose >= 0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Bad %s choice %s!\n"
+ " REF: Page 122, section 5.17\n"),
+ prefix, option->keyword, choice->choice);
+ }
+
+ if (!warn)
+ errors ++;
+ }
+ }
+
+ return (errors);
+}
+
+
/*
* 'check_filters()' - Check filters in the PPD file.
*/
if (!warn)
errors ++;
}
- else
+ else if (strcmp(program, "-"))
{
if (program[0] == '/')
snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
if (!warn)
errors ++;
}
- else
+ else if (strcmp(program, "-"))
{
if (program[0] == '/')
snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
ppd_cparam_t *cparam; /* Custom parameter */
char ll[3]; /* Base language */
const char *prefix; /* WARN/FAIL prefix */
+ const char *text; /* Pointer into UI text */
prefix = warn ? " WARN " : "**FAIL**";
for (j = 0; j < option->num_choices; j ++)
{
+ /*
+ * First see if this choice is a number; if so, don't require
+ * translation...
+ */
+
+ for (text = option->choices[j].text; *text; text ++)
+ if (!strchr("0123456789-+.", *text))
+ break;
+
+ if (!*text)
+ continue;
+
+ /*
+ * Check custom choices differently...
+ */
+
if (!strcasecmp(option->choices[j].choice, "Custom") &&
(coption = ppdFindCustomOption(ppd,
option->keyword)) != NULL)
"Options:\n"
"\n"
" -R root-directory Set alternate root\n"
- " -W {all,none,constraints,defaults,filters,translations}\n"
+ " -W {all,none,constraints,defaults,duplex,filters,"
+ "translations}\n"
" Issue warnings instead of errors\n"
" -q Run silently\n"
" -r Use 'relaxed' open mode\n"
static void device_cb(const char *device_clas, const char *device_id,
const char *device_info,
const char *device_make_and_model,
- const char *device_uri, void *user_data);
+ const char *device_uri, const char *device_location,
+ void *user_data);
static int show_devices(http_t *, int);
static int show_models(http_t *, int);
const char *device_info, /* I - device-info string */
const char *device_make_and_model, /* I - device-make-and-model string */
const char *device_uri, /* I - device-uri string */
+ const char *device_location, /* I - device-location string */
void *user_data) /* I - User data */
{
int *long_status; /* Show verbose info? */
" class = %s\n"
" info = %s\n"
" make-and-model = %s\n"
- " device-id = %s\n"),
+ " device-id = %s\n"
+ " location = %s\n"),
device_uri, device_class, device_info,
- device_make_and_model, device_id);
+ device_make_and_model, device_id, device_location);
}
else
_cupsLangPrintf(stdout, "%s %s\n", device_class, device_uri);
<TR>
<TH CLASS="label"{conflicted=1? CLASS="conflict":}><A NAME="{keyword}">{keytext}</A>:</TH>
-<TD><SELECT NAME="{keyword}">
+<TD><SELECT NAME="{keyword}" ID="select-{keyword}" ONCHANGE="update_paramtable('{keyword}')">
{[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
-</SELECT></TD>
+</SELECT>
+{iscustom=1?<TABLE NAME="paramtable" id="{keyword}-params">{[params]
+<TR><TH CLASS="sublabel">{paramtext}:</TH>
+<TD>{params=Units?<SELECT NAME="{keyword}.{params}">
+<OPTION VALUE="pt"{paramvalue=pt? SELECTED:}>Points</OPTION>
+<OPTION VALUE="mm"{paramvalue=mm? SELECTED:}>Millimeters</OPTION>
+<OPTION VALUE="cm"{paramvalue=cm? SELECTED:}>Centimeters</OPTION>
+<OPTION VALUE="in"{paramvalue=in? SELECTED:}>Inches</OPTION>
+<OPTION VALUE="ft"{paramvalue=ft? SELECTED:}>Feet</OPTION>
+<OPTION VALUE="m"{paramvalue=m? SELECTED:}>Meters</OPTION>
+</SELECT>:<INPUT TYPE="{inputtype}" NAME="{keyword}.{params}" VALUE="{paramvalue}">}</TD></TR>
+}</TABLE>
+</TD>:}
</TR>
<FORM METHOD="POST" ACTION="/admin">
<INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
<INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+
+<SCRIPT TYPE="text/javascript"><!--
+function update_paramtable(option)
+{
+ var cb = document.getElementById("select-" + option)
+ var paramstable = document.getElementById(option + "-params");
+ if (cb.value == "Custom")
+ paramstable.style.display = "table";
+ else
+ paramstable.style.display = "none";
+}
+--></SCRIPT>
+
+<SCRIPT TYPE="text/javascript"><!--
+// Hide custom options parameters for browsers that understand Javascript
+var paramtables = document.getElementsByName("paramtable");
+for (var i = 0; i < paramtables.length; i++)
+{
+ var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-"));
+ var cb = document.getElementById("select-" + opt);
+ if (cb.value != "Custom")
+ paramtables[i].style.display = "none";
+}
+--></SCRIPT>
</FORM>