From 749b1e90a80fd8245f9cb84d2f78ab65034eeb81 Mon Sep 17 00:00:00 2001 From: msweet Date: Wed, 30 Jul 2008 23:42:12 +0000 Subject: [PATCH] Merge changes from CUPS 1.4svn-r7817. git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@901 a1ca3aef-8c08-0410-bb20-df032aa958be --- CHANGES-1.3.txt | 1 + CHANGES.txt | 13 +- Makedefs.in | 2 + Makefile | 5 + backend/backend-private.h | 3 + backend/mdns.c | 14 +- backend/parallel.c | 12 +- backend/snmp.c | 344 ++--- backend/usb-darwin.c | 148 +-- backend/usb-libusb.c | 5 +- backend/usb-unix.c | 9 +- cgi-bin/admin.c | 498 ++++++- config-scripts/cups-common.m4 | 13 + config-scripts/cups-compiler.m4 | 1 + config-scripts/cups-directories.m4 | 11 +- config-scripts/cups-ldap.m4 | 26 +- config.h.in | 11 + configure.in | 2 +- cups/adminutil.c | 57 +- cups/backend.c | 72 +- cups/backend.h | 9 +- cups/cups.h | 3 +- cups/dest.c | 89 +- cups/getdevices.c | 18 +- cups/globals.h | 3 +- cups/langprintf.c | 8 +- cups/libcups.exp | 1 + cups/ppd.c | 39 +- cups/request.c | 67 +- cups/testppd.c | 7 + cups/util.c | 54 +- cups/versioning.h | 63 +- doc/cups.css | 6 + doc/help/kerberos.html | 134 +- doc/help/options.html | 70 - doc/help/ref-cupsd-conf.html.in | 14 + doc/help/spec-ipp.html | 45 +- doc/help/spec-ppd.html | 139 +- init/cups.xml.in | 212 +++ man/backend.man | 12 +- man/cupsd.conf.man.in | 20 + notifier/Makefile | 9 +- scheduler/Makefile | 5 +- scheduler/client.c | 42 +- scheduler/cups-deviced.c | 184 ++- scheduler/cups-driverd.cxx | 2 +- scheduler/dirsvc.c | 1364 +++++++++++++++++--- scheduler/dirsvc.h | 19 +- scheduler/main.c | 113 +- systemv/cupstestppd.c | 303 ++++- systemv/lpinfo.c | 9 +- templates/option-pickone.tmpl | 16 +- templates/set-printer-options-header.tmpl | 13 + templates/set-printer-options-trailer.tmpl | 11 + 54 files changed, 3285 insertions(+), 1065 deletions(-) create mode 100644 init/cups.xml.in diff --git a/CHANGES-1.3.txt b/CHANGES-1.3.txt index fca0738fa..ea573a924 100644 --- a/CHANGES-1.3.txt +++ b/CHANGES-1.3.txt @@ -3,6 +3,7 @@ CHANGES-1.3.txt 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) diff --git a/CHANGES.txt b/CHANGES.txt index f3f407183..8a1984e9a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,8 +1,19 @@ -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. diff --git a/Makedefs.in b/Makedefs.in index 0e5068553..b34c7ae0e 100644 --- a/Makedefs.in +++ b/Makedefs.in @@ -92,6 +92,7 @@ LIBSLP = @LIBSLP@ LIBGSSAPI = @LIBGSSAPI@ LIBTIFF = @LIBTIFF@ LIBUSB = @LIBUSB@ +LIBWRAP = @LIBWRAP@ LIBZ = @LIBZ@ # @@ -229,6 +230,7 @@ REQUESTS = $(BUILDROOT)@CUPS_REQUESTS@ SBINDIR = $(BUILDROOT)@sbindir@ SERVERBIN = $(BUILDROOT)@CUPS_SERVERBIN@ SERVERROOT = $(BUILDROOT)@CUPS_SERVERROOT@ +SMFMANIFESTDIR = @SMFMANIFESTDIR@ STATEDIR = $(BUILDROOT)@CUPS_STATEDIR@ XINETD = @XINETD@ diff --git a/Makefile b/Makefile index 9074d6731..017378db3 100644 --- a/Makefile +++ b/Makefile @@ -182,6 +182,11 @@ install-data: $(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; \ diff --git a/backend/backend-private.h b/backend/backend-private.h index b7912d59d..c124274a9 100644 --- a/backend/backend-private.h +++ b/backend/backend-private.h @@ -51,6 +51,9 @@ extern "C" { /* 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 diff --git a/backend/mdns.c b/backend/mdns.c index 4ae2c8121..419b12dc3 100644 --- a/backend/mdns.c +++ b/backend/mdns.c @@ -280,11 +280,8 @@ main(int argc, /* I - Number of command-line args */ 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; } @@ -305,11 +302,8 @@ main(int argc, /* I - Number of command-line args */ 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; } } diff --git a/backend/parallel.c b/backend/parallel.c index bba472095..e20499545 100644 --- a/backend/parallel.c +++ b/backend/parallel.c @@ -328,6 +328,7 @@ list_devices(void) 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 */ @@ -359,10 +360,15 @@ list_devices(void) 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); } diff --git a/backend/snmp.c b/backend/snmp.c index b7bafbf56..712981cfd 100644 --- a/backend/snmp.c +++ b/backend/snmp.c @@ -111,6 +111,16 @@ * 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 */ @@ -124,7 +134,9 @@ typedef struct snmp_cache_s /**** SNMP scan cache ****/ *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; @@ -174,14 +186,15 @@ static cups_array_t *Addresses = NULL; 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; @@ -660,15 +673,8 @@ static void 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); } @@ -953,156 +959,172 @@ read_snmp_response(int fd) /* I - SNMP socket file descriptor */ * 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; } } @@ -1141,15 +1163,8 @@ scan_devices(int fd) /* I - SNMP socket */ 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... */ @@ -1189,7 +1204,7 @@ scan_devices(int fd) /* I - SNMP socket */ 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); @@ -1219,21 +1234,30 @@ scan_devices(int fd) /* I - SNMP socket */ 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()); } diff --git a/backend/usb-darwin.c b/backend/usb-darwin.c index d0371378b..d33379564 100644 --- a/backend/usb-darwin.c +++ b/backend/usb-darwin.c @@ -65,7 +65,7 @@ * 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. @@ -98,8 +98,11 @@ #include #include +#include #include +extern char **environ; + /* * WAIT_EOF_DELAY is number of seconds we'll wait for responses from @@ -275,11 +278,11 @@ static void setup_cfLanguage(void); 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); @@ -392,17 +395,18 @@ print_device(const char *uri, /* I - Device URI */ 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) { @@ -518,7 +522,7 @@ print_device(const char *uri, /* I - Device URI */ if (print_fd != STDIN_FILENO) { - fputs("PAGE: 1 1", stderr); + fputs("PAGE: 1 1\n", stderr); lseek(print_fd, 0, SEEK_SET); } @@ -1052,8 +1056,8 @@ static Boolean list_device_cb(void *refcon, 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); @@ -1154,7 +1158,7 @@ static void status_timer_cb(CFRunLoopTimerRef timer, 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) { @@ -1729,36 +1733,42 @@ static void setup_cfLanguage(void) } #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... @@ -1777,57 +1787,49 @@ static void run_ppc_backend(int argc, 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); } /* @@ -1851,9 +1853,9 @@ static void run_ppc_backend(int argc, 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 { @@ -1869,7 +1871,7 @@ static void run_ppc_backend(int argc, else { fputs("DEBUG: usb(legacy) backend running native again\n", stderr); - exitstatus = ENOENT; + exitstatus = CUPS_BACKEND_STOP; } exit(exitstatus); @@ -1889,7 +1891,7 @@ static void sigterm_handler(int sig) exit(1); } -#endif /* __i386__ */ +#endif /* __i386__ || __x86_64__ */ #ifdef PARSE_PS_ERRORS diff --git a/backend/usb-libusb.c b/backend/usb-libusb.c index 4a7716ec3..cad8d87ca 100644 --- a/backend/usb-libusb.c +++ b/backend/usb-libusb.c @@ -447,9 +447,8 @@ list_cb(usb_printer_t *printer, /* I - Printer */ * 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... diff --git a/backend/usb-unix.c b/backend/usb-unix.c index 5fbed6ecd..de4ab4e29 100644 --- a/backend/usb-unix.c +++ b/backend/usb-unix.c @@ -210,6 +210,7 @@ list_devices(void) device_uri[1024], /* Device URI string */ make_model[1024]; /* Make and model */ + /* * Try to open each USB device... */ @@ -245,8 +246,8 @@ list_devices(void) 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); } @@ -273,8 +274,8 @@ list_devices(void) 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); } diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c index e67582d02..bddc2d038 100644 --- a/cgi-bin/admin.c +++ b/cgi-bin/admin.c @@ -20,15 +20,17 @@ * 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. */ @@ -43,6 +45,7 @@ #include #include #include +#include /* @@ -64,6 +67,9 @@ static void do_printer_op(http_t *http, 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); @@ -177,7 +183,7 @@ main(int argc, /* I - Number of command-line arguments */ else { /* - * Bad operation code... Display an error... + * Bad operation code - display an error... */ cgiStartHTML(cgiText(_("Administration"))); @@ -206,7 +212,7 @@ main(int argc, /* I - Number of command-line arguments */ else { /* - * Form data but no operation code... Display an error... + * Form data but no operation code - display an error... */ cgiStartHTML(cgiText(_("Administration"))); @@ -1769,7 +1775,7 @@ do_config_server(http_t *http) /* I - HTTP connection */ /* - * 'do_delete_class()' - Delete a class... + * 'do_delete_class()' - Delete a class. */ static void @@ -1854,7 +1860,7 @@ do_delete_class(http_t *http) /* I - HTTP connection */ /* - * 'do_delete_printer()' - Delete a printer... + * 'do_delete_printer()' - Delete a printer. */ static void @@ -1939,7 +1945,7 @@ do_delete_printer(http_t *http) /* I - HTTP connection */ /* - * 'do_export()' - Export printers to Samba... + * 'do_export()' - Export printers to Samba. */ static void @@ -2075,7 +2081,7 @@ do_export(http_t *http) /* I - HTTP connection */ /* - * 'do_list_printers()' - List available printers... + * 'do_list_printers()' - List available printers. */ static void @@ -2278,7 +2284,7 @@ do_list_printers(http_t *http) /* I - HTTP connection */ /* - * 'do_menu()' - Show the main menu... + * 'do_menu()' - Show the main menu. */ static void @@ -2774,12 +2780,15 @@ do_set_options(http_t *http, /* I - HTTP connection */ 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 */ @@ -2847,32 +2856,14 @@ do_set_options(http_t *http, /* I - HTTP connection */ { ppdMarkDefaults(ppd); - DEBUG_printf(("

ppd->num_groups = %d\n" - "

    \n", ppd->num_groups)); - - for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) - { - DEBUG_printf(("
  • %s
      \n", group->text)); - - for (j = group->num_options, option = group->options; - j > 0; - j --, option ++) - if ((var = cgiGetVariable(option->keyword)) != NULL) - { - DEBUG_printf(("
    • %s = \"%s\"
    • \n", option->keyword, var)); - have_options = 1; - ppdMarkOption(ppd, option->keyword, var); - } -#ifdef DEBUG - else - printf("
    • %s not defined!
    • \n", option->keyword); -#endif /* DEBUG */ - - DEBUG_puts("
  • "); - } - - DEBUG_printf(("
\n" - "

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)) @@ -2928,7 +2919,7 @@ do_set_options(http_t *http, /* I - HTTP connection */ cgiSetVariable("KEYWORD", option->keyword); cgiSetVariable("KEYTEXT", option->text); - + if (option->conflicted) cgiSetVariable("CONFLICTED", "1"); else @@ -2938,13 +2929,6 @@ do_set_options(http_t *http, /* I - HTTP connection */ 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); @@ -2954,6 +2938,118 @@ do_set_options(http_t *http, /* I - HTTP connection */ 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 : @@ -3199,17 +3295,21 @@ do_set_options(http_t *http, /* I - HTTP connection */ 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); @@ -3307,7 +3407,7 @@ do_set_options(http_t *http, /* I - HTTP connection */ /* - * 'do_set_sharing()' - Set printer-is-shared value... + * 'do_set_sharing()' - Set printer-is-shared value. */ static void @@ -3399,6 +3499,294 @@ do_set_sharing(http_t *http) /* I - HTTP connection */ } +/* + * '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. */ diff --git a/config-scripts/cups-common.m4 b/config-scripts/cups-common.m4 index e48fc0fe4..16e6b2b0e 100644 --- a/config-scripts/cups-common.m4 +++ b/config-scripts/cups-common.m4 @@ -188,6 +188,19 @@ if test $check_libusb = yes; then 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*) diff --git a/config-scripts/cups-compiler.m4 b/config-scripts/cups-compiler.m4 index 8598aebb9..8d30df79c 100644 --- a/config-scripts/cups-compiler.m4 +++ b/config-scripts/cups-compiler.m4 @@ -145,6 +145,7 @@ if test -n "$GCC"; then # 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 diff --git a/config-scripts/cups-directories.m4 b/config-scripts/cups-directories.m4 index 4105ba17f..16d414d22 100644 --- a/config-scripts/cups-directories.m4 +++ b/config-scripts/cups-directories.m4 @@ -123,12 +123,14 @@ AC_ARG_WITH(rcdir, [ --with-rcdir set path for rc scripts],rcdir="$w 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 @@ -192,8 +194,12 @@ if test x$rcdir = x; then SunOS*) # Solaris - INITDIR="/etc" - RCSTART="81" + if test "x$smfmanifestdir" != x; then + SMFMANIFESTDIR=$smfmanifestdir + else + INITDIR="/etc" + RCSTART="81" + fi ;; *) @@ -214,6 +220,7 @@ AC_SUBST(INITDDIR) 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="") diff --git a/config-scripts/cups-ldap.m4 b/config-scripts/cups-ldap.m4 index 3f5adec23..1c5f516bc 100644 --- a/config-scripts/cups-ldap.m4 +++ b/config-scripts/cups-ldap.m4 @@ -14,22 +14,34 @@ dnl file is missing or damaged, see the license at "http://www.cups.org/". 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 ]) + 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) diff --git a/config.h.in b/config.h.in index cd801f72e..9a95a084f 100644 --- a/config.h.in +++ b/config.h.in @@ -307,6 +307,10 @@ #undef HAVE_LDAP #undef HAVE_OPENLDAP +#undef HAVE_MOZILLA_LDAP +#undef HAVE_LDAP_SSL_H +#undef HAVE_LDAP_SSL +#undef HAVE_LDAP_REBIND_PROC /* @@ -586,6 +590,13 @@ #undef HAVE_USB_H +/* + * Do we have libwrap and tcpd.h? + */ + +#undef HAVE_TCPD_H + + #endif /* !_CUPS_CONFIG_H_ */ /* diff --git a/configure.in b/configure.in index 0425660be..8ff9a0e0c 100644 --- a/configure.in +++ b/configure.in @@ -65,7 +65,7 @@ AC_SUBST(UNINSTALL_LANGUAGES) 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 diff --git a/cups/adminutil.c b/cups/adminutil.c index 87ff36fd7..3ea7e81af 100644 --- a/cups/adminutil.c +++ b/cups/adminutil.c @@ -260,9 +260,9 @@ cupsAdminCreateWindowsPPD( 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); @@ -281,7 +281,7 @@ cupsAdminCreateWindowsPPD( _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); @@ -300,7 +300,7 @@ cupsAdminCreateWindowsPPD( _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); @@ -343,10 +343,7 @@ cupsAdminCreateWindowsPPD( 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); @@ -434,7 +431,7 @@ cupsAdminExportSamba( if (!dest || !ppd || !samba_server || !samba_user || !samba_password) { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); return (0); } @@ -444,7 +441,7 @@ cupsAdminExportSamba( if ((fp = cupsTempFile2(authfile, sizeof(authfile))) == NULL) { - _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno)); + _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0); return (0); } @@ -497,7 +494,7 @@ cupsAdminExportSamba( _("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); @@ -532,7 +529,7 @@ cupsAdminExportSamba( _("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); @@ -575,7 +572,7 @@ cupsAdminExportSamba( _("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); @@ -620,7 +617,7 @@ cupsAdminExportSamba( _("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); @@ -649,7 +646,7 @@ cupsAdminExportSamba( _("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); @@ -701,7 +698,7 @@ cupsAdminExportSamba( _("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); @@ -736,7 +733,7 @@ cupsAdminExportSamba( _("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); @@ -779,7 +776,7 @@ cupsAdminExportSamba( _("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); @@ -804,13 +801,13 @@ cupsAdminExportSamba( "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); @@ -831,7 +828,7 @@ cupsAdminExportSamba( _("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); @@ -901,7 +898,7 @@ _cupsAdminGetServerSettings( if (!http || !num_settings || !settings) { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); if (num_settings) *num_settings = 0; @@ -928,9 +925,9 @@ _cupsAdminGetServerSettings( 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 @@ -1224,7 +1221,7 @@ _cupsAdminSetServerSettings( if (!http || !num_settings || !settings) { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); return (0); } @@ -1238,7 +1235,7 @@ _cupsAdminSetServerSettings( { if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL) { - _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno)); + _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0); return (0); } } @@ -1395,7 +1392,7 @@ _cupsAdminSetServerSettings( if (remote) unlink(cupsdconf); - _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno)); + _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0); return (0); } @@ -2203,7 +2200,7 @@ get_cupsd_conf( 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'; @@ -2225,7 +2222,7 @@ get_cupsd_conf( { *name = '\0'; - _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno)); + _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0); invalidate_cupsd_cache(cg); diff --git a/cups/backend.c b/cups/backend.c index 021dad2e2..ca4fad2f3 100644 --- a/cups/backend.c +++ b/cups/backend.c @@ -1,5 +1,5 @@ /* - * "$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). * @@ -17,6 +17,8 @@ * 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 ". */ /* @@ -28,6 +30,13 @@ #include "globals.h" +/* + * Local functions... + */ + +static void quote_string(const char *s); + + /* * 'cupsBackendDeviceURI()' - Get the device URI for a backend. * @@ -58,5 +67,64 @@ cupsBackendDeviceURI(char **argv) /* I - Command-line arguments */ /* - * 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 $". */ diff --git a/cups/backend.h b/cups/backend.h index 77bf57569..f128895da 100644 --- a/cups/backend.h +++ b/cups/backend.h @@ -48,7 +48,14 @@ typedef enum cups_backend_e cups_backend_t; */ 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_ */ diff --git a/cups/cups.h b/cups/cups.h index 1038c8313..08aaf3479 100644 --- a/cups/cups.h +++ b/cups/cups.h @@ -124,7 +124,8 @@ typedef const char *(*cups_password_cb_t)(const char *prompt); 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 ****/ diff --git a/cups/dest.c b/cups/dest.c index 66289b2c7..d2a9b3462 100644 --- a/cups/dest.c +++ b/cups/dest.c @@ -31,9 +31,9 @@ * 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. @@ -73,9 +73,9 @@ */ #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); @@ -929,6 +929,44 @@ cupsSetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_ #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. */ @@ -957,7 +995,7 @@ appleGetDefault(char *name, /* I - Name buffer */ * Get the current location... */ - if ((network = appleGetNetwork()) == NULL) + if ((network = appleCopyNetwork()) == NULL) { DEBUG_puts("appleGetDefault: Unable to get current network..."); return (NULL); @@ -980,6 +1018,8 @@ appleGetDefault(char *name, /* I - Name buffer */ DEBUG_puts("appleGetDefault: Missing or bad location history array..."); + CFRelease(network); + return (NULL); } @@ -991,6 +1031,8 @@ appleGetDefault(char *name, /* I - Name buffer */ else name[0] = '\0'; + CFRelease(network); + DEBUG_printf(("appleGetDefault: Returning \"%s\"...\n", name)); return (*name ? name : NULL); @@ -1025,44 +1067,6 @@ appleGetLocations(void) } -/* - * '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. */ @@ -1122,7 +1126,7 @@ appleSetDefault(const char *name) /* I - Default printer/class name */ * Get the current location... */ - if ((network = appleGetNetwork()) == NULL) + if ((network = appleCopyNetwork()) == NULL) { DEBUG_puts("appleSetDefault: Unable to get current network..."); return; @@ -1202,6 +1206,7 @@ appleSetDefault(const char *name) /* I - Default printer/class name */ CFRelease(newlocation); } + CFRelease(network); CFRelease(newprinter); } diff --git a/cups/getdevices.c b/cups/getdevices.c index d0e1cf2fa..c6f7ddac3 100644 --- a/cups/getdevices.c +++ b/cups/getdevices.c @@ -15,6 +15,7 @@ * * Contents: * + * cupsGetDevices() - Get available printer devices. */ /* @@ -50,6 +51,7 @@ cupsGetDevices( 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 */ @@ -160,6 +162,7 @@ cupsGetDevices( device_class = NULL; device_id = NULL; device_info = NULL; + device_location = ""; device_make_and_model = NULL; device_uri = NULL; attr = NULL; @@ -192,11 +195,13 @@ cupsGetDevices( 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; } @@ -209,6 +214,9 @@ cupsGetDevices( 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; @@ -225,7 +233,7 @@ cupsGetDevices( 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... @@ -235,7 +243,7 @@ cupsGetDevices( httpFlush(http); if (status == IPP_ERROR) - _cupsSetError(IPP_ERROR, NULL); + _cupsSetError(IPP_ERROR, NULL, 0); else { attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT); @@ -245,8 +253,8 @@ cupsGetDevices( 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); diff --git a/cups/globals.h b/cups/globals.h index d098e868e..f2ae63b97 100644 --- a/cups/globals.h +++ b/cups/globals.h @@ -136,7 +136,8 @@ typedef struct _cups_globals_s /**** CUPS global state data ****/ 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); diff --git a/cups/langprintf.c b/cups/langprintf.c index 84956888c..059e9983f 100644 --- a/cups/langprintf.c +++ b/cups/langprintf.c @@ -17,9 +17,11 @@ * * 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. */ /* diff --git a/cups/libcups.exp b/cups/libcups.exp index 8f34b3ccc..3da3642b0 100644 --- a/cups/libcups.exp +++ b/cups/libcups.exp @@ -86,6 +86,7 @@ _cupsArrayUserData _cupsBackChannelRead _cupsBackChannelWrite _cupsBackendDeviceURI +_cupsBackendReport _cupsCancelJob _cupsCancelJob2 _cupsCharsetToUTF8 diff --git a/cups/ppd.c b/cups/ppd.c index 75db5c5ac..e88dad15b 100644 --- a/cups/ppd.c +++ b/cups/ppd.c @@ -1050,14 +1050,15 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * 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)); @@ -1089,14 +1090,15 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ 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)); @@ -1301,14 +1303,15 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ 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"), diff --git a/cups/request.c b/cups/request.c index f8978a627..fc6a7fa18 100644 --- a/cups/request.c +++ b/cups/request.c @@ -80,7 +80,7 @@ cupsDoFileRequest(http_t *http, /* I - Connection to server or @code CUPS_HT */ _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, - strerror(errno)); + NULL, 0); ippDelete(request); @@ -143,7 +143,7 @@ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP { ippDelete(request); - _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL)); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); return (NULL); } @@ -169,7 +169,7 @@ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP */ _cupsSetError(errno == EBADF ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, - strerror(errno)); + NULL, 0); ippDelete(request); @@ -188,7 +188,7 @@ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP ippDelete(request); - _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR)); + _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR), 0); return (NULL); } @@ -395,7 +395,7 @@ cupsGetResponse(http_t *http, /* I - Connection to server or @code CUPS_HTTP ippDelete(response); response = NULL; - _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno)); + _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0); } } else if (status != HTTP_ERROR) @@ -453,8 +453,8 @@ cupsGetResponse(http_t *http, /* I - Connection to server or @code CUPS_HTTP 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); @@ -492,7 +492,7 @@ cupsReadResponseData( if ((http = cg->http) == NULL) { - _cupsSetError(IPP_INTERNAL_ERROR, "No active connection"); + _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1); return (-1); } } @@ -542,7 +542,7 @@ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP if (!request || !resource) { - _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL)); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); return (HTTP_ERROR); } @@ -724,7 +724,7 @@ cupsWriteRequestData( if ((http = cg->http) == NULL) { - _cupsSetError(IPP_INTERNAL_ERROR, "No active connection"); + _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1); return (HTTP_ERROR); } } @@ -753,26 +753,49 @@ cupsWriteRequestData( 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 : "")); } @@ -786,37 +809,37 @@ _cupsSetHTTPError(http_status_t status) /* I - HTTP status code */ 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; } } diff --git a/cups/testppd.c b/cups/testppd.c index 943e390e1..cfd872d29 100644 --- a/cups/testppd.c +++ b/cups/testppd.c @@ -602,7 +602,14 @@ main(int argc, /* I - Number of command-line arguments */ 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]; diff --git a/cups/util.c b/cups/util.c index 605cd89e8..f52bbe7f0 100644 --- a/cups/util.c +++ b/cups/util.c @@ -131,7 +131,7 @@ cupsCancelJob2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_ if (job_id < -1 || (!name && job_id == 0)) { - _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL)); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); return (0); } @@ -229,7 +229,7 @@ cupsCreateJob( if (!name) { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); return (0); } @@ -239,7 +239,7 @@ cupsCreateJob( if ((request = ippNewRequest(IPP_CREATE_JOB)) == NULL) { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(ENOMEM), 0); return (0); } @@ -346,7 +346,7 @@ cupsGetClasses(char ***classes) /* O - Classes */ if (!classes) { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); return (0); } @@ -596,7 +596,7 @@ cupsGetJobs2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_D if (!jobs) { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); return (-1); } @@ -610,7 +610,7 @@ cupsGetJobs2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_D 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); } @@ -764,7 +764,7 @@ cupsGetJobs2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_D * Ran out of memory! */ - _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno)); + _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0); cupsFreeJobs(n, *jobs); *jobs = NULL; @@ -921,19 +921,19 @@ cupsGetPPD3(http_t *http, /* I - HTTP connection or @code CUPS_HTTP_DEFAUL 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); } @@ -1010,7 +1010,7 @@ cupsGetPPD3(http_t *http, /* I - HTTP connection or @code CUPS_HTTP_DEFAUL * 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); @@ -1043,17 +1043,17 @@ cupsGetPPD3(http_t *http, /* I - HTTP connection or @code CUPS_HTTP_DEFAUL 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; } @@ -1096,7 +1096,7 @@ cupsGetPrinters(char ***printers) /* O - Printers */ if (!printers) { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); return (0); } @@ -1208,7 +1208,7 @@ cupsGetServerPPD(http_t *http, /* I - Connection to server or @code CUPS_HTT if (!name) { - _cupsSetError(IPP_INTERNAL_ERROR, "No PPD name!"); + _cupsSetError(IPP_INTERNAL_ERROR, _("No PPD name!"), 1); return (NULL); } @@ -1227,7 +1227,7 @@ cupsGetServerPPD(http_t *http, /* I - Connection to server or @code CUPS_HTT * 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); } @@ -1388,7 +1388,7 @@ cupsPrintFiles2( if (!name || num_files < 1 || !files) { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); return (0); } @@ -1490,7 +1490,7 @@ cupsStartDocument( if ((request = ippNewRequest(IPP_SEND_DOCUMENT)) == NULL) { - _cupsSetError(IPP_INTERNAL_ERROR, NULL); + _cupsSetError(IPP_INTERNAL_ERROR, strerror(ENOMEM), 0); return (0); } @@ -1583,8 +1583,13 @@ _cupsConnect(void) { 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); + } } /* @@ -1642,7 +1647,7 @@ cups_get_printer_uri( 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'; @@ -1777,7 +1782,8 @@ cups_get_printer_uri( 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'; @@ -1792,7 +1798,7 @@ cups_get_printer_uri( } 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'; diff --git a/cups/versioning.h b/cups/versioning.h index 659d55bef..96972ee74 100644 --- a/cups/versioning.h +++ b/cups/versioning.h @@ -3,7 +3,7 @@ * * 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 @@ -22,48 +22,33 @@ * _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 +# 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 diff --git a/doc/cups.css b/doc/cups.css index 637f3d885..7588d1149 100644 --- a/doc/cups.css +++ b/doc/cups.css @@ -204,6 +204,12 @@ TH.label { vertical-align: top; } +TH.sublabel { + padding-top: 0pt; + text-align: right; + font-weight: normal; +} + HR { border: solid thin; } diff --git a/doc/help/kerberos.html b/doc/help/kerberos.html index 83c5fe8f0..d30758118 100644 --- a/doc/help/kerberos.html +++ b/doc/help/kerberos.html @@ -5,20 +5,43 @@ -

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.

+

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.

-
Note: -

In order to use Kerberos-authenticated shared printers, you must be -running a version of MIT Kerberos with the krb5_cc_new_unique() -function or Heimdal Kerberos. Otherwise, only local Kerberos authentication -is supported.

+

System Requirements

-
+

The following are required to use Kerberos with CUPS:

+ +
    + +
  1. Heimdal Kerberos (any version) or MIT Kerberos (1.6.3 or newer)
  2. + +
  3. Properly configured Domain Name System (DNS) + infrastructure:
      +
    1. DNS server(s) with static IP addresses for all CUPS clients + and servers or configured to allow DHCP updates to the host + addresses
    2. +
    3. All CUPS clients and servers configured to use the same + DNS server(s)
    4. +
  4. + +
  5. Properly configured Kerberos infrastructure:
      +
    1. KDC configured to allow CUPS clients and servers to obtain + Service Granting Tickets (SGTs) for the "ipp" service
    2. +
    3. LDAP-based user accounts - both OpenDirectory and + ActiveDirectory provide this with the KDC
    4. +
    5. CUPS clients and servers bound to the KDC and LDAP + server(s)
    6. +
  6. + +
  7. An "ipp" Service Granting Ticket (SGT) for every CUPS client and + server
  8. + +

Configuring Kerberos on Your System

@@ -68,80 +91,29 @@ Settings:

http://localhost:631/admin -

After you have enabled Kerberos authentication, add AuthType Default -lines to the policies you want to protect with authentication, for example:

- -
-Listing 1: Remote Printer Operation Policy
-
- 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 varies by OS
-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>
-
+

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 Managing Operation Policies +for more information.

Implementation Information

-

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.

- -

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.

+

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.

+ +

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.

+ +

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.

diff --git a/doc/help/options.html b/doc/help/options.html index 8ad4ffada..c2d37220c 100644 --- a/doc/help/options.html +++ b/doc/help/options.html @@ -720,76 +720,6 @@ at half its natural size. If the specified scaling makes the image larger than the page, multiple pages will be printed to satisfy the request. -

Adjusting Image Hue (Tint)

- -

The -o hue=value option will adjust the hue of the -printed image, much like the tint control on your television: - -

-lp -o hue=value filename
-lpr -o hue=value filename
-
- -

The value 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:

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Originalhue=-45hue=45
RedPurpleYellow-orange
GreenYellow-greenBlue-green
YellowOrangeGreen-yellow
BlueSky-bluePurple
MagentaIndigoCrimson
CyanBlue-greenLight-navy-blue
- -

The default hue adjustment is 0. - -

Adjusting Image Saturation (Color)

- -

The -o saturation=percent option adjusts the saturation -of the colors in an image, much like the color control on your television:

- -
-lp -o saturation=percent filename
-lpr -o saturation=percent filename
-
- -

The percent 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.

- -

The default saturation is 100.

-

HP-GL/2 Options

diff --git a/doc/help/ref-cupsd-conf.html.in b/doc/help/ref-cupsd-conf.html.in index 37ddc448a..9d5ca0e5b 100644 --- a/doc/help/ref-cupsd-conf.html.in +++ b/doc/help/ref-cupsd-conf.html.in @@ -474,6 +474,20 @@ domain name to use when listening for printer registrations. The default is undefined.

+

CUPS 1.4BrowseLDAPCACertFile

+ +

Examples

+ +
+BrowseLDAPCACertFile /etc/cups/ssl/certs
+
+ +

Description

+ +

The BrowseLDAPCACertFile directive specifies the SSL certificate +authority file to use for LDAP + SSL. The default is undefined.

+ +

CUPS 1.2BrowseLDAPDN

Examples

diff --git a/doc/help/spec-ipp.html b/doc/help/spec-ipp.html index a1c85a825..63a5fe5a6 100644 --- a/doc/help/spec-ipp.html +++ b/doc/help/spec-ipp.html @@ -2043,9 +2043,14 @@ string for the device.

The device-info attribute specifies a human-readable string describing the device, e.g. "Parallel Port #1". +

device-location (text(127))CUPS 1.4

+ +

The device-location attribute specifies the physical location of the +printer. +

device-make-and-model (text(127))

-

The device-makr-and-model attribute specifies a device +

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". @@ -2108,7 +2113,7 @@ of the device-class attribute: rendered entirely in black ink (blackplot=true) or using the colors and shades specified in the file (blackplot=false). The default value is false. -

brightness (integer(0:200))

+

brightness (integer(0:200))Deprecated

The brightness attribute specifies the overall brightness of the printed output in percent. A brightness of 100 is normal, while 200 is twice as @@ -2117,6 +2122,13 @@ bright and 50 is half as bright. The default value is 100.

Brightness is applied to the Cyan, Magenta, Yellow, and Black values using the function "f(x) = brightness / 100 * x". +

Note: + +

This attribute is deprecated and will be removed from a future CUPS +release.

+ +
+

columns (integer(1:4))

The columns attribute specifies the number of columns to generate when @@ -2139,7 +2151,7 @@ are present in the job. fit on the selected media (fitplot=true) or use the physical scale specified in the plot file (fitplot=false). The default value is false. -

gamma (integer(1:10000))

+

gamma (integer(1:10000))Deprecated

The gamma attribute specifies the luminance correction for the output. A value of 1000 specifies no correction, while values of 2000 and 500 will @@ -2147,13 +2159,27 @@ generate lighter and darker output, respectively. The default value is 1000.

Gamma is applied to the Red, Green, and Blue values (or luminance for -grayscale output) using the function "f(x) = x(1000/gamma)". +grayscale output) using the function "f(x) = x(1000/gamma)". + +

Note: + +

This attribute is deprecated and will be removed from a future CUPS +release.

-

hue (integer(-180:180))

+
+ +

hue (integer(-180:180))Deprecated

The hue attribute specifies a color hue rotation when printing image files. The default value is 0. +

Note: + +

This attribute is deprecated and will be removed from a future CUPS +release.

+ +
+

job-billing (text(MAX))CUPS 1.1

The job-billing attribute provides a text value to associate with a job @@ -2344,13 +2370,20 @@ per inch. The default value is the resolution included with the file or with a shaded header and keyword highlighting (prettyprint=true) or without additional formatting (prettyprint=false). The default value is false. -

saturation (integer(0:200))

+

saturation (integer(0:200))Deprecated

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. +

Note: + +

This attribute is deprecated and will be removed from a future CUPS +release.

+ +
+

scaling (integer(1:1000))

The scaling attribute specifies the scaling of image files with diff --git a/doc/help/spec-ppd.html b/doc/help/spec-ppd.html index 5a9865090..33254bd14 100644 --- a/doc/help/spec-ppd.html +++ b/doc/help/spec-ppd.html @@ -1022,6 +1022,96 @@ PRE B { +

Media Attributes

+ +

The CUPS media attributes allow drivers to specify alternate custom page +size limits based on up to two options.

+ +

CUPS 1.4cupsMediaQualifier2

+ +

*cupsMediaQualifier2: MainKeyword

+ +

This attribute specifies the second option to use for overriding the +custom page size limits.

+ +

Example:

+ +
+*% Specify alternate custom page size limits based on InputSlot and Quality
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+
+ +

CUPS 1.4cupsMediaQualifier3

+ +

*cupsMediaQualifier3: MainKeyword

+ +

This attribute specifies the third option to use for overriding the +custom page size limits.

+ +

Example:

+ +
+*% Specify alternate custom page size limits based on InputSlot and Quality
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+
+ +

CUPS 1.4cupsMinSize

+ +

*cupsMinSize .Qualifier2.Qualifier3: "width length"
+*cupsMinSize .Qualifier2.: "width length"
+*cupsMinSize ..Qualifier3: "width length"

+ +

This attribute specifies alternate minimum custom page sizes in points. +The cupsMediaQualifier2 and +cupsMediaQualifier3 attributes +are used to identify options to use for matching.

+ +

Example:

+ +
+*% Specify alternate custom page size limits based on InputSlot and Quality
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+
+ +

CUPS 1.4cupsMaxSize

+ +

*cupsMaxSize .Qualifier2.Qualifier3: "width length"
+*cupsMaxSize .Qualifier2.: "width length"
+*cupsMaxSize ..Qualifier3: "width length"

+ +

This attribute specifies alternate maximum custom page sizes in points. +The cupsMediaQualifier2 and +cupsMediaQualifier3 attributes +are used to identify options to use for matching.

+ +

Example:

+ +
+*% Specify alternate custom page size limits based on InputSlot and Quality
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+
+ +

General Attributes

CUPS 1.3cupsBackSide

@@ -1711,17 +1801,28 @@ the device.

@@ -1744,13 +1845,18 @@ the device.

    -
  • Added cupsBackSide and deprecated cupsFlipDuplex.
  • +
  • Added cupsBackSide and + deprecated cupsFlipDuplex.
  • -
  • Added text URI information to cupsIPPReason documentation.
  • +
  • Added text URI information to + cupsIPPReason documentation.
  • -
  • Added APPrinterPreset, cupsIPPFinishings, and cupsPreFilter attributes.
  • +
  • Added APPrinterPreset, + cupsIPPFinishings, and + cupsPreFilter attributes.
  • -
  • Added discussion of custom option code, sample CustomPageSize code, and "do not use dict and put" note.
  • +
  • Added discussion of custom option code, sample + CustomPageSize code, and "do not use dict and put" note.
@@ -1771,17 +1877,18 @@ the device.

  • Added custom option values support
  • -
  • Added APHelpBook attribute
  • +
  • Added APHelpBook attribute
  • -
  • Added APDuplexRequiresFlippedMargin attribute
  • +
  • Added APDuplexRequiresFlippedMargin + attribute
  • -
  • Added cupsICCProfile attribute
  • +
  • Added cupsICCProfile attribute
  • -
  • Added cupsIPPReason attribute
  • +
  • Added cupsIPPReason attribute
  • -
  • Added cupsLanguages attribute
  • +
  • Added cupsLanguages attribute
  • -
  • Added cupsPortMonitor attribute
  • +
  • Added cupsPortMonitor attribute
  • Removed cupsProtocol attribute
  • @@ -1791,7 +1898,7 @@ the device.

      -
    • Added cupsFlipDuplex attribute
    • +
    • Added cupsFlipDuplex attribute
    • Added cupsProtocol attribute
    • diff --git a/init/cups.xml.in b/init/cups.xml.in new file mode 100644 index 000000000..e47398ae4 --- /dev/null +++ b/init/cups.xml.in @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/man/backend.man b/man/backend.man index b8a52d9ba..b4ba42516 100644 --- a/man/backend.man +++ b/man/backend.man @@ -3,7 +3,7 @@ .\" .\" 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 @@ -12,7 +12,7 @@ .\" 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 @@ -59,6 +59,7 @@ forms: 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 @@ -111,6 +112,11 @@ The optional \fIdevice-id\fR field specifies the IEEE-1284 device 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 @@ -173,7 +179,7 @@ All other exit code values are reserved. 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 $". .\" diff --git a/man/cupsd.conf.man.in b/man/cupsd.conf.man.in index 6fbdd31bb..4421c1df4 100644 --- a/man/cupsd.conf.man.in +++ b/man/cupsd.conf.man.in @@ -146,6 +146,26 @@ BrowseInterval seconds .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 diff --git a/notifier/Makefile b/notifier/Makefile index 4f05e374f..90b51b4d7 100644 --- a/notifier/Makefile +++ b/notifier/Makefile @@ -58,9 +58,7 @@ install-data: -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 @@ -70,9 +68,8 @@ install-data: 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 # diff --git a/scheduler/Makefile b/scheduler/Makefile index c199e697c..e580c2ddc 100644 --- a/scheduler/Makefile +++ b/scheduler/Makefile @@ -333,14 +333,15 @@ cupsd: $(CUPSDOBJS) $(LIBCUPSMIME) ../cups/$(LIBCUPS) $(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) # diff --git a/scheduler/client.c b/scheduler/client.c index 25be7a491..ac52bd99e 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -76,6 +76,10 @@ extern const char *cssmErrorString(int error); # include #endif /* HAVE_GNUTLS */ +#ifdef HAVE_TCPD_H +# include +#endif /* HAVE_TCPD_H */ + /* * Local functions... @@ -125,6 +129,9 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ 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, @@ -240,7 +247,9 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ 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 @@ -322,7 +331,8 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ * 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... @@ -362,6 +372,34 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ } } +#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)", diff --git a/scheduler/cups-deviced.c b/scheduler/cups-deviced.c index 3fb619e1e..8b634a27c 100644 --- a/scheduler/cups-deviced.c +++ b/scheduler/cups-deviced.c @@ -65,10 +65,8 @@ typedef struct 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; @@ -92,7 +90,8 @@ static int send_class, /* Send device-class attribute? */ 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? */ @@ -105,7 +104,8 @@ static int add_device(const char *device_class, 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); @@ -198,7 +198,10 @@ main(int argc, /* I - Number of command-line args */ 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; @@ -206,6 +209,7 @@ main(int argc, /* I - Number of command-line args */ 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; } /* @@ -345,7 +349,8 @@ add_device( 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 */ @@ -366,11 +371,8 @@ add_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... @@ -397,16 +399,20 @@ add_device( 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); @@ -508,11 +514,14 @@ static int /* O - 0 on success, -1 on error */ 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))) @@ -520,35 +529,123 @@ get_device(cupsd_backend_t *backend) /* I - Backend to read from */ /* * 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); } @@ -561,6 +658,19 @@ get_device(cupsd_backend_t *backend) /* I - Backend to read from */ 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); } diff --git a/scheduler/cups-driverd.cxx b/scheduler/cups-driverd.cxx index bed393eae..7742abc93 100644 --- a/scheduler/cups-driverd.cxx +++ b/scheduler/cups-driverd.cxx @@ -76,7 +76,7 @@ static const char * const ppd_types[] = /* ppd-type values */ 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 */ diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c index b2960d65d..27efd0d00 100644 --- a/scheduler/dirsvc.c +++ b/scheduler/dirsvc.c @@ -14,55 +14,6 @@ * * 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. */ /* @@ -104,7 +55,36 @@ static void process_browse_data(const char *uri, const char *host, 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); @@ -131,7 +111,7 @@ static void dnssdRegisterPrinter(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", @@ -141,7 +121,7 @@ static const char * const ldap_attrs[] =/* CUPS LDAP attributes */ "printerURI", NULL }; -#endif /* HAVE_OPENLDAP */ +#endif /* HAVE_LDAP */ #ifdef HAVE_LIBSLP /* @@ -224,6 +204,11 @@ cupsdDeregisterPrinter( 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); @@ -928,6 +913,425 @@ cupsdSendBrowseList(void) } +#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. */ @@ -1125,7 +1529,7 @@ cupsdStartBrowsing(void) BrowseSLPHandle = NULL; #endif /* HAVE_LIBSLP */ -#ifdef HAVE_OPENLDAP +#ifdef HAVE_LDAP if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) { if (!BrowseLDAPDN) @@ -1137,84 +1541,13 @@ cupsdStartBrowsing(void) } 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... @@ -1425,11 +1758,12 @@ cupsdStopBrowsing(void) } #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 */ @@ -1545,7 +1879,7 @@ cupsdUpdateDNSSDName(void) #endif /* HAVE_DNSSD */ -#ifdef HAVE_OPENLDAP +#ifdef HAVE_LDAP /* * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP... */ @@ -1559,36 +1893,72 @@ cupsdUpdateLDAPBrowse(void) 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... @@ -1602,41 +1972,28 @@ cupsdUpdateLDAPBrowse(void) * 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... */ @@ -1646,8 +2003,10 @@ cupsdUpdateLDAPBrowse(void) location, info, make_model, 0, NULL); } + + ldap_freeres(res); } -#endif /* HAVE_OPENLDAP */ +#endif /* HAVE_LDAP */ #ifdef HAVE_LIBSLP @@ -3232,7 +3591,346 @@ send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */ } -#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. */ @@ -3243,7 +3941,8 @@ send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */ 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], @@ -3251,9 +3950,14 @@ send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */ *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 */ @@ -3262,8 +3966,34 @@ send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */ 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... */ @@ -3283,63 +4013,153 @@ send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */ 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 ++) { @@ -3348,13 +4168,155 @@ send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */ } 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 diff --git a/scheduler/dirsvc.h b/scheduler/dirsvc.h index 60c22c3bd..7de4e2d56 100644 --- a/scheduler/dirsvc.h +++ b/scheduler/dirsvc.h @@ -22,12 +22,15 @@ # include #endif /* HAVE_LIBSLP */ -#ifdef HAVE_OPENLDAP +#ifdef HAVE_LDAP # ifdef __sun # include # endif /* __sun */ # include -#endif /* HAVE_OPENLDAP */ +# ifdef HAVE_LDAP_SSL_H +# include +# endif /* HAVE_LDAP_SSL_H */ +#endif /* HAVE_LDAP */ /* * Browse protocols... @@ -150,22 +153,26 @@ VAR time_t BrowseSLPRefresh VALUE(0); #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 */ diff --git a/scheduler/main.c b/scheduler/main.c index b6beb3ee0..571b3a7fc 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -1418,6 +1418,7 @@ launchd_checkin(void) "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) @@ -1426,28 +1427,32 @@ launchd_checkin(void) 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 */ } /* @@ -1464,73 +1469,75 @@ launchd_checkin(void) * 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 */ + } } } diff --git a/systemv/cupstestppd.c b/systemv/cupstestppd.c index b8052b3b5..e398d3f4c 100644 --- a/systemv/cupstestppd.c +++ b/systemv/cupstestppd.c @@ -21,8 +21,11 @@ * 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. @@ -58,7 +61,8 @@ enum WARN_FILTERS = 4, WARN_PROFILES = 8, WARN_TRANSLATIONS = 16, - WARN_ALL = 31 + WARN_DUPLEX = 32, + WARN_ALL = 63 }; @@ -96,8 +100,11 @@ enum 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, @@ -190,6 +197,8 @@ main(int argc, /* I - Number of command-line args */ 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")) @@ -1008,55 +1017,6 @@ main(int argc, /* I - Number of command-line args */ } } - /* - * 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")) { @@ -1074,6 +1034,8 @@ main(int argc, /* I - Number of command-line args */ errors ++; } + errors = check_case(ppd, errors, verbose); + if (!(warn & WARN_CONSTRAINTS)) errors = check_constraints(ppd, errors, verbose, 0); @@ -1086,6 +1048,9 @@ main(int argc, /* I - Number of command-line args */ 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) { @@ -1217,6 +1182,24 @@ main(int argc, /* I - Number of command-line args */ 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... */ @@ -1246,22 +1229,6 @@ main(int argc, /* I - Number of command-line args */ 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)) { @@ -1964,6 +1931,116 @@ check_constraints(ppd_file_t *ppd, /* I - PPD file */ } +/* + * '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. */ @@ -2031,6 +2108,76 @@ check_defaults(ppd_file_t *ppd, /* I - 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. */ @@ -2071,7 +2218,7 @@ check_filters(ppd_file_t *ppd, /* I - PPD file */ if (!warn) errors ++; } - else + else if (strcmp(program, "-")) { if (program[0] == '/') snprintf(pathprog, sizeof(pathprog), "%s%s", root, program); @@ -2122,7 +2269,7 @@ check_filters(ppd_file_t *ppd, /* I - PPD file */ if (!warn) errors ++; } - else + else if (strcmp(program, "-")) { if (program[0] == '/') snprintf(pathprog, sizeof(pathprog), "%s%s", root, program); @@ -2310,6 +2457,7 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ 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**"; @@ -2397,6 +2545,22 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ 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) @@ -2725,7 +2889,8 @@ usage(void) "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" diff --git a/systemv/lpinfo.c b/systemv/lpinfo.c index bd7fb0311..3e7cc1c6e 100644 --- a/systemv/lpinfo.c +++ b/systemv/lpinfo.c @@ -40,7 +40,8 @@ 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); @@ -173,6 +174,7 @@ device_cb( 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? */ @@ -191,9 +193,10 @@ device_cb( " 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); diff --git a/templates/option-pickone.tmpl b/templates/option-pickone.tmpl index 08342d06e..a2ce9d8c8 100644 --- a/templates/option-pickone.tmpl +++ b/templates/option-pickone.tmpl @@ -1,6 +1,18 @@ {keytext}: - {[choices]