From: mike Date: Tue, 23 Aug 2005 19:30:08 +0000 (+0000) Subject: backend/usb-unix.c: X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1d5ef58365ab07527c66d4026f8ab7633df91d3c;p=thirdparty%2Fcups.git backend/usb-unix.c: - Add some more checking to ensure we don't get "HP hp designjet..." model strings, and remove some unused code. cgi-bin/admin.c: - Set PRINTER_INFO (printer-description) value to make and model so that MacOS X clients see a reasonable printer name. doc/images/accept-jobs.gif: doc/images/reject-jobs.gif: - Change colors to green and red, respectively. scheduler/client.c: - Support IPP requests that use subprocesses (cups-deviced for now) scheduler/conf.c: scheduler/cupsd.h: scheduler/devices.c: - Remove static device initialization data. scheduler/cups-deviced.c: - Add new external (CGI-style) program to list devices dynamically. scheduler/ipp.c: - get_devices(): use new external cups-deviced command. - Remove extra looping variables. - ProcessIPPRequest(): add code to handle subprocess responses. scheduler/job.c: - Add CUPS_SERVERBIN environment variable. scheduler/Makefile: - Add cups-deviced targets, remove devices.o. scheduler/util.c: scheduler/util.h: - Added new utility functions for cups-deviced and others. test/run-stp-tests.sh: - Add symlink for daemon directory (now required for testing) git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@4583 7a7537e8-13f0-0310-91df-b6672ffda945 --- diff --git a/backend/usb-unix.c b/backend/usb-unix.c index d91610f62..2eaa50603 100644 --- a/backend/usb-unix.c +++ b/backend/usb-unix.c @@ -283,7 +283,20 @@ decode_device_id(int port, /* I - Port number */ if (attr) { - if (strncasecmp(attr, "Hewlett-Packard ", 16) == 0) + /* + * Use description... + */ + + if (!strncasecmp(attr, "Hewlett-Packard hp ", 19)) + { + /* + * Check for a common HP bug... + */ + + strlcpy(make_model, "HP ", mmsize); + strlcpy(make_model + 3, attr + 19, mmsize - 3); + } + else if (!strncasecmp(attr, "Hewlett-Packard ", 16)) { strlcpy(make_model, "HP ", mmsize); strlcpy(make_model + 3, attr + 16, mmsize - 3); @@ -292,9 +305,6 @@ decode_device_id(int port, /* I - Port number */ { strlcpy(make_model, attr, mmsize); } - - if ((delim = strchr(make_model, ';')) != NULL) - *delim = '\0'; } else if (mfg && mdl) { @@ -302,16 +312,31 @@ decode_device_id(int port, /* I - Port number */ * Build a make-model string from the manufacturer and model attributes... */ - strlcpy(make_model, mfg, mmsize); + if (!strncasecmp(mfg, "Hewlett-Packard", 15)) + strlcpy(make_model, "HP", mmsize); + else + strlcpy(make_model, mfg, mmsize); if ((delim = strchr(make_model, ';')) != NULL) *delim = '\0'; - strlcat(make_model, " ", mmsize); - strlcat(make_model, mdl, mmsize); + if (!strncasecmp(make_model, mdl, strlen(make_model))) + { + /* + * Just copy model string, since it has the manufacturer... + */ - if ((delim = strchr(make_model, ';')) != NULL) - *delim = '\0'; + strlcpy(make_model, mdl, mmsize); + } + else + { + /* + * Concatenate the make and model... + */ + + strlcat(make_model, " ", mmsize); + strlcat(make_model, mdl, mmsize); + } } else { @@ -322,6 +347,9 @@ decode_device_id(int port, /* I - Port number */ strlcpy(make_model, "Unknown", mmsize); } + if ((delim = strchr(make_model, ';')) != NULL) + *delim = '\0'; + /* * Look for the serial number field... */ @@ -333,26 +361,6 @@ decode_device_id(int port, /* I - Port number */ else if ((attr = strstr(device_id, ";SN:")) != NULL) attr += 4; - if (mfg) - { - /* - * Make sure manufacturer is truncated at delimiter... - */ - - if ((delim = strchr(mfg, ';')) != NULL) - *delim = '\0'; - } - - if (mdl) - { - /* - * Make sure model is truncated at delimiter... - */ - - if ((delim = strchr(mdl, ';')) != NULL) - *delim = '\0'; - } - if (attr) { strlcpy(serial_number, attr, sizeof(serial_number)); diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c index 0e483866f..8f6c338c9 100644 --- a/cgi-bin/admin.c +++ b/cgi-bin/admin.c @@ -2691,12 +2691,25 @@ do_menu(http_t *http, /* I - HTTP connection */ *options_ptr++ = *ptr; else if (*ptr == ' ') *options_ptr++ = '_'; - + + /* + * Then add the make and model in the printer info, so + * that MacOS clients see something reasonable... + */ + + strlcpy(options_ptr, "&PRINTER_LOCATION=&PRINTER_INFO=", + sizeof(options) - (options_ptr - options)); + options_ptr += strlen(options_ptr); + + form_encode(options_ptr, device_make_and_model, + sizeof(options) - (options_ptr - options)); + options_ptr += strlen(options_ptr); + /* * Then copy the device URI... */ - strlcpy(options_ptr, "&PRINTER_LOCATION=&PRINTER_INFO=&DEVICE_URI=", + strlcpy(options_ptr, "&DEVICE_URI=", sizeof(options) - (options_ptr - options)); options_ptr += strlen(options_ptr); diff --git a/doc/images/accept-jobs.gif b/doc/images/accept-jobs.gif index 9da7a0dce..e0f46d921 100644 Binary files a/doc/images/accept-jobs.gif and b/doc/images/accept-jobs.gif differ diff --git a/doc/images/reject-jobs.gif b/doc/images/reject-jobs.gif index 6d938e308..23dfa99c0 100644 Binary files a/doc/images/reject-jobs.gif and b/doc/images/reject-jobs.gif differ diff --git a/scheduler/Makefile b/scheduler/Makefile index d3f659f31..cd23dbd1e 100644 --- a/scheduler/Makefile +++ b/scheduler/Makefile @@ -24,14 +24,20 @@ include ../Makedefs -CUPSDOBJS = auth.o banners.o cert.o classes.o client.o conf.o devices.o \ +CUPSDOBJS = auth.o banners.o cert.o classes.o client.o conf.o \ dirsvc.o main.o ipp.o listen.o job.o log.o network.o \ policy.o ppds.o printers.o process.o quotas.o server.o \ statbuf.o subscriptions.o MIMEOBJS = filter.o mime.o type.o -OBJS = $(CUPSDOBJS) $(MIMEOBJS) cups-lpd.o cups-polld.o testmime.o \ +OBJS = $(CUPSDOBJS) $(MIMEOBJS) \ + cups-deviced.o util.o \ + cups-lpd.o \ + cups-polld.o \ + testmime.o \ testspeed.o -TARGETS = cupsd cups-lpd cups-polld libmime.a testmime testspeed +TARGETS = cupsd cups-deviced cups-lpd cups-polld libmime.a \ + testmime testspeed + # # Make everything... @@ -65,6 +71,7 @@ install: all $(INSTALL_DIR) $(SBINDIR) $(INSTALL_BIN) cupsd $(SBINDIR) $(INSTALL_DIR) $(SERVERBIN)/daemon + $(INSTALL_BIN) cups-deviced $(SERVERBIN)/daemon $(INSTALL_BIN) cups-lpd $(SERVERBIN)/daemon $(INSTALL_BIN) cups-polld $(SERVERBIN)/daemon $(INSTALL_DIR) -m 711 -o $(CUPS_USER) -g $(CUPS_GROUP) $(SERVERROOT)/certs @@ -86,6 +93,15 @@ cupsd: $(CUPSDOBJS) libmime.a ../cups/$(LIBCUPS) $(LIBPAPER) $(LIBMALLOC) +# +# Make the device daemon, "cups-deviced". +# + +cups-deviced: cups-deviced.o util.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o cups-deviced cups-deviced.o util.o $(LIBS) + + # # Make the line printer daemon, "cups-lpd". # diff --git a/scheduler/client.c b/scheduler/client.c index 4f913da1a..7afd0d19c 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -1967,12 +1967,12 @@ ReadClient(client_t *con) /* I - Client to read from */ * 'SendCommand()' - Send output from a command via HTTP. */ -int -SendCommand(client_t *con, - char *command, - char *options) +int /* O - 1 on success, 0 on failure */ +SendCommand(client_t *con, /* I - Client connection */ + char *command, /* I - Command to run */ + char *options) /* I - Command-line options */ { - int fd; + int fd; /* Standard input file descriptor */ if (con->filename) @@ -2940,6 +2940,7 @@ pipe_command(client_t *con, /* I - Client connection */ char content_length[1024], /* CONTENT_LENGTH environment variable */ content_type[1024], /* CONTENT_TYPE environment variable */ cups_datadir[1024], /* CUPS_DATADIR environment variable */ + cups_serverbin[1024], /* CUPS_SERVERBIN environment variable */ cups_serverroot[1024], /* CUPS_SERVERROOT environment variable */ cups_statedir[1024], /* CUPS_STATEDIR environment variable */ http_cookie[1024], /* HTTP_COOKIE environment variable */ @@ -3141,6 +3142,7 @@ pipe_command(client_t *con, /* I - Client connection */ snprintf(remote_user, sizeof(remote_user), "REMOTE_USER=%s", con->username); snprintf(tmpdir, sizeof(tmpdir), "TMPDIR=%s", TempDir); snprintf(cups_datadir, sizeof(cups_datadir), "CUPS_DATADIR=%s", DataDir); + snprintf(cups_serverbin, sizeof(cups_serverbin), "CUPS_SERVERBIN=%s", ServerBin); snprintf(cups_serverroot, sizeof(cups_serverroot), "CUPS_SERVERROOT=%s", ServerRoot); snprintf(cups_statedir, sizeof(cups_statedir), "CUPS_STATEDIR=%s", StateDir); @@ -3168,6 +3170,7 @@ pipe_command(client_t *con, /* I - Client connection */ envp[envc ++] = TZ; envp[envc ++] = tmpdir; envp[envc ++] = cups_datadir; + envp[envc ++] = cups_serverbin; envp[envc ++] = cups_serverroot; envp[envc ++] = cups_statedir; diff --git a/scheduler/conf.c b/scheduler/conf.c index 325043acc..b04f9072c 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -786,12 +786,6 @@ ReadConfiguration(void) DefaultPrinter = NULL; - if (Devices) - { - ippDelete(Devices); - Devices = NULL; - } - if (PPDs) { ippDelete(PPDs); @@ -862,9 +856,6 @@ ReadConfiguration(void) * Load devices and PPDs... */ - snprintf(temp, sizeof(temp), "%s/backend", ServerBin); - LoadDevices(temp); - snprintf(temp, sizeof(temp), "%s/model", DataDir); LoadPPDs(temp); diff --git a/scheduler/cups-deviced.c b/scheduler/cups-deviced.c new file mode 100644 index 000000000..c5c6fee29 --- /dev/null +++ b/scheduler/cups-deviced.c @@ -0,0 +1,420 @@ +/* + * "$Id$" + * + * Device scanning mini-daemon for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + */ + +/* + * Include necessary headers... + */ + +#include "util.h" + + +/* + * Device information structure... + */ + +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 */ +} dev_info_t; + + +/* + * Local globals... + */ + +static int alarm_tripped; /* Non-zero if alarm was tripped */ +static int num_devs, /* Number of devices */ + alloc_devs; /* Number of allocated entries */ +static dev_info_t *devs; /* Device info */ + + +/* + * Local functions... + */ + +static dev_info_t *add_dev(const char *device_class, + const char *device_make_and_model, + const char *device_info, + const char *device_uri); +static int compare_devs(const dev_info_t *p0, + const dev_info_t *p1); +static void sigalrm_handler(int sig); + + +/* + * 'main()' - Scan for devices and return an IPP response. + * + * Usage: + * + * cups-deviced request_id limit + */ + +int /* O - Exit code */ +main(int argc, /* I - Number of command-line args */ + char *argv[]) /* I - Command-line arguments */ +{ + const char *server_bin; /* CUPS_SERVERBIN environment variable */ + char backends[1024]; /* Location of backends */ + int count; /* Number of devices from backend */ + int compat; /* Compatibility device? */ + FILE *fp; /* Pipe to device backend */ + DIR *dir; /* Directory pointer */ + DIRENT *dent; /* Directory entry */ + char filename[1024], /* Name of backend */ + line[2048], /* Line from backend */ + dclass[64], /* Device class */ + uri[1024], /* Device URI */ + info[128], /* Device info */ + make_model[256]; /* Make and model */ + dev_info_t *dev; /* Current device */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + /* + * Check the command-line... + */ + + if (argc != 3) + { + fputs("Usage: cups-deviced request_id limit\n", stderr); + return (1); + } + + /* + * Try opening the backend directory... + */ + + if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL) + server_bin = CUPS_SERVERBIN; + + snprintf(backends, sizeof(backends), "%s/backend", server_bin); + + if ((dir = opendir(backends)) == NULL) + { + fprintf(stderr, "ERROR: [cups-deviced] Unable to open backend directory \"%s\": %s", + backends, strerror(errno)); + return (1); + } + + /* + * Setup the devices array... + */ + + alloc_devs = 0; + num_devs = 0; + devs = (dev_info_t *)0; + + /* + * Loop through all of the device backends... + */ + + while ((dent = readdir(dir)) != NULL) + { + /* + * Skip "." and ".."... + */ + + if (dent->d_name[0] == '.') + continue; + + /* + * Run the backend with no arguments and collect the output... + */ + + snprintf(filename, sizeof(filename), "%s/%s", backends, dent->d_name); + if ((fp = popen(filename, "r")) != NULL) + { + /* + * Set an alarm for the first read from the backend; this avoids + * problems when a backend is hung getting device information. + */ + +#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ + sigset(SIGALRM, sigalrm_handler); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, SIGALRM); + action.sa_handler = sigalrm_handler; + sigaction(SIGALRM, &action, NULL); +#else + signal(SIGALRM, sigalrm_handler); +#endif /* HAVE_SIGSET */ + + alarm_tripped = 0; + count = 0; + compat = !strcmp(dent->d_name, "smb"); + + alarm(30); + + while (fgets(line, sizeof(line), fp) != NULL) + { + /* + * Reset the alarm clock... + */ + + alarm(30); + + /* + * Each line is of the form: + * + * class URI "make model" "name" + */ + + if (!strncasecmp(line, "Usage", 5)) + compat = 1; + else if (sscanf(line, "%63s%1023s%*[ \t]\"%255[^\"]\"%*[ \t]\"%127[^\"]", + dclass, uri, make_model, info) != 4) + { + /* + * Bad format; strip trailing newline and write an error message. + */ + + if (line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = '\0'; + + fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n", + dent->d_name, line); + compat = 1; + break; + } + else + { + /* + * Add the device to the array of available devices... + */ + + dev = add_dev(dclass, make_model, info, uri); + if (!dev) + { + closedir(dir); + return (1); + } + + fprintf(stderr, "DEBUG: [cups-deviced] Added device \"%s\"...\n", uri); + count ++; + } + } + + /* + * Turn the alarm clock off and close the pipe to the command... + */ + + alarm(0); + + if (alarm_tripped) + fprintf(stderr, "WARNING: [cups-deviced] Backend \"%s\" did not respond within 30 seconds!\n", + dent->d_name); + + pclose(fp); + + /* + * Hack for backends that don't support the CUPS 1.1 calling convention: + * add a network device with the method == backend name. + */ + + if (count == 0 && compat) + { + snprintf(line, sizeof(line), "Unknown Network Device (%s)", + dent->d_name); + + dev = add_dev("network", line, "Unknown", dent->d_name); + if (!dev) + { + closedir(dir); + return (1); + } + + fprintf(stderr, "DEBUG: [cups-deviced] Compatibility device \"%s\"...\n", + dent->d_name); + } + } + else + fprintf(stderr, "WARNING: [cups-deviced] Unable to execute \"%s\" backend: %s\n", + dent->d_name, strerror(errno)); + } + + closedir(dir); + + /* + * Sort the available devices... + */ + + if (num_devs > 1) + qsort(devs, num_devs, sizeof(dev_info_t), + (int (*)(const void *, const void *))compare_devs); + + /* + * Output the list of devices... + */ + + puts("Content-Type: application/ipp\n"); + + cupsdSendIPPHeader(IPP_OK, atoi(argv[1])); + cupsdSendIPPGroup(IPP_TAG_OPERATION); + cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); + cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US"); + + if ((count = atoi(argv[2])) <= 0) + count = num_devs; + + if (count > num_devs) + count = num_devs; + + for (dev = devs; count > 0; count --, dev ++) + { + /* + * Add strings to attributes... + */ + + cupsdSendIPPGroup(IPP_TAG_PRINTER); + cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class", dev->device_class); + cupsdSendIPPString(IPP_TAG_TEXT, "device-info", dev->device_info); + cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model", + dev->device_make_and_model); + cupsdSendIPPString(IPP_TAG_URI, "device-uri", dev->device_uri); + } + + cupsdSendIPPTrailer(); + + /* + * Free the devices array and return... + */ + + if (alloc_devs) + free(devs); + + return (0); +} + + +/* + * 'add_dev()' - Add a new device to the list. + */ + +static dev_info_t * /* O - New device or NULL on error */ +add_dev( + const char *device_class, /* I - Device class */ + 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 */ +{ + dev_info_t *dev; /* New device */ + + + if (num_devs >= alloc_devs) + { + /* + * Allocate (more) memory for the devices... + */ + + if (alloc_devs == 0) + dev = malloc(sizeof(dev_info_t) * 16); + else + dev = realloc(devs, sizeof(dev_info_t) * (alloc_devs + 16)); + + if (dev == NULL) + { + fprintf(stderr, "ERROR: [cups-deviced] Ran out of memory for %d devices!\n", + alloc_devs + 16); + return (NULL); + } + + devs = dev; + alloc_devs += 16; + } + + /* + * Add a new device at the end of the array... + */ + + dev = devs + num_devs; + num_devs ++; + + memset(dev, 0, sizeof(dev_info_t)); + + /* + * Copy the strings and return... + */ + + strlcpy(dev->device_class, device_class, sizeof(dev->device_class)); + strlcpy(dev->device_make_and_model, device_make_and_model, + sizeof(dev->device_make_and_model)); + strlcpy(dev->device_info, device_info, sizeof(dev->device_info)); + strlcpy(dev->device_uri, device_uri, sizeof(dev->device_uri)); + + return (dev); +} + + +/* + * 'compare_devs()' - Compare device names for sorting. + */ + +static int /* O - Result of comparison */ +compare_devs(const dev_info_t *d0, /* I - First device */ + const dev_info_t *d1) /* I - Second device */ +{ + int diff; /* Difference between strings */ + + + /* + * Sort devices by device-info, device-class, and device-uri... + */ + + if ((diff = cupsdCompareNames(d0->device_info, d1->device_info)) != 0) + return (diff); + else if ((diff = strcasecmp(d0->device_class, d1->device_class)) != 0) + return (diff); + else + return (strcasecmp(d0->device_uri, d1->device_uri)); +} + + +/* + * 'sigalrm_handler()' - Handle alarm signals for backends that get hung + * trying to list the available devices... + */ + +static void +sigalrm_handler(int sig) /* I - Signal number */ +{ + (void)sig; /* remove compiler warnings... */ + + alarm_tripped = 1; +} + + +/* + * End of "$Id$". + */ diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h index 5408a6634..5be06f89b 100644 --- a/scheduler/cupsd.h +++ b/scheduler/cupsd.h @@ -188,9 +188,7 @@ VAR int NeedReload VALUE(RELOAD_ALL), VAR char *TZ VALUE(NULL); /* Timezone configuration */ -VAR ipp_t *Devices VALUE(NULL), - /* Available devices */ - *PPDs VALUE(NULL); +VAR ipp_t *PPDs VALUE(NULL); /* Available PPDs */ @@ -202,7 +200,6 @@ extern void CatchChildSignals(void); extern void ClearString(char **s); extern void HoldSignals(void); extern void IgnoreChildSignals(void); -extern void LoadDevices(const char *d); extern void LoadPPDs(const char *d); extern void ReleaseSignals(void); extern void SetString(char **s, const char *v); diff --git a/scheduler/devices.c b/scheduler/devices.c deleted file mode 100644 index 93fb7d47c..000000000 --- a/scheduler/devices.c +++ /dev/null @@ -1,484 +0,0 @@ -/* - * "$Id$" - * - * Device scanning routines for the Common UNIX Printing System (CUPS). - * - * Copyright 1997-2005 by Easy Software Products. - * - * These coded instructions, statements, and computer programs are the - * property of Easy Software Products and are protected by Federal - * copyright law. Distribution and use rights are outlined in the file - * "LICENSE.txt" which should have been included with this file. If this - * file is missing or damaged please contact Easy Software Products - * at: - * - * Attn: CUPS Licensing Information - * Easy Software Products - * 44141 Airport View Drive, Suite 204 - * Hollywood, Maryland 20636 USA - * - * Voice: (301) 373-9600 - * EMail: cups-info@cups.org - * WWW: http://www.cups.org - * - * Contents: - * - * LoadDevices() - Load all available devices. - * compare_devs() - Compare PPD file make and model names for sorting. - * sigalrm_handler() - Handle alarm signals for backends that get hung - */ - -/* - * Include necessary headers... - */ - -#include "cupsd.h" - - -/* - * Device information structure... - */ - -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 */ -} dev_info_t; - - -/* - * Local globals... - */ - -static int num_devs, /* Number of devices */ - alloc_devs; /* Number of allocated entries */ -static dev_info_t *devs; /* Device info */ - - -/* - * Local functions... - */ - -static int compare_devs(const dev_info_t *p0, const dev_info_t *p1); -static void sigalrm_handler(int sig); - - -/* - * 'LoadDevices()' - Load all available devices. - */ - -void -LoadDevices(const char *d) /* I - Directory to scan */ -{ - int i; /* Looping var */ - int count; /* Number of devices from backend */ - int compat; /* Compatibility device? */ - FILE *fp; /* Pipe to device backend */ - DIR *dir; /* Directory pointer */ - DIRENT *dent; /* Directory entry */ - char filename[1024], /* Name of backend */ - line[2048], /* Line from backend */ - dclass[64], /* Device class */ - uri[1024], /* Device URI */ - info[128], /* Device info */ - make_model[256];/* Make and model */ - dev_info_t *dev; /* Current device */ -#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ -#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ - - - /* - * Initialize the device list. - */ - - Devices = ippNew(); - - /* - * Try opening the backend directory... - */ - - if ((dir = opendir(d)) == NULL) - { - LogMessage(L_ERROR, "LoadDevices: Unable to open backend directory \"%s\": %s", - d, strerror(errno)); - return; - } - - /* - * Setup the devices array... - */ - - alloc_devs = 0; - num_devs = 0; - devs = (dev_info_t *)0; - - /* - * Ignore child signals... - */ - - IgnoreChildSignals(); - - /* - * Loop through all of the device backends... - */ - - while ((dent = readdir(dir)) != NULL) - { - /* - * Skip "." and ".."... - */ - - if (dent->d_name[0] == '.') - continue; - - /* - * Run the backend with no arguments and collect the output... - */ - - snprintf(filename, sizeof(filename), "%s/%s", d, dent->d_name); - if ((fp = popen(filename, "r")) != NULL) - { - /* - * Set an alarm for the first read from the backend; this avoids - * problems when a backend is hung getting device information. - */ - -#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ - sigset(SIGALRM, sigalrm_handler); -#elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - - sigemptyset(&action.sa_mask); - sigaddset(&action.sa_mask, SIGALRM); - action.sa_handler = sigalrm_handler; - sigaction(SIGALRM, &action, NULL); -#else - signal(SIGALRM, sigalrm_handler); -#endif /* HAVE_SIGSET */ - - alarm(30); - count = 0; - compat = strcmp(dent->d_name, "smb") == 0; - - while (fgets(line, sizeof(line), fp) != NULL) - { - /* - * Reset the alarm clock... - */ - - alarm(30); - - /* - * Each line is of the form: - * - * class URI "make model" "name" - */ - - if (strncasecmp(line, "Usage", 5) == 0) - compat = 1; - else if (sscanf(line, "%63s%1023s%*[ \t]\"%255[^\"]\"%*[ \t]\"%127[^\"]", - dclass, uri, make_model, info) != 4) - { - /* - * Bad format; strip trailing newline and write an error message. - */ - - if (line[strlen(line) - 1] == '\n') - line[strlen(line) - 1] = '\0'; - - LogMessage(L_ERROR, "LoadDevices: Bad line from \"%s\": %s", - dent->d_name, line); - compat = 1; - break; - } - else - { - /* - * Add the device to the array of available devices... - */ - - if (num_devs >= alloc_devs) - { - /* - * Allocate (more) memory for the devices... - */ - - if (alloc_devs == 0) - dev = malloc(sizeof(dev_info_t) * 16); - else - dev = realloc(devs, sizeof(dev_info_t) * (alloc_devs + 16)); - - if (dev == NULL) - { - LogMessage(L_ERROR, "LoadDevices: Ran out of memory for %d devices!", - alloc_devs + 16); - closedir(dir); - return; - } - - devs = dev; - alloc_devs += 16; - } - - dev = devs + num_devs; - num_devs ++; - - memset(dev, 0, sizeof(dev_info_t)); - strlcpy(dev->device_class, dclass, sizeof(dev->device_class)); - strlcpy(dev->device_info, info, sizeof(dev->device_info)); - strlcpy(dev->device_make_and_model, make_model, - sizeof(dev->device_make_and_model)); - strlcpy(dev->device_uri, uri, sizeof(dev->device_uri)); - - LogMessage(L_DEBUG, "LoadDevices: Added device \"%s\"...", uri); - count ++; - } - } - - /* - * Turn the alarm clock off and close the pipe to the command... - */ - - alarm(0); - - pclose(fp); - - /* - * Hack for backends that don't support the CUPS 1.1 calling convention: - * add a network device with the method == backend name. - */ - - if (count == 0 && compat) - { - if (num_devs >= alloc_devs) - { - /* - * Allocate (more) memory for the devices... - */ - - if (alloc_devs == 0) - dev = malloc(sizeof(dev_info_t) * 16); - else - dev = realloc(devs, sizeof(dev_info_t) * (alloc_devs + 16)); - - if (dev == NULL) - { - LogMessage(L_ERROR, "LoadDevices: Ran out of memory for %d devices!", - alloc_devs + 16); - closedir(dir); - return; - } - - devs = dev; - alloc_devs += 16; - } - - dev = devs + num_devs; - num_devs ++; - - memset(dev, 0, sizeof(dev_info_t)); - strcpy(dev->device_class, "network"); - snprintf(dev->device_info, sizeof(dev->device_info), - "Unknown Network Device (%s)", dent->d_name); - strcpy(dev->device_make_and_model, "Unknown"); - strlcpy(dev->device_uri, dent->d_name, sizeof(dev->device_uri)); - - LogMessage(L_DEBUG, "LoadDevices: Compatibility device \"%s\"...", - dent->d_name); - } - } - else - LogMessage(L_WARN, "LoadDevices: Unable to execute \"%s\" backend: %s", - dent->d_name, strerror(errno)); - } - - closedir(dir); - - /* - * Catch child signals... - */ - - CatchChildSignals(); - - /* - * Sort the available devices... - */ - - if (num_devs > 1) - qsort(devs, num_devs, sizeof(dev_info_t), - (int (*)(const void *, const void *))compare_devs); - - /* - * Create the list of devices... - */ - - for (i = num_devs, dev = devs; i > 0; i --, dev ++) - { - /* - * Add strings to attributes... - */ - - if (i < num_devs) - ippAddSeparator(Devices); - - ippAddString(Devices, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "device-class", NULL, dev->device_class); - ippAddString(Devices, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "device-info", NULL, dev->device_info); - ippAddString(Devices, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "device-make-and-model", NULL, dev->device_make_and_model); - ippAddString(Devices, IPP_TAG_PRINTER, IPP_TAG_URI, - "device-uri", NULL, dev->device_uri); - } - - /* - * Free the devices array... - */ - - if (alloc_devs) - free(devs); -} - - -/* - * 'compare_devs()' - Compare device names for sorting. - */ - -static int /* O - Result of comparison */ -compare_devs(const dev_info_t *d0, /* I - First device */ - const dev_info_t *d1) /* I - Second device */ -{ - const char *s, /* First name */ - *t; /* Second name */ - int diff, /* Difference between digits */ - digits; /* Number of digits */ - - - /* - * First compare names... - */ - - s = d0->device_info; - t = d1->device_info; - - /* - * Loop through both nicknames, returning only when a difference is - * seen. Also, compare whole numbers rather than just characters, too! - */ - - while (*s && *t) - { - if (isdigit(*s & 255) && isdigit(*t & 255)) - { - /* - * Got a number; start by skipping leading 0's... - */ - - while (*s == '0') - s ++; - while (*t == '0') - t ++; - - /* - * Skip equal digits... - */ - - while (isdigit(*s & 255) && *s == *t) - { - s ++; - t ++; - } - - /* - * Bounce out if *s and *t aren't both digits... - */ - - if (isdigit(*s & 255) && !isdigit(*t & 255)) - return (1); - else if (!isdigit(*s & 255) && isdigit(*t & 255)) - return (-1); - else if (!isdigit(*s & 255) || !isdigit(*t & 255)) - continue; - - if (*s < *t) - diff = -1; - else - diff = 1; - - /* - * Figure out how many more digits there are... - */ - - digits = 0; - s ++; - t ++; - - while (isdigit(*s & 255)) - { - digits ++; - s ++; - } - - while (isdigit(*t & 255)) - { - digits --; - t ++; - } - - /* - * Return if the number or value of the digits is different... - */ - - if (digits < 0) - return (-1); - else if (digits > 0) - return (1); - else if (diff) - return (diff); - } - else if (tolower(*s) < tolower(*t)) - return (-1); - else if (tolower(*s) > tolower(*t)) - return (1); - else - { - s ++; - t ++; - } - } - - /* - * Return the results of the final comparison... - */ - - if (*s) - return (1); - else if (*t) - return (-1); - else if ((diff = strcasecmp(d0->device_class, d1->device_class)) != 0) - return (diff); - else - return (strcasecmp(d0->device_uri, d1->device_uri)); -} - - -/* - * 'sigalrm_handler()' - Handle alarm signals for backends that get hung - * trying to list the available devices... - */ - -static void -sigalrm_handler(int sig) /* I - Signal number */ -{ - (void)sig; /* remove compiler warnings... */ - - LogMessage(L_WARN, "LoadDevices: Backend did not respond within 30 seconds!"); -} - - -/* - * End of "$Id$". - */ diff --git a/scheduler/ipp.c b/scheduler/ipp.c index c7aae01a3..d3f0e6a12 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -554,45 +554,61 @@ ProcessIPPRequest(client_t *con) /* I - Client connection */ } } - LogMessage(L_DEBUG, "ProcessIPPRequest: %d status_code=%x (%s)", - con->http.fd, con->response->request.status.status_code, - ippErrorString(con->response->request.status.status_code)); - - if (SendHeader(con, HTTP_OK, "application/ipp")) + if (con->response) { - if (con->http.version == HTTP_1_1) - { - con->http.data_encoding = HTTP_ENCODE_CHUNKED; + /* + * Sending data from the scheduler... + */ - httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n\r\n"); - } - else + LogMessage(L_DEBUG, "ProcessIPPRequest: %d status_code=%x (%s)", + con->http.fd, con->response->request.status.status_code, + ippErrorString(con->response->request.status.status_code)); + + if (SendHeader(con, HTTP_OK, "application/ipp")) { - con->http.data_encoding = HTTP_ENCODE_LENGTH; - con->http.data_remaining = ippLength(con->response); + if (con->http.version == HTTP_1_1) + { + con->http.data_encoding = HTTP_ENCODE_CHUNKED; - httpPrintf(HTTP(con), "Content-Length: %d\r\n\r\n", - con->http.data_remaining); - } + httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n\r\n"); + } + else + { + con->http.data_encoding = HTTP_ENCODE_LENGTH; + con->http.data_remaining = ippLength(con->response); - LogMessage(L_DEBUG2, "ProcessIPPRequest: Adding fd %d to OutputSet...", - con->http.fd); + httpPrintf(HTTP(con), "Content-Length: %d\r\n\r\n", + con->http.data_remaining); + } - FD_SET(con->http.fd, OutputSet); + LogMessage(L_DEBUG2, "ProcessIPPRequest: Adding fd %d to OutputSet...", + con->http.fd); - /* - * Tell the caller the response header was sent successfully... - */ + FD_SET(con->http.fd, OutputSet); - return (1); + /* + * Tell the caller the response header was sent successfully... + */ + + return (1); + } + else + { + /* + * Tell the caller the response header could not be sent... + */ + + return (0); + } } else { /* - * Tell the caller the response header could not be sent... + * Sending data from a subprocess like cups-deviced; tell the caller + * everything is A-OK so far... */ - return (0); + return (1); } } @@ -1517,6 +1533,7 @@ add_printer(client_t *con, /* I - Client connection */ * See if the backend is listed as a device... */ +#if 0 /* ADD THIS BACK IN SOMEHOW */ for (device = ippFindAttribute(Devices, "device-uri", IPP_TAG_URI); device != NULL; device = ippFindNextAttribute(Devices, "device-uri", IPP_TAG_URI)) @@ -1536,6 +1553,7 @@ add_printer(client_t *con, /* I - Client connection */ send_ipp_error(con, IPP_NOT_POSSIBLE); return; } +#endif /* 0 */ } LogMessage(L_INFO, "Setting %s device-uri to \"%s\" (was \"%s\".)", @@ -3352,8 +3370,6 @@ create_job(client_t *con, /* I - Client connection */ * Also, we can only have 1 value and it must be a name value. */ - int i; /* Looping var */ - switch (attr->value_tag) { case IPP_TAG_STRING : @@ -3841,6 +3857,11 @@ get_default(client_t *con) /* I - Client connection */ static void get_devices(client_t *con) /* I - Client connection */ { + ipp_attribute_t *limit; /* Limit attribute */ + char command[1024], /* cups-deviced command */ + options[1024]; /* Options to pass to command */ + + LogMessage(L_DEBUG2, "get_devices(%p[%d])\n", con, con->http.fd); /* @@ -3855,15 +3876,34 @@ get_devices(client_t *con) /* I - Client connection */ } /* - * Copy the device attributes to the response using the requested-attributes - * attribute that may be provided by the client. + * Run cups-deviced command with the given options... */ - copy_attrs(con->response, Devices, - ippFindAttribute(con->request, "requested-attributes", - IPP_TAG_KEYWORD), IPP_TAG_ZERO, IPP_TAG_COPY); + limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER); - con->response->request.status.status_code = IPP_OK; + snprintf(command, sizeof(command), "%s/daemon/cups-deviced", ServerBin); + snprintf(options, sizeof(options), "cups-deviced %d+%d", + con->request->request.op.request_id, + limit ? limit->values[0].integer : 0); + + if (SendCommand(con, command, options)) + { + /* + * Command started successfully, don't send an IPP response here... + */ + + ippDelete(con->response); + con->response = NULL; + } + else + { + /* + * Command failed, return "internal error" so the user knows something + * went wrong... + */ + + send_ipp_error(con, IPP_INTERNAL_ERROR); + } } @@ -5369,8 +5409,6 @@ print_job(client_t *con, /* I - Client connection */ * Also, we can only have 1 value and it must be a name value. */ - int i; /* Looping var */ - switch (attr->value_tag) { case IPP_TAG_STRING : diff --git a/scheduler/job.c b/scheduler/job.c index d905c0681..2887a6398 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -1363,6 +1363,7 @@ StartJob(int id, /* I - Job ID */ class_name[255], /* CLASS environment variable */ printer_name[255], /* PRINTER environment variable */ root[1024], /* CUPS_SERVERROOT environment variable */ + cups_serverbin[1024], /* CUPS_SERVERBIN environment variable */ cups_statedir[1024], /* CUPS_STATEDIR environment variable */ cache[255], /* RIP_MAX_CACHE environment variable */ tmpdir[1024], /* TMPDIR environment variable */ @@ -1879,6 +1880,7 @@ StartJob(int id, /* I - Job ID */ snprintf(printer_name, sizeof(printer_name), "PRINTER=%s", printer->name); snprintf(cache, sizeof(cache), "RIP_MAX_CACHE=%s", RIPCache); snprintf(root, sizeof(root), "CUPS_SERVERROOT=%s", ServerRoot); + snprintf(cups_serverbin, sizeof(cups_serverbin), "CUPS_SERVERBIN=%s", ServerBin); snprintf(cups_statedir, sizeof(cups_statedir), "CUPS_STATEDIR=%s", StateDir); snprintf(tmpdir, sizeof(tmpdir), "TMPDIR=%s", TempDir); snprintf(datadir, sizeof(datadir), "CUPS_DATADIR=%s", DataDir); @@ -1895,6 +1897,7 @@ StartJob(int id, /* I - Job ID */ if (TZ && TZ[0]) envp[envc ++] = TZ; envp[envc ++] = ppd; + envp[envc ++] = cups_serverbin; envp[envc ++] = root; envp[envc ++] = cups_statedir; envp[envc ++] = cache; diff --git a/scheduler/util.c b/scheduler/util.c new file mode 100644 index 000000000..bdb16db63 --- /dev/null +++ b/scheduler/util.c @@ -0,0 +1,280 @@ +/* + * "$Id$" + * + * Mini-daemon utility functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdSendIPPGroup() - Send a group tag. + * cupsdSendIPPHeader() - Send the IPP response header. + * cupsdSendIPPInteger() - Send an integer attribute. + * cupsdSendIPPString() - Send a string attribute. + * cupsdSendIPPTrailer() - Send the end-of-message tag. + */ + +/* + * Include necessary headers... + */ + +#include "util.h" + + +/* + * 'cupsdCompareNames()' - Compare two names. + * + * This function basically does a strcasecmp() of the two strings, + * but is also aware of numbers so that "a2" < "a100". + */ + +int /* O - Result of comparison */ +cupsdCompareNames(const char *s, /* I - First string */ + const char *t) /* I - Second string */ +{ + int diff, /* Difference between digits */ + digits; /* Number of digits */ + + + /* + * Loop through both names, returning only when a difference is + * seen. Also, compare whole numbers rather than just characters, too! + */ + + while (*s && *t) + { + if (isdigit(*s & 255) && isdigit(*t & 255)) + { + /* + * Got a number; start by skipping leading 0's... + */ + + while (*s == '0') + s ++; + while (*t == '0') + t ++; + + /* + * Skip equal digits... + */ + + while (isdigit(*s & 255) && *s == *t) + { + s ++; + t ++; + } + + /* + * Bounce out if *s and *t aren't both digits... + */ + + if (isdigit(*s & 255) && !isdigit(*t & 255)) + return (1); + else if (!isdigit(*s & 255) && isdigit(*t & 255)) + return (-1); + else if (!isdigit(*s & 255) || !isdigit(*t & 255)) + continue; + + if (*s < *t) + diff = -1; + else + diff = 1; + + /* + * Figure out how many more digits there are... + */ + + digits = 0; + s ++; + t ++; + + while (isdigit(*s & 255)) + { + digits ++; + s ++; + } + + while (isdigit(*t & 255)) + { + digits --; + t ++; + } + + /* + * Return if the number or value of the digits is different... + */ + + if (digits < 0) + return (-1); + else if (digits > 0) + return (1); + else if (diff) + return (diff); + } + else if (tolower(*s) < tolower(*t)) + return (-1); + else if (tolower(*s) > tolower(*t)) + return (1); + else + { + s ++; + t ++; + } + } + + /* + * Return the results of the final comparison... + */ + + if (*s) + return (1); + else if (*t) + return (-1); + else + return (0); +} + + +/* + * 'cupsdSendIPPGroup()' - Send a group tag. + */ + +void +cupsdSendIPPGroup(ipp_tag_t group_tag) /* I - Group tag */ +{ + /* + * Send IPP group tag (1 byte)... + */ + + putchar(group_tag); +} + + +/* + * 'cupsdSendIPPHeader()' - Send the IPP response header. + */ + +void +cupsdSendIPPHeader( + ipp_status_t status_code, /* I - Status code */ + int request_id) /* I - Request ID */ +{ + /* + * Send IPP/1.1 response header: version number (2 bytes), status code + * (4 bytes), and request ID (4 bytes)... + */ + + putchar(1); + putchar(1); + + putchar(status_code >> 24); + putchar(status_code >> 16); + putchar(status_code >> 8); + putchar(status_code); + + putchar(request_id >> 24); + putchar(request_id >> 16); + putchar(request_id >> 8); + putchar(request_id); +} + + +/* + * 'cupsdSendIPPInteger()' - Send an integer attribute. + */ + +void +cupsdSendIPPInteger( + ipp_tag_t value_tag, /* I - Value tag */ + const char *name, /* I - Attribute name */ + int value) /* I - Attribute value */ +{ + size_t len; /* Length of attribute name */ + + + /* + * Send IPP integer value: value tag (1 byte), name length (2 bytes), + * name string (without nul), and value (4 bytes)... + */ + + putchar(value_tag); + + len = strlen(name); + putchar(len >> 8); + putchar(len); + + fputs(name, stdout); + + putchar(value >> 24); + putchar(value >> 16); + putchar(value >> 8); + putchar(value); +} + + +/* + * 'cupsdSendIPPString()' - Send a string attribute. + */ + +void +cupsdSendIPPString( + ipp_tag_t value_tag, /* I - Value tag */ + const char *name, /* I - Attribute name */ + const char *value) /* I - Attribute value */ +{ + size_t len; /* Length of attribute name */ + + + /* + * Send IPP string value: value tag (1 byte), name length (2 bytes), + * name string (without nul), value length (2 bytes), and value string + * (without nul)... + */ + + putchar(value_tag); + + len = strlen(name); + putchar(len >> 8); + putchar(len); + + fputs(name, stdout); + + len = strlen(value); + putchar(len >> 8); + putchar(len); + + fputs(value, stdout); +} + + +/* + * 'cupsdSendIPPTrailer()' - Send the end-of-message tag. + */ + +void +cupsdSendIPPTrailer(void) +{ + putchar(IPP_TAG_END); + fflush(stdout); +} + + +/* + * End of "$Id$". + */ diff --git a/scheduler/util.h b/scheduler/util.h new file mode 100644 index 000000000..f9d8cc829 --- /dev/null +++ b/scheduler/util.h @@ -0,0 +1,76 @@ +/* + * "$Id$" + * + * Mini-daemon utility definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPSD_UTIL_H_ +# define _CUPSD_UTIL_H_ + +/* + * Include necessary headers... + */ + +# include +# include +# include +# include +# include +# include + +# if HAVE_DIRENT_H +# include +typedef struct dirent DIRENT; +# define NAMLEN(dirent) strlen((dirent)->d_name) +# else +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +typedef struct direct DIRENT; +# define NAMLEN(dirent) (dirent)->d_namlen +# endif /* HAVE_DIRENT_H */ + + +/* + * Prototypes... + */ + +extern int cupsdCompareNames(const char *s, const char *t); +extern void cupsdSendIPPGroup(ipp_tag_t group_tag); +extern void cupsdSendIPPHeader(ipp_status_t status_code, int request_id); +extern void cupsdSendIPPInteger(ipp_tag_t value_tag, const char *name, + int value); +extern void cupsdSendIPPString(ipp_tag_t value_tag, const char *name, + const char *value); +extern void cupsdSendIPPTrailer(void); + + +#endif /* !_CUPSD_UTIL_H_ */ + +/* + * End of "$Id$". + */ diff --git a/test/run-stp-tests.sh b/test/run-stp-tests.sh index d20d16bf4..d83b165f5 100755 --- a/test/run-stp-tests.sh +++ b/test/run-stp-tests.sh @@ -200,6 +200,7 @@ ln -s $root/backend/serial /tmp/$user/bin/backend ln -s $root/backend/socket /tmp/$user/bin/backend ln -s $root/backend/usb /tmp/$user/bin/backend ln -s $root/cgi-bin /tmp/$user/bin +ln -s $root/scheduler /tmp/$user/bin/daemon ln -s $root/filter/hpgltops /tmp/$user/bin/filter ln -s $root/filter/imagetops /tmp/$user/bin/filter ln -s $root/filter/imagetoraster /tmp/$user/bin/filter