CHANGES IN CUPS V1.3.8
- Documentation updates (STR #2785)
- - The scheduler did not reject requests with an empty
- Content-Length field (STR #2787)
+ - The scheduler now ensures that the RSS directory has
+ the correct permissions.
+ - The RSS notifier did not quote the feed URL in the RSS
+ file it created (STR #2801)
- The web interface allowed the creation and cancellation
of RSS subscriptions without a username (STR #2774)
+ - Increased the default MaxCopies value on Mac OS X to
+ 9999 to match the limit imposed by the print dialog.
+ - The scheduler did not reject requests with an empty
+ Content-Length field (STR #2787)
- The PNG image loading code would crash with large images
(STR #2790)
- The scheduler did not log the current date and time and
-CHANGES.txt - 2008-04-08
+CHANGES.txt - 2008-04-14
------------------------
CHANGES IN CUPS V1.4b1
+ - The CUPS-Get-Devices operation now supports the
+ exclude-schemes and timeout attributes to control which
+ backends are polled and for how long.
+ - The cups-deviced helper application now runs backends in
+ parallel to get the list of devices faster.
- Added --enable-pap configure option.
- The default cupsd.conf file now includes an "authenticated"
policy which requires authentication for remote print jobs.
test1284: test1284.o ../cups/libcups.a
echo Linking $@...
$(CC) $(LDFLAGS) -o test1284 test1284.o ../cups/libcups.a \
- $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+ $(LIBGSSAPI) $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
#
testbackend: testbackend.o ../cups/libcups.a
echo Linking $@...
$(CC) $(LDFLAGS) -o testbackend testbackend.o ../cups/libcups.a \
- $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+ $(LIBGSSAPI) $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
#
* Community public
* DebugLevel 0
* HostNameLookups off
- * MaxRunTime 10
+ * MaxRunTime 120
*
* This backend is known to work with the following network printers and
* print servers:
static unsigned DeviceTypeRequest;
static cups_array_t *DeviceURIs = NULL;
static int HostNameLookups = 0;
-static int MaxRunTime = 10;
+static int MaxRunTime = 120;
static struct timeval StartTime;
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->make_and_model ? cache->make_and_model : "Unknown",
cache->addrname, cache->id ? cache->id : "");
+ fflush(stdout);
+ }
}
free(device->make_and_model);
device->make_and_model = strdup(make_model);
+
+ probe_device(device);
}
}
* Then read any responses that come in over the next 3 seconds...
*/
- endtime = time(NULL) + 3;
+ endtime = time(NULL) + MaxRunTime;
FD_ZERO(&input);
while (time(NULL) < endtime)
{
- timeout.tv_sec = 1;
+ timeout.tv_sec = 2;
timeout.tv_usec = 0;
FD_SET(fd, &input);
# include <fcntl.h>
#endif /* WIN32 */
-#define DEBUG
+#ifndef DEBUG
+# define DEBUG
+#endif /* !DEBUG */
#include "ieee1284.c"
langArray = CFArrayCreate(kCFAllocatorDefault, (const void **)lang, sizeof(lang) / sizeof(lang[0]), &kCFTypeArrayCallBacks);
CFPreferencesSetAppValue(CFSTR("AppleLanguages"), langArray, kCFPreferencesCurrentApplication);
- DEBUG_printf((stderr, "DEBUG: usb: AppleLanguages = \"%s\"\n", requestedLang));
+ fprintf(stderr, "DEBUG: usb: AppleLanguages = \"%s\"\n", requestedLang);
CFRelease(lang[0]);
CFRelease(langArray);
*
* "lpq" command 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
};
- DEBUG_printf(("show_jobs(%08x, %08x, %08x, %d, %d)\n", http, dest, user, id,
- longstatus));
+ DEBUG_printf(("show_jobs(http=%p, dest=%p, user=%p, id=%d, longstatus%d)\n",
+ http, dest, user, id, longstatus));
if (http == NULL)
return (0);
*
* On-line help index routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
else
{
if (cupsFilePrintf(fp, "%s %d " CUPS_LLFMT " " CUPS_LLFMT " \"%s\" \"%s\"\n",
- node->filename, node->mtime,
+ node->filename, (int)node->mtime,
CUPS_LLCAST node->offset, CUPS_LLCAST node->length,
node->section ? node->section : "", node->text) < 0)
break;
#ifdef DEBUG
if (var == NULL)
- printf("cgiGetVariable(\"%s\") is returning NULL...\n", name);
+ DEBUG_printf(("cgiGetVariable(\"%s\") is returning NULL...\n", name));
else
- printf("cgiGetVariable(\"%s\") is returning \"%s\"...\n", name,
- var->values[var->nvalues - 1]);
+ DEBUG_printf(("cgiGetVariable(\"%s\") is returning \"%s\"...\n", name,
+ var->values[var->nvalues - 1]));
#endif /* DEBUG */
return ((var == NULL) ? NULL : var->values[var->nvalues - 1]);
*/
setbuf(stdout, NULL);
- puts("Content-type: text/plain\n");
#endif /* DEBUG */
/*
if (name == NULL || value == NULL || element < 0 || element > 100000)
return;
-#ifdef DEBUG
- printf("Adding variable \'%s\' with value \'%s\'...\n", name, value);
-#endif /* DEBUG */
+ DEBUG_printf(("cgi_add_variable: Adding variable \'%s\' with value "
+ "\'%s\'...\n", name, value));
if (form_count >= form_alloc)
{
char *data; /* Pointer to form data string */
-#ifdef DEBUG
- puts("Initializing variables using GET method...");
-#endif /* DEBUG */
+ DEBUG_puts("cgi_initialize_get: Initializing variables using GET method...");
/*
* Check to see if there is anything for us to read...
status; /* Return status */
-#ifdef DEBUG
- puts("Initializing variables using POST method...");
-#endif /* DEBUG */
+ DEBUG_puts("cgi_initialize_post: Initializing variables using POST method...");
/*
* Check to see if there is anything for us to read...
int i;
- puts("Sorting variables...");
+ DEBUG_puts("cgi_sort_variables: Sorting variables...");
#endif /* DEBUG */
if (form_count < 2)
(int (*)(const void *, const void *))cgi_compare_variables);
#ifdef DEBUG
- puts("Sorted variable list is:");
+ DEBUG_puts("cgi_sort_variables: Sorted variable list is:");
for (i = 0; i < form_count; i ++)
- printf("%d: %s (%d) = \"%s\" ...\n", i, form_vars[i].name,
- form_vars[i].nvalues, form_vars[i].values[0]);
+ DEBUG_printf(("cgi_sort_variables: %d: %s (%d) = \"%s\" ...\n", i,
+ form_vars[i].name, form_vars[i].nvalues,
+ form_vars[i].values[0]));
#endif /* DEBUG */
}
</Limit>
# All administration operations require an administrator to authenticate...
- <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default>
+ <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default CUPS-Get-Devices>
AuthType Default
Require user @SYSTEM
Order deny,allow
dnl For debugging, keep symbols, otherwise strip them...
if test x$enable_debug = xyes; then
OPTIM="-g"
+ CFLAGS="$CFLAGS -DDEBUG"
else
INSTALL_STRIP="-s"
fi
AC_DEFINE_UNQUOTED(CUPS_DEFAULT_SMB_CONFIG_FILE, "$CUPS_DEFAULT_SMB_CONFIG_FILE")
dnl Default MaxCopies value...
-AC_ARG_WITH(max-copies, [ --with-max-copies set max copies value, default=100 ],
+AC_ARG_WITH(max-copies, [ --with-max-copies set default max copies value, default=auto ],
CUPS_MAX_COPIES="$withval",
if test "x$uname" = xDarwin; then
- CUPS_MAX_COPIES="999"
+ CUPS_MAX_COPIES="9999"
else
CUPS_MAX_COPIES="100"
fi)
dnl
dnl PDF filter configuration stuff for the Common UNIX Printing System (CUPS).
dnl
-dnl Copyright 2007 by Apple Inc.
+dnl Copyright 2007-2008 by Apple Inc.
dnl Copyright 2006 by Easy Software Products, all rights reserved.
dnl
dnl These coded instructions, statements, and computer programs are the
if test "x$enable_pdftops" != xno; then
AC_PATH_PROG(CUPS_PDFTOPS, pdftops)
+ if test "x$CUPS_PDFTOPS" != x; then
+ AC_DEFINE(HAVE_PDFTOPS)
+ fi
AC_DEFINE_UNQUOTED(CUPS_PDFTOPS, "$CUPS_PDFTOPS")
- if test "x$CUPS_PDFTOPS" != x; then
+ AC_PATH_PROG(CUPS_GHOSTSCRIPT, gs)
+ if test "x$CUPS_GHOSTSCRIPT" != x; then
+ AC_DEFINE(HAVE_GHOSTSCRIPT)
+ fi
+ AC_DEFINE_UNQUOTED(CUPS_GHOSTSCRIPT, "$CUPS_GHOSTSCRIPT")
+
+ if test "x$CUPS_PDFTOPS" != x -o "x$CUPS_GHOSTSCRIPT" != x; then
AC_MSG_CHECKING(whether to build pdftops filter)
if test x$enable_pdftops = xyes -o $uname != Darwin; then
PDFTOPS="pdftops"
AC_MSG_RESULT(no)
fi
elif test x$enable_pdftops = xyes; then
- AC_MSG_ERROR(Unable to find pdftops program!)
+ AC_MSG_ERROR(Unable to find pdftops or gs programs!)
exit 1
fi
fi
*
* Configuration file for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
* Location of the poppler/Xpdf pdftops program...
*/
+#undef HAVE_PDFTOPS
#define CUPS_PDFTOPS "/usr/bin/pdftops"
+/*
+ * Location of the Ghostscript gs program...
+ */
+
+#undef HAVE_GHOSTSCRIPT
+#define CUPS_GHOSTSCRIPT "/usr/bin/gs"
+
+
/*
* Do we have Darwin's CoreFoundation and SystemConfiguration frameworks?
*/
backchannel.o \
backend.o \
custom.o \
+ debug.o \
dest.o \
dir.o \
emit.o \
encode.o \
file.o \
+ getdevices.o \
getifaddrs.o \
getputfile.o \
globals.o \
mxmldoc --section "Programming" --title "CUPS API" \
--css ../doc/cups-printable.css \
--header api-cups.header --intro api-cups.shtml \
- cups.h dest.c getputfile.c language.c notify.c \
+ cups.h dest.c language.c notify.c \
options.c tempfile.c usersys.c \
util.c >../doc/help/api-cups.html
mxmldoc --section "Programming" --title "File and Directory APIs" \
mxmldoc --section "Programming" --title "HTTP and IPP APIs" \
--css ../doc/cups-printable.css \
--header api-httpipp.header --intro api-httpipp.shtml \
- http.h ipp.h auth.c encode.c http.c http-addr.c \
- http-support.c ipp.c ipp-support.c md5passwd.c \
- request.c >../doc/help/api-httpipp.html
+ http.h ipp.h auth.c getdevices.c getputfile.c encode.c \
+ http.c http-addr.c http-support.c ipp.c ipp-support.c \
+ md5passwd.c request.c >../doc/help/api-httpipp.html
mxmldoc --section "Programming" \
--title "Filter and Backend Programming" \
--css ../doc/cups-printable.css \
--section "Programming" --title "CUPS API" \
--css ../doc/cups-printable.css \
--header api-cups.header --intro api-cups.shtml \
- cups.h dest.c getputfile.c language.c notify.c \
+ cups.h dest.c language.c notify.c \
options.c tempfile.c usersys.c \
util.c
mxmldoc --framed api-filedir \
--section "Programming" --title "HTTP and IPP APIs" \
--css ../doc/cups-printable.css \
--header api-httpipp.header --intro api-httpipp.shtml \
- http.h ipp.h auth.c encode.c http.c http-addr.c \
- http-support.c ipp.c ipp-support.c md5passwd.c \
- request.c
+ http.h ipp.h auth.c getdevices.c getputfile.c encode.c \
+ http.c http-addr.c http-support.c ipp.c ipp-support.c \
+ md5passwd.c request.c
mxmldoc --framed api-filter \
--section "Programming" \
--title "Filter and Backend Programming" \
}
#ifdef DEBUG
else
- printf("cups_array_add: append element at %d...\n", current);
+ DEBUG_printf(("cups_array_add: append element at %d...\n", current));
#endif /* DEBUG */
a->elements[current] = e;
#ifdef DEBUG
for (current = 0; current < a->num_elements; current ++)
- printf("cups_array_add: a->elements[%d]=%p\n", current, a->elements[current]);
+ DEBUG_printf(("cups_array_add: a->elements[%d]=%p\n", current,
+ a->elements[current]));
#endif /* DEBUG */
DEBUG_puts("cups_array_add: returning 1");
else
{
DEBUG_printf(("cupsDoAuthentication: Kerberos credentials too large - "
- "%d bytes!\n", output_token.length));
+ "%d bytes!\n", (int)output_token.length));
major_status = gss_release_buffer(&minor_status, &output_token);
# define CUPS_VERSION_PATCH -1
# define CUPS_DATE_ANY (time_t)-1
+# define CUPS_EXCLUDE_NONE (const char *)0
# define CUPS_FORMAT_AUTO "application/octet-stream"
# define CUPS_FORMAT_PDF "application/pdf"
# define CUPS_FORMAT_POSTSCRIPT "application/postscript"
# define CUPS_JOBID_ALL -1
# define CUPS_JOBID_CURRENT 0
# define CUPS_LENGTH_VARIABLE (ssize_t)0
+# define CUPS_TIMEOUT_DEFAULT 0
# define CUPS_WHICHJOBS_ALL -1
# define CUPS_WHICHJOBS_ACTIVE 0
# define CUPS_WHICHJOBS_COMPLETED 1
CUPS_PRINTER_OPTIONS = 0x6fffc /* ~(CLASS | REMOTE | IMPLICIT | DEFAULT | FAX | REJECTING | DELETE | NOT_SHARED | AUTHENTICATED | COMMANDS | DISCOVERED) @private@ */
};
-typedef const char *(*cups_password_cb_t)(const char *);
+typedef const char *(*cups_password_cb_t)(const char *prompt);
/**** Password callback ****/
+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);
+ /**** Device callback @since CUPS 1.4@ ****/
+
typedef struct cups_option_s /**** Printer Options ****/
{
char *name; /* Name of option */
cups_option_t *options) _CUPS_API_1_4;
extern ipp_status_t cupsFinishDocument(http_t *http,
const char *name) _CUPS_API_1_4;
+extern ipp_status_t cupsGetDevices(http_t *http, int timeout,
+ const char *exclude_schemes,
+ cups_device_cb_t callback,
+ void *user_data) _CUPS_API_1_4;
extern cups_dest_t *cupsGetNamedDest(http_t *http, const char *name,
const char *instance) _CUPS_API_1_4;
extern http_status_t cupsGetPPD3(http_t *http, const char *name,
--- /dev/null
+/*
+ * "$Id$"
+ *
+ * Debugging functions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2008 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * _cups_debug_printf() - Write a formatted line to the log.
+ * _cups_debug_puts() - Write a single line to the log.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "globals.h"
+#include "debug.h"
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+#ifdef DEBUG
+/*
+ * 'debug_vsnprintf()' - Format a string into a fixed size buffer.
+ */
+
+int /* O - Number of bytes formatted */
+debug_vsnprintf(char *buffer, /* O - Output buffer */
+ size_t bufsize, /* O - Size of output buffer */
+ const char *format, /* I - printf-style format string */
+ va_list ap) /* I - Pointer to additional arguments */
+{
+ char *bufptr, /* Pointer to position in buffer */
+ *bufend, /* Pointer to end of buffer */
+ sign, /* Sign of format width */
+ size, /* Size character (h, l, L) */
+ type; /* Format type character */
+ int width, /* Width of field */
+ prec; /* Number of characters of precision */
+ char tformat[100], /* Temporary format string for sprintf() */
+ *tptr, /* Pointer into temporary format */
+ temp[1024]; /* Buffer for formatted numbers */
+ char *s; /* Pointer to string */
+ int bytes; /* Total number of bytes needed */
+
+
+ /*
+ * Loop through the format string, formatting as needed...
+ */
+
+ bufptr = buffer;
+ bufend = buffer + bufsize - 1;
+ bytes = 0;
+
+ while (*format)
+ {
+ if (*format == '%')
+ {
+ tptr = tformat;
+ *tptr++ = *format++;
+
+ if (*format == '%')
+ {
+ if (bufptr && bufptr < bufend) *bufptr++ = *format;
+ bytes ++;
+ format ++;
+ continue;
+ }
+ else if (strchr(" -+#\'", *format))
+ {
+ *tptr++ = *format;
+ sign = *format++;
+ }
+ else
+ sign = 0;
+
+ if (*format == '*')
+ {
+ /*
+ * Get width from argument...
+ */
+
+ format ++;
+ width = va_arg(ap, int);
+
+ snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
+ tptr += strlen(tptr);
+ }
+ else
+ {
+ width = 0;
+
+ while (isdigit(*format & 255))
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ width = width * 10 + *format++ - '0';
+ }
+ }
+
+ if (*format == '.')
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ format ++;
+
+ if (*format == '*')
+ {
+ /*
+ * Get precision from argument...
+ */
+
+ format ++;
+ prec = va_arg(ap, int);
+
+ snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
+ tptr += strlen(tptr);
+ }
+ else
+ {
+ prec = 0;
+
+ while (isdigit(*format & 255))
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ prec = prec * 10 + *format++ - '0';
+ }
+ }
+ }
+ else
+ prec = -1;
+
+ if (*format == 'l' && format[1] == 'l')
+ {
+ size = 'L';
+
+ if (tptr < (tformat + sizeof(tformat) - 2))
+ {
+ *tptr++ = 'l';
+ *tptr++ = 'l';
+ }
+
+ format += 2;
+ }
+ else if (*format == 'h' || *format == 'l' || *format == 'L')
+ {
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ size = *format++;
+ }
+
+ if (!*format)
+ break;
+
+ if (tptr < (tformat + sizeof(tformat) - 1))
+ *tptr++ = *format;
+
+ type = *format++;
+ *tptr = '\0';
+
+ switch (type)
+ {
+ case 'E' : /* Floating point formats */
+ case 'G' :
+ case 'e' :
+ case 'f' :
+ case 'g' :
+ if ((width + 2) > sizeof(temp))
+ break;
+
+ sprintf(temp, tformat, va_arg(ap, double));
+
+ bytes += (int)strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'B' : /* Integer formats */
+ case 'X' :
+ case 'b' :
+ case 'd' :
+ case 'i' :
+ case 'o' :
+ case 'u' :
+ case 'x' :
+ if ((width + 2) > sizeof(temp))
+ break;
+
+#ifdef HAVE_LONG_LONG
+ if (size == 'L')
+ sprintf(temp, tformat, va_arg(ap, long long));
+ else
+#endif /* HAVE_LONG_LONG */
+ if (size == 'l')
+ sprintf(temp, tformat, va_arg(ap, long));
+ else
+ sprintf(temp, tformat, va_arg(ap, int));
+
+ bytes += (int)strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'p' : /* Pointer value */
+ if ((width + 2) > sizeof(temp))
+ break;
+
+ sprintf(temp, tformat, va_arg(ap, void *));
+
+ bytes += (int)strlen(temp);
+
+ if (bufptr)
+ {
+ if ((bufptr + strlen(temp)) > bufend)
+ {
+ strncpy(bufptr, temp, (size_t)(bufend - bufptr));
+ bufptr = bufend;
+ }
+ else
+ {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'c' : /* Character or character array */
+ bytes += width;
+
+ if (bufptr)
+ {
+ if (width <= 1)
+ *bufptr++ = va_arg(ap, int);
+ else
+ {
+ if ((bufptr + width) > bufend)
+ width = (int)(bufend - bufptr);
+
+ memcpy(bufptr, va_arg(ap, char *), (size_t)width);
+ bufptr += width;
+ }
+ }
+ break;
+
+ case 's' : /* String */
+ if ((s = va_arg(ap, char *)) == NULL)
+ s = "(null)";
+
+ /*
+ * Copy the C string, replacing control chars and \ with
+ * C character escapes...
+ */
+
+ for (bufend --; *s && bufptr < bufend; s ++)
+ {
+ if (*s == '\n')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = 'n';
+ }
+ else if (*s == '\r')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = 'r';
+ }
+ else if (*s == '\t')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = 't';
+ }
+ else if (*s == '\\')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = '\\';
+ }
+ else if (*s == '\'')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = '\'';
+ }
+ else if (*s == '\"')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = '\"';
+ }
+ else if ((*s & 255) < ' ')
+ {
+ *bufptr++ = '\\';
+ *bufptr++ = '0';
+ *bufptr++ = '0' + *s / 8;
+ *bufptr++ = '0' + (*s & 7);
+ }
+ else
+ *bufptr++ = *s;
+ }
+
+ bufend ++;
+ break;
+
+ case 'n' : /* Output number of chars so far */
+ *(va_arg(ap, int *)) = bytes;
+ break;
+ }
+ }
+ else
+ {
+ bytes ++;
+
+ if (bufptr && bufptr < bufend)
+ *bufptr++ = *format;
+
+ format ++;
+ }
+ }
+
+ /*
+ * Nul-terminate the string and return the number of characters needed.
+ */
+
+ *bufptr = '\0';
+
+ return (bytes);
+}
+
+
+/*
+ * '_cups_debug_printf()' - Write a formatted line to the log.
+ */
+
+void
+_cups_debug_printf(const char *format, /* I - Printf-style format string */
+ ...) /* I - Additional arguments as needed */
+{
+ va_list ap; /* Pointer to arguments */
+ struct timeval curtime; /* Current time */
+ char buffer[2048]; /* Output buffer */
+ size_t bytes; /* Number of bytes in buffer */
+ const char *cups_debug_log;/* CUPS_DEBUG_LOG environment variable */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Global data */
+
+
+ /*
+ * See if we need to do any logging...
+ */
+
+ if (!cg->debug_init)
+ {
+ cg->debug_init = 1;
+
+ if ((cups_debug_log = getenv("CUPS_DEBUG_LOG")) == NULL)
+ cg->debug_fd = -1;
+ else if (!strcmp(cups_debug_log, "-"))
+ cg->debug_fd = 2;
+ else
+ cg->debug_fd = open(cups_debug_log, O_WRONLY | O_APPEND | O_CREAT, 0644);
+ }
+
+ if (cg->debug_fd < 0)
+ return;
+
+ /*
+ * Format the message...
+ */
+
+ gettimeofday(&curtime, NULL);
+ snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d.%03d ",
+ (int)((curtime.tv_sec / 3600) % 24),
+ (int)((curtime.tv_sec / 60) % 60),
+ (int)(curtime.tv_sec % 60), (int)(curtime.tv_usec / 1000));
+
+ va_start(ap, format);
+ debug_vsnprintf(buffer + 13, sizeof(buffer) - 14, format, ap);
+ va_end(ap);
+
+ bytes = strlen(buffer);
+ if (buffer[bytes - 1] != '\n')
+ {
+ buffer[bytes] = '\n';
+ bytes ++;
+ buffer[bytes] = '\0';
+ }
+
+ /*
+ * Write it out...
+ */
+
+ write(cg->debug_fd, buffer, bytes);
+}
+
+
+/*
+ * '_cups_debug_puts()' - Write a single line to the log.
+ */
+
+void
+_cups_debug_puts(const char *s) /* I - String to output */
+{
+ _cups_debug_printf("%s\n", s);
+}
+
+
+#elif defined(__APPLE__)
+/* Mac OS X needs these stubbed since we reference them in the libcups.exp file */
+void _cups_debug_printf(const char *format, ...) {}
+void _cups_debug_puts(const char *s) {}
+#endif /* DEBUG */
+
+
+/*
+ * End of "$Id$".
+ */
*
* Debugging macros for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2005 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
#ifndef _CUPS_DEBUG_H_
# define _CUPS_DEBUG_H_
-/*
- * Include necessary headers...
- */
-
-# include <stdio.h>
-
/*
* The debug macros are used if you compile with DEBUG defined.
*
*/
# ifdef DEBUG
-# define DEBUG_puts(x) puts(x)
-# define DEBUG_printf(x) printf x
+# define DEBUG_puts(x) _cups_debug_puts(x)
+# define DEBUG_printf(x) _cups_debug_printf x
# else
# define DEBUG_puts(x)
# define DEBUG_printf(x)
# endif /* DEBUG */
+
+/*
+ * Prototypes...
+ */
+
+extern void _cups_debug_printf(const char *format, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 1, 2)))
+#endif /* __GNUC__ */
+;
+extern void _cups_debug_puts(const char *s);
+
+
#endif /* !_CUPS_DEBUG_H_ */
/*
#ifdef DEBUG
CFStringGetCString(network, name, namesize, kCFStringEncodingUTF8);
- printf("appleGetDefault: network=\"%s\"\n", name);
+ DEBUG_printf(("appleGetDefault: network=\"%s\"\n", name));
#endif /* DEBUG */
/*
* Allocate memory...
*/
- DEBUG_printf(("ppdEmitString: Allocating %d bytes for string...\n", bufsize));
+ DEBUG_printf(("ppdEmitString: Allocating %d bytes for string...\n",
+ (int)bufsize));
if ((buffer = calloc(1, bufsize)) == NULL)
{
bufptr += strlen(bufptr);
DEBUG_printf(("ppdEmitString: Offset in string is %d...\n",
- bufptr - buffer));
+ (int)(bufptr - buffer)));
}
else
{
{ 0, "copies-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
{ 0, "document-format", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION },
{ 0, "document-format-default", IPP_TAG_MIMETYPE, IPP_TAG_PRINTER },
+ { 1, "exclude-schemes", IPP_TAG_NAME, IPP_TAG_OPERATION },
{ 1, "finishings", IPP_TAG_ENUM, IPP_TAG_JOB },
{ 1, "finishings-default", IPP_TAG_ENUM, IPP_TAG_PRINTER },
{ 0, "fitplot", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
{ 0, "printer-uri", IPP_TAG_URI, IPP_TAG_OPERATION },
{ 0, "queued-job-count", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
{ 0, "raw", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION },
+ { 1, "requested-attributes", IPP_TAG_NAME, IPP_TAG_OPERATION },
{ 1, "requesting-user-name-allowed", IPP_TAG_NAME, IPP_TAG_PRINTER },
{ 1, "requesting-user-name-denied", IPP_TAG_NAME, IPP_TAG_PRINTER },
{ 0, "resolution", IPP_TAG_RESOLUTION, IPP_TAG_JOB },
attr->values[j].unknown.length = (int)strlen(val);
attr->values[j].unknown.data = strdup(val);
- DEBUG_printf(("cupsEncodeOptions2: Added octet-string value \"%s\"...\n",
- attr->values[j].unknown.data));
+ DEBUG_printf(("cupsEncodeOptions2: Added octet-string value "
+ "\"%s\"...\n", (char *)attr->values[j].unknown.data));
break;
default :
extern cups_file_t *cupsFileOpen(const char *filename, const char *mode) _CUPS_API_1_2;
extern cups_file_t *cupsFileOpenFd(int fd, const char *mode) _CUPS_API_1_2;
extern int cupsFilePeekChar(cups_file_t *fp) _CUPS_API_1_2;
-extern int cupsFilePrintf(cups_file_t *fp, const char *format, ...) _CUPS_API_1_2;
+extern int cupsFilePrintf(cups_file_t *fp, const char *format, ...)
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+#endif /* __GNUC__ */
+_CUPS_API_1_2;
extern int cupsFilePutChar(cups_file_t *fp, int c) _CUPS_API_1_2;
extern int cupsFilePuts(cups_file_t *fp, const char *s) _CUPS_API_1_2;
extern ssize_t cupsFileRead(cups_file_t *fp, char *buf, size_t bytes) _CUPS_API_1_2;
--- /dev/null
+/*
+ * "$Id$"
+ *
+ * cupsGetDevices implementation for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2008 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "globals.h"
+#include "debug.h"
+
+
+/*
+ * 'cupsGetDevices()' - Get available printer devices.
+ *
+ * This function sends a CUPS-Get-Devices request and streams the discovered
+ * devices to the specified callback function. The "timeout" parameter controls
+ * how long the request lasts, while the "exclude_schemes" parameter provides
+ * a comma-delimited list of backends to omit from the request.
+ *
+ * @since CUPS 1.4@
+ */
+
+ipp_status_t /* O - Request status - @code IPP_OK@ on success. */
+cupsGetDevices(
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ int timeout, /* I - Timeout in seconds or @code CUPS_TIMEOUT_DEFAULT@ */
+ const char *exclude_schemes, /* I - Comma-separated URI schemes to exclude or @code CUPS_EXCLUDE_NONE@ */
+ cups_device_cb_t callback, /* I - Callback function */
+ void *user_data) /* I - User data pointer */
+{
+ ipp_t *request, /* CUPS-Get-Devices request */
+ *response; /* CUPS-Get-Devices response */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *device_class, /* device-class value */
+ *device_id, /* device-id value */
+ *device_info, /* device-info value */
+ *device_make_and_model, /* device-make-and-model value */
+ *device_uri; /* device-uri value */
+ int blocking; /* Current blocking-IO mode */
+ cups_option_t option; /* exclude-schemes option */
+ http_status_t status; /* HTTP status of request */
+ ipp_state_t state; /* IPP response state */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!callback)
+ return (IPP_INTERNAL_ERROR);
+
+ if (!http)
+ http = _cupsConnect();
+
+ if (!http)
+ return (IPP_SERVICE_UNAVAILABLE);
+
+ /*
+ * Create a CUPS-Get-Devices request...
+ */
+
+ request = ippNewRequest(CUPS_GET_DEVICES);
+
+ if (timeout > 0)
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "timeout",
+ timeout);
+
+ if (exclude_schemes)
+ {
+ option.name = "exclude-schemes";
+ option.value = (char *)exclude_schemes;
+
+ cupsEncodeOptions2(request, 1, &option, IPP_TAG_OPERATION);
+ }
+
+ /*
+ * Send the request and do any necessary authentication...
+ */
+
+ do
+ {
+ DEBUG_puts("cupsGetDevices: Sending request...");
+ status = cupsSendRequest(http, request, "/", ippLength(request));
+
+ DEBUG_puts("cupsGetDevices: Waiting for response status...");
+ while (status == HTTP_CONTINUE)
+ status = httpUpdate(http);
+
+ if (status != HTTP_OK)
+ {
+ httpFlush(http);
+
+ if (status == HTTP_UNAUTHORIZED)
+ {
+ /*
+ * See if we can do authentication...
+ */
+
+ int auth_result;
+
+ DEBUG_puts("cupsGetDevices: Need authorization...");
+
+ if ((auth_result = cupsDoAuthentication(http, "POST", "/")) == 0)
+ httpReconnect(http);
+ else if (auth_result < 0)
+ http->status = status = HTTP_FORBIDDEN;
+ }
+
+#ifdef HAVE_SSL
+ else if (status == HTTP_UPGRADE_REQUIRED)
+ {
+ /*
+ * Force a reconnect with encryption...
+ */
+
+ DEBUG_puts("cupsGetDevices: Need encryption...");
+
+ if (!httpReconnect(http))
+ httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
+ }
+#endif /* HAVE_SSL */
+ }
+ }
+ while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED);
+
+ DEBUG_printf(("cupsGetDevices: status=%d\n", status));
+
+ ippDelete(request);
+
+ if (status != HTTP_OK)
+ {
+ _cupsSetHTTPError(status);
+ return (cupsLastError());
+ }
+
+ /*
+ * Read the response in non-blocking mode...
+ */
+
+ blocking = httpGetBlocking(http);
+ httpBlocking(http, 0);
+
+ response = ippNew();
+ device_class = NULL;
+ device_id = NULL;
+ device_info = NULL;
+ device_make_and_model = NULL;
+ device_uri = NULL;
+ attr = NULL;
+
+ DEBUG_puts("cupsGetDevices: Reading response...");
+
+ do
+ {
+ if ((state = ippRead(http, response)) == IPP_ERROR)
+ break;
+
+ DEBUG_printf(("cupsGetDevices: state=%d, response->last=%p\n", state,
+ response->last));
+
+ if (!response->attrs)
+ continue;
+
+ while (attr != response->last)
+ {
+ if (!attr)
+ attr = response->attrs;
+ else
+ attr = attr->next;
+
+ DEBUG_printf(("cupsGetDevices: attr->name=\"%s\", attr->value_tag=%d\n",
+ attr->name ? attr->name : "(null)", attr->value_tag));
+
+ if (!attr->name)
+ {
+ 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_class = NULL;
+ device_id = NULL;
+ device_info = NULL;
+ device_make_and_model = NULL;
+ device_uri = NULL;
+ }
+ else if (!strcmp(attr->name, "device-class") &&
+ attr->value_tag == IPP_TAG_KEYWORD)
+ device_class = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "device-id") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_id = attr->values[0].string.text;
+ 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-make-and-model") &&
+ attr->value_tag == IPP_TAG_TEXT)
+ device_make_and_model = attr->values[0].string.text;
+ else if (!strcmp(attr->name, "device-uri") &&
+ attr->value_tag == IPP_TAG_URI)
+ device_uri = attr->values[0].string.text;
+ }
+ }
+ while (state != IPP_DATA);
+
+ DEBUG_printf(("cupsGetDevices: state=%d, response->last=%p\n", state,
+ response->last));
+
+ 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);
+
+ /*
+ * Set the IPP status and return...
+ */
+
+ httpBlocking(http, blocking);
+
+ if (status == IPP_ERROR)
+ _cupsSetError(IPP_ERROR, NULL);
+ else
+ {
+ attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
+
+ DEBUG_printf(("cupsGetDevices: status-code=%s, status-message=\"%s\"\n",
+ ippErrorString(response->request.status.status_code),
+ attr ? attr->values[0].string.text : ""));
+
+ _cupsSetError(response->request.status.status_code,
+ attr ? attr->values[0].string.text :
+ ippErrorString(response->request.status.status_code));
+ }
+
+ ippDelete(response);
+
+ return (cupsLastError());
+}
+
+
+/*
+ * End of "$Id$".
+ */
*
* Global variable access routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
#include "http-private.h"
#include "globals.h"
-#include "debug.h"
#include <stdlib.h>
* Initialize the global data exactly once...
*/
- DEBUG_printf(("_cupsGlobals(): globals_key_once=%d\n", globals_key_once));
-
pthread_once(&globals_key_once, globals_init);
/*
if ((globals = (_cups_globals_t *)pthread_getspecific(globals_key)) == NULL)
{
- DEBUG_puts("_cupsGlobals: allocating memory for thread...");
-
/*
* No, allocate memory as set the pointer for the key...
*/
globals = calloc(1, sizeof(_cups_globals_t));
pthread_setspecific(globals_key, globals);
- DEBUG_printf((" globals=%p\n", globals));
-
/*
* Initialize variables that have non-zero values
*/
globals_init()
{
pthread_key_create(&globals_key, globals_destructor);
-
- DEBUG_printf(("globals_init(): globals_key=%x(%u)\n", globals_key,
- globals_key));
}
_cups_globals_t *cg; /* Global data */
- DEBUG_printf(("globals_destructor(value=%p)\n", value));
-
cg = (_cups_globals_t *)value;
httpClose(cg->http);
/* Number of server settings */
cups_option_t *cupsd_settings;/* Server settings */
+#ifdef DEBUG
+ /* debug.c */
+ int debug_init, /* Did we initialize debugging? */
+ debug_fd; /* Debug log file descriptor */
+#endif /* DEBUG */
+
/* file.c */
cups_file_t *stdio_files[3];/* stdin, stdout, stderr */
#ifdef DEBUG
- printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, service=\"%s\")\n",
- hostname ? hostname : "(nil)",
- family == AF_UNSPEC ? "UNSPEC" :
+ _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, "
+ "service=\"%s\")\n",
+ hostname ? hostname : "(nil)",
+ family == AF_UNSPEC ? "UNSPEC" :
# ifdef AF_LOCAL
- family == AF_LOCAL ? "LOCAL" :
+ family == AF_LOCAL ? "LOCAL" :
# endif /* AF_LOCAL */
# ifdef AF_INET6
- family == AF_INET6 ? "INET6" :
+ family == AF_INET6 ? "INET6" :
# endif /* AF_INET6 */
- family == AF_INET ? "INET" : "???", service);
+ family == AF_INET ? "INET" : "???", service);
#endif /* DEBUG */
/*
* http_bio_puts() - Send a string for OpenSSL.
* http_bio_read() - Read data for OpenSSL.
* http_bio_write() - Write data for OpenSSL.
+ * http_debug_hex() - Do a hex dump of a buffer.
* http_field() - Return the field index for a field name.
* http_read_ssl() - Read from a SSL/TLS connection.
* http_send() - Send a request with all fields and the trailing
* Local functions...
*/
+#ifdef DEBUG
+static void http_debug_hex(const char *prefix, const char *buffer,
+ int bytes);
+#endif /* DEBUG */
static http_field_t http_field(const char *name);
static int http_send(http_t *http, http_state_t request,
const char *uri);
char len[32]; /* Length string */
- DEBUG_printf(("httpRead(http=%p, buffer=%p, length=" CUPS_LLFMT ")\n",
+ DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT ")\n",
http, buffer, CUPS_LLCAST length));
if (http == NULL || buffer == NULL)
}
#ifdef DEBUG
- {
- int i, j, ch;
- printf("httpRead2: Read " CUPS_LLFMT " bytes:\n", CUPS_LLCAST bytes);
- for (i = 0; i < bytes; i += 16)
- {
- printf(" ");
-
- for (j = 0; j < 16 && (i + j) < bytes; j ++)
- printf(" %02X", buffer[i + j] & 255);
-
- while (j < 16)
- {
- printf(" ");
- j ++;
- }
-
- printf(" ");
- for (j = 0; j < 16 && (i + j) < bytes; j ++)
- {
- ch = buffer[i + j] & 255;
-
- if (ch < ' ' || ch >= 127)
- ch = '.';
-
- putchar(ch);
- }
- putchar('\n');
- }
- }
+ http_debug_hex("httpRead2", buffer, (int)bytes);
#endif /* DEBUG */
return (bytes);
ssize_t bytes; /* Bytes written */
- DEBUG_printf(("httpWrite(http=%p, buffer=%p, length=" CUPS_LLFMT ")\n", http,
+ DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")\n", http,
buffer, CUPS_LLCAST length));
/*
{
if (http->wused && (length + http->wused) > sizeof(http->wbuffer))
{
- DEBUG_printf((" flushing buffer (wused=%d, length=" CUPS_LLFMT ")\n",
- http->wused, CUPS_LLCAST length));
+ DEBUG_printf(("httpWrite2: Flushing buffer (wused=%d, length="
+ CUPS_LLFMT ")\n", http->wused, CUPS_LLCAST length));
httpFlushWrite(http);
}
* Write to buffer...
*/
- DEBUG_printf((" copying " CUPS_LLFMT " bytes to wbuffer...\n",
+ DEBUG_printf(("httpWrite2: Copying " CUPS_LLFMT " bytes to wbuffer...\n",
CUPS_LLCAST length));
memcpy(http->wbuffer + http->wused, buffer, length);
* Otherwise write the data directly...
*/
- DEBUG_printf((" writing " CUPS_LLFMT " bytes to socket...\n",
+ DEBUG_printf(("httpWrite2: Writing " CUPS_LLFMT " bytes to socket...\n",
CUPS_LLCAST length));
if (http->data_encoding == HTTP_ENCODE_CHUNKED)
else
bytes = (ssize_t)http_write(http, buffer, (int)length);
- DEBUG_printf((" wrote " CUPS_LLFMT " bytes...\n", CUPS_LLCAST bytes));
+ DEBUG_printf(("httpWrite2: Wrote " CUPS_LLFMT " bytes...\n",
+ CUPS_LLCAST bytes));
}
if (http->data_encoding == HTTP_ENCODE_LENGTH)
#endif /* HAVE_SSL && HAVE_LIBSSL */
+#ifdef DEBUG
+/*
+ * 'http_debug_hex()' - Do a hex dump of a buffer.
+ */
+
+static void
+http_debug_hex(const char *prefix, /* I - Prefix for line */
+ const char *buffer, /* I - Buffer to dump */
+ int bytes) /* I - Bytes to dump */
+{
+ int i, j, /* Looping vars */
+ ch; /* Current character */
+ char line[255], /* Line buffer */
+ *start, /* Start of line after prefix */
+ *ptr; /* Pointer into line */
+
+
+ DEBUG_printf(("%s: %d bytes:\n", prefix, bytes));
+
+ snprintf(line, sizeof(line), "%s: ", prefix);
+ start = line + strlen(line);
+
+ for (i = 0; i < bytes; i += 16)
+ {
+ for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2)
+ sprintf(ptr, "%02X", buffer[i + j] & 255);
+
+ while (j < 16)
+ {
+ strcpy(ptr, " ");
+ ptr += 2;
+ j ++;
+ }
+
+ strcpy(ptr, " ");
+ ptr += 2;
+
+ for (j = 0; j < 16 && (i + j) < bytes; j ++)
+ {
+ ch = buffer[i + j] & 255;
+
+ if (ch < ' ' || ch >= 127)
+ ch = '.';
+
+ *ptr++ = ch;
+ }
+
+ *ptr = '\0';
+ DEBUG_puts(line);
+ }
+}
+#endif /* DEBUG */
+
+
/*
* 'http_field()' - Return the field index for a field name.
*/
-static http_field_t /* O - Field index */
-http_field(const char *name) /* I - String name */
+static http_field_t /* O - Field index */
+http_field(const char *name) /* I - String name */
{
- int i; /* Looping var */
+ int i; /* Looping var */
for (i = 0; i < HTTP_FIELD_MAX; i ++)
for (i = 0; i < HTTP_FIELD_MAX; i ++)
if (http->fields[i][0] != '\0')
{
- DEBUG_printf(("%s: %s\n", http_fields[i], httpGetField(http, i)));
+ DEBUG_printf(("http_send: %s: %s\n", http_fields[i],
+ httpGetField(http, i)));
if (httpPrintf(http, "%s: %s\r\n", http_fields[i],
httpGetField(http, i)) < 1)
}
#ifdef DEBUG
- {
- int i, j, ch;
- printf("http_write: wrote %d bytes: \n", tbytes);
- for (i = 0, buffer -= tbytes; i < tbytes; i += 16)
- {
- printf(" ");
-
- for (j = 0; j < 16 && (i + j) < tbytes; j ++)
- printf(" %02X", buffer[i + j] & 255);
-
- while (j < 16)
- {
- printf(" ");
- j ++;
- }
-
- printf(" ");
- for (j = 0; j < 16 && (i + j) < tbytes; j ++)
- {
- ch = buffer[i + j] & 255;
-
- if (ch < ' ' || ch == 127)
- ch = '.';
-
- putchar(ch);
- }
- putchar('\n');
- }
- }
+ http_debug_hex("http_write", buffer - tbytes, tbytes);
#endif /* DEBUG */
return (tbytes);
#ifdef DEBUG
if (cg->ipp_port)
- puts("ippPort: Set via cupsServer()...");
+ DEBUG_puts(("ippPort: Set via cupsServer()..."));
#endif /* DEBUG */
}
if (http == NULL)
return (IPP_ERROR);
- DEBUG_printf(("http->state = %d\n", http->state));
+ DEBUG_printf(("ippRead: http->state=%d, http->used=%d\n", http->state,
+ http->used));
- return (ippReadIO(http, (ipp_iocb_t)ipp_read_http,
- http->blocking || http->used != 0, NULL, ipp));
+ return (ippReadIO(http, (ipp_iocb_t)ipp_read_http, http->blocking, NULL,
+ ipp));
}
ipp_value_t *value; /* Current value */
- DEBUG_printf(("ippReadIO(%p, %p, %d, %p, %p)\n", src, cb, blocking,
- parent, ipp));
+ DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)\n",
+ src, cb, blocking, parent, ipp));
DEBUG_printf(("ippReadIO: ipp->state=%d\n", ipp->state));
if (src == NULL || ipp == NULL)
if (!attr->name)
continue;
- DEBUG_printf(("attr->name = %s, attr->num_values = %d, bytes = %d\n",
- attr->name, attr->num_values, bytes));
+ DEBUG_printf(("ipp_length: attr->name=\"%s\", attr->num_values=%d, "
+ "bytes=%d\n", attr->name, attr->num_values, bytes));
bytes += (int)strlen(attr->name); /* Name */
bytes += attr->num_values; /* Value tag for each value */
else
bytes ++;
- DEBUG_printf(("bytes = %d\n", bytes));
+ DEBUG_printf(("ipp_length: bytes=%d\n", bytes));
return (bytes);
}
* Loop until all bytes are read...
*/
- for (tbytes = 0, bytes = 0; tbytes < (int)length; tbytes += bytes, buffer += bytes)
+ for (tbytes = 0, bytes = 0;
+ tbytes < (int)length;
+ tbytes += bytes, buffer += bytes)
{
- DEBUG_printf(("tbytes = %d, http->state = %d\n", tbytes, http->state));
+ DEBUG_printf(("ipp_read_http: tbytes=%d, http->state=%d\n", tbytes,
+ http->state));
if (http->state == HTTP_WAITING)
break;
if (tbytes == 0 && bytes < 0)
tbytes = -1;
- DEBUG_printf(("returning %d bytes...\n", tbytes));
+ DEBUG_printf(("ipp_read_http: returning %d bytes...\n", tbytes));
return (tbytes);
}
* No generic localization, so use POSIX...
*/
- DEBUG_printf(("access(\"%s\", 0): %s\n", filename, strerror(errno)));
+ DEBUG_printf(("cupsLangGet: access(\"%s\", 0): %s\n", filename,
+ strerror(errno)));
snprintf(filename, sizeof(filename), "%s/C/cups_C.po", cg->localedir);
}
+__cups_debug_printf
+__cups_debug_puts
__cups_strcpy
__cupsAdminGetServerSettings
__cupsAdminSetServerSettings
_cupsGetDest
_cupsGetDests
_cupsGetDests2
+_cupsGetDevices
_cupsGetFd
_cupsGetFile
_cupsGetJobs
#ifdef DEBUG
if (attr)
- printf(" *%s %s/%s: \"%s\"\n", attr->name, attr->spec, attr->text,
- attr->value ? attr->value : "");
+ DEBUG_printf(("_ppdLocalizedAttr: *%s %s/%s: \"%s\"\n", attr->name,
+ attr->spec, attr->text, attr->value ? attr->value : ""));
else
- puts(" NOT FOUND");
+ DEBUG_puts("_ppdLocalizedAttr: NOT FOUND");
#endif /* DEBUG */
return (attr);
ppd_choice_t *c; /* Current choice */
- printf("cupsMarkOptions: %s\n", title);
+ DEBUG_printf(("cupsMarkOptions: %s\n", title));
for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
c;
c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
- printf("cupsMarkOptions: %s=%s\n", c->option->keyword, c->choice);
+ DEBUG_printf(("cupsMarkOptions: %s=%s\n", c->option->keyword, c->choice));
}
#endif /* DEBUG */
while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
{
-#ifdef DEBUG
- printf("mask = %x, keyword = \"%s\"", mask, keyword);
-
- if (name[0] != '\0')
- printf(", name = \"%s\"", name);
-
- if (text[0] != '\0')
- printf(", text = \"%s\"", text);
-
- if (string != NULL)
- {
- if (strlen(string) > 40)
- printf(", string = %p", string);
- else
- printf(", string = \"%s\"", string);
- }
-
- puts("");
-#endif /* DEBUG */
+ DEBUG_printf(("mask=%x, keyword=\"%s\", name=\"%s\", text=\"%s\", "
+ "string=%d chars...", mask, keyword, name, text,
+ (int)strlen(string)));
if (strcmp(keyword, "CloseUI") && strcmp(keyword, "CloseGroup") &&
strcmp(keyword, "CloseSubGroup") && strncmp(keyword, "Default", 7) &&
* Add an option record to the current sub-group, group, or file...
*/
- DEBUG_printf(("name=\"%s\" (%d)\n", name, strlen(name)));
+ DEBUG_printf(("name=\"%s\" (%d)\n", name, (int)strlen(name)));
if (name[0] == '*')
_cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
#ifdef DEBUG
if (!cupsFileEOF(fp))
- printf("Premature EOF at %lu...\n", (unsigned long)cupsFileTell(fp));
+ DEBUG_printf(("Premature EOF at %lu...\n",
+ (unsigned long)cupsFileTell(fp)));
#endif /* DEBUG */
if (cg->ppd_status != PPD_OK)
*lineptr = '\0';
- DEBUG_printf(("LINE = \"%s\"\n", line));
+ DEBUG_printf(("LINE=\"%s\"\n", line->buffer));
/*
* The dynamically created PPDs for older style Mac OS X
DEBUG_puts("cupsGetResponse: Need authorization...");
- if ((auth_result =cupsDoAuthentication(http, "POST", resource)) == 0)
+ if ((auth_result = cupsDoAuthentication(http, "POST", resource)) == 0)
httpReconnect(http);
else if (auth_result < 0)
http->status = status = HTTP_FORBIDDEN;
cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
ipp_t *request, /* I - IPP request */
const char *resource, /* I - Resource path */
- size_t length) /* I - Length of data to follow or CUPS_LENGTH_VARIABLE */
+ size_t length) /* I - Length of data to follow or @code CUPS_LENGTH_VARIABLE@ */
{
http_status_t status; /* Status of HTTP request */
int got_status; /* Did we get the status? */
_cups_sp_item_t *item; /* Current item */
- DEBUG_printf(("_cupsStrFlush(cg=%p)\n", cg));
- DEBUG_printf((" %d strings in array\n", cupsArrayCount(stringpool)));
+ DEBUG_printf(("_cupsStrFlush: %d strings in array\n",
+ cupsArrayCount(stringpool)));
#ifdef HAVE_PTHREAD_H
pthread_mutex_lock(&sp_mutex);
*
* File test program for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
#ifdef HAVE_LIBZ
# include <zlib.h>
#endif /* HAVE_LIBZ */
+#include <fcntl.h>
/*
main(int argc, /* I - Number of command-line arguments */
char *argv[]) /* I - Command-line arguments */
{
- int status; /* Exit status */
- char filename[1024]; /* Filename buffer */
+ int status; /* Exit status */
+ char filename[1024]; /* Filename buffer */
+ int fds[2]; /* Open file descriptors */
+ cups_file_t *fdfile; /* File opened with cupsFileOpenFd() */
if (argc == 1)
status += read_write_tests(1);
#endif /* HAVE_LIBZ */
+ /*
+ * Test fdopen and close without reading...
+ */
+
+ pipe(fds);
+ close(fds[1]);
+
+ fputs("cupsFileOpenFd(fd, \"r\"): ", stdout);
+ fflush(stdout);
+
+ if ((fdfile = cupsFileOpenFd(fds[0], "r")) == NULL)
+ {
+ puts("FAIL");
+ status ++;
+ }
+ else
+ {
+ /*
+ * Able to open file, now close without reading. If we don't return
+ * before the alarm fires, that is a failure and we will crash on the
+ * alarm signal...
+ */
+
+ puts("PASS");
+ fputs("cupsFileClose(no read): ", stdout);
+ fflush(stdout);
+
+ alarm(5);
+ cupsFileClose(fdfile);
+ alarm(0);
+
+ puts("PASS");
+ }
+
/*
* Test path functions...
*/
DEBUG_printf(("cupsGetPPD3(http=%p, name=\"%s\", modtime=%p(%d), buffer=%p, "
"bufsize=%d)\n", http, name ? name : "(null)", modtime,
- modtime ? *modtime : 0, buffer, (int)bufsize));
+ modtime ? (int)*modtime : 0, buffer, (int)bufsize));
if (!name)
{
<li><a href="#cupsGetDest" title="Get the named destination from the list.">cupsGetDest</a></li>
<li><a href="#cupsGetDests" title="Get the list of destinations from the default server.">cupsGetDests</a></li>
<li><a href="#cupsGetDests2" title="Get the list of destinations from the specified server.">cupsGetDests2</a></li>
-<li><a href="#cupsGetFd" title="Get a file from the server.">cupsGetFd</a></li>
-<li><a href="#cupsGetFile" title="Get a file from the server.">cupsGetFile</a></li>
<li><a href="#cupsGetJobs" title="Get the jobs from the default server.">cupsGetJobs</a></li>
<li><a href="#cupsGetJobs2" title="Get the jobs from the specified server.">cupsGetJobs2</a></li>
<li><a href="#cupsGetNamedDest" title="Get options for the named destination.">cupsGetNamedDest</a></li>
default server.">cupsPrintFiles</a></li>
<li><a href="#cupsPrintFiles2" title="Print one or more files to a printer or class on the
specified server.">cupsPrintFiles2</a></li>
-<li><a href="#cupsPutFd" title="Put a file on the server.">cupsPutFd</a></li>
-<li><a href="#cupsPutFile" title="Put a file on the server.">cupsPutFile</a></li>
<li><a href="#cupsRemoveDest" title="Remove a destination from the destination list.">cupsRemoveDest</a></li>
<li><a href="#cupsRemoveOption" title="Remove an option from an option array.">cupsRemoveOption</a></li>
<li><a href="#cupsServer" title="Return the hostname/address of the default server.">cupsServer</a></li>
</ul>
<li><a href="#TYPES">Data Types</a><ul class="code">
<li><a href="#cups_dest_t" title="Destination">cups_dest_t</a></li>
+ <li><a href="#cups_device_cb_t" title="Device callback ">cups_device_cb_t</a></li>
<li><a href="#cups_job_t" title="Job">cups_job_t</a></li>
<li><a href="#cups_option_t" title="Printer Options">cups_option_t</a></li>
<li><a href="#cups_password_cb_t" title="Password callback">cups_password_cb_t</a></li>
Use the <a href="#cupsFreeDests"><code>cupsFreeDests</code></a> function to free the destination list and
the <a href="#cupsGetDest"><code>cupsGetDest</code></a> function to find a particular destination.
-</p>
-<h3 class="function"><span class="info"> CUPS 1.1.20 </span><a name="cupsGetFd">cupsGetFd</a></h3>
-<p class="description">Get a file from the server.</p>
-<p class="code">
-http_status_t cupsGetFd (<br>
- http_t *http,<br>
- const char *resource,<br>
- int fd<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>http</dt>
-<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
-<dt>resource</dt>
-<dd class="description">Resource name</dd>
-<dt>fd</dt>
-<dd class="description">File descriptor</dd>
-</dl>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">HTTP status</p>
-<h4 class="discussion">Discussion</h4>
-<p class="discussion">This function returns <code>HTTP_OK</code> when the file is successfully retrieved.
-
-</p>
-<h3 class="function"><span class="info"> CUPS 1.1.20 </span><a name="cupsGetFile">cupsGetFile</a></h3>
-<p class="description">Get a file from the server.</p>
-<p class="code">
-http_status_t cupsGetFile (<br>
- http_t *http,<br>
- const char *resource,<br>
- const char *filename<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>http</dt>
-<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
-<dt>resource</dt>
-<dd class="description">Resource name</dd>
-<dt>filename</dt>
-<dd class="description">Filename</dd>
-</dl>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">HTTP status</p>
-<h4 class="discussion">Discussion</h4>
-<p class="discussion">This function returns <code>HTTP_OK</code> when the file is successfully retrieved.
-
</p>
<h3 class="function"><a name="cupsGetJobs">cupsGetJobs</a></h3>
<p class="description">Get the jobs from the default server.</p>
</dl>
<h4 class="returnvalue">Return Value</h4>
<p class="description">Job ID or 0 on error</p>
-<h3 class="function"><span class="info"> CUPS 1.1.20 </span><a name="cupsPutFd">cupsPutFd</a></h3>
-<p class="description">Put a file on the server.</p>
-<p class="code">
-http_status_t cupsPutFd (<br>
- http_t *http,<br>
- const char *resource,<br>
- int fd<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>http</dt>
-<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
-<dt>resource</dt>
-<dd class="description">Resource name</dd>
-<dt>fd</dt>
-<dd class="description">File descriptor</dd>
-</dl>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">HTTP status</p>
-<h4 class="discussion">Discussion</h4>
-<p class="discussion">This function returns <code>HTTP_CREATED</code> when the file is stored
-successfully.
-
-</p>
-<h3 class="function"><span class="info"> CUPS 1.1.20 </span><a name="cupsPutFile">cupsPutFile</a></h3>
-<p class="description">Put a file on the server.</p>
-<p class="code">
-http_status_t cupsPutFile (<br>
- http_t *http,<br>
- const char *resource,<br>
- const char *filename<br>
-);</p>
-<h4 class="parameters">Parameters</h4>
-<dl>
-<dt>http</dt>
-<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
-<dt>resource</dt>
-<dd class="description">Resource name</dd>
-<dt>filename</dt>
-<dd class="description">Filename</dd>
-</dl>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">HTTP status</p>
-<h4 class="discussion">Discussion</h4>
-<p class="discussion">This function returns <code>HTTP_CREATED</code> when the file is stored
-successfully.
-
-</p>
<h3 class="function"><span class="info"> CUPS 1.3 </span><a name="cupsRemoveDest">cupsRemoveDest</a></h3>
<p class="description">Remove a destination from the destination list.</p>
<p class="code">
<p class="code">
typedef struct <a href="#cups_dest_s">cups_dest_s</a> cups_dest_t;
</p>
+<h3 class="typedef"><span class="info"> CUPS 1.4 </span><a name="cups_device_cb_t">cups_device_cb_t</a></h3>
+<p class="description">Device callback </p>
+<p class="code">
+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);
+</p>
<h3 class="typedef"><a name="cups_job_t">cups_job_t</a></h3>
<p class="description">Job</p>
<p class="code">
<h3 class="typedef"><a name="cups_password_cb_t">cups_password_cb_t</a></h3>
<p class="description">Password callback</p>
<p class="code">
-typedef const char *(*cups_password_cb_t)(const char *);
+typedef const char *(*cups_password_cb_t)(const char *prompt);
</p>
<h3 class="typedef"><a name="cups_ptype_t">cups_ptype_t</a></h3>
<p class="description">Printer type/capability bits</p>
<li><a href="#cupsDoRequest" title="Do an IPP request.">cupsDoRequest</a></li>
<li><a href="#cupsEncodeOptions" title="Encode printer options into IPP attributes.">cupsEncodeOptions</a></li>
<li><a href="#cupsEncodeOptions2" title="Encode printer options into IPP attributes for a group.">cupsEncodeOptions2</a></li>
+<li><a href="#cupsGetDevices" title="Get available printer devices.">cupsGetDevices</a></li>
+<li><a href="#cupsGetFd" title="Get a file from the server.">cupsGetFd</a></li>
+<li><a href="#cupsGetFile" title="Get a file from the server.">cupsGetFile</a></li>
<li><a href="#cupsGetResponse" title="Get a response to an IPP request.">cupsGetResponse</a></li>
+<li><a href="#cupsPutFd" title="Put a file on the server.">cupsPutFd</a></li>
+<li><a href="#cupsPutFile" title="Put a file on the server.">cupsPutFile</a></li>
<li><a href="#cupsReadResponseData" title="Read additional data after the IPP response.">cupsReadResponseData</a></li>
<li><a href="#cupsSendRequest" title="Send an IPP request.">cupsSendRequest</a></li>
<li><a href="#cupsWriteRequestData" title="Write additional data after an IPP request.">cupsWriteRequestData</a></li>
function multiple times for each group, or use cupsEncodeOptions()
to add the standard groups.
+</p>
+<h3 class="function"><span class="info"> CUPS 1.4 </span><a name="cupsGetDevices">cupsGetDevices</a></h3>
+<p class="description">Get available printer devices.</p>
+<p class="code">
+ipp_status_t cupsGetDevices (<br>
+ <a href="#http_t">http_t</a> *http,<br>
+ int timeout,<br>
+ const char *exclude_schemes,<br>
+ cups_device_cb_t callback,<br>
+ void *user_data<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>timeout</dt>
+<dd class="description">Timeout in seconds or <code>CUPS_TIMEOUT_DEFAULT</code></dd>
+<dt>exclude_schemes</dt>
+<dd class="description">Comma-separated URI schemes to exclude or <code>CUPS_EXCLUDE_NONE</code></dd>
+<dt>callback</dt>
+<dd class="description">Callback function</dd>
+<dt>user_data</dt>
+<dd class="description">User data pointer</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Request status - <code>IPP_OK</code> on success.</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function sends a CUPS-Get-Devices request and streams the discovered
+devices to the specified callback function. The "timeout" parameter controls
+how long the request lasts, while the "exclude_schemes" parameter provides
+a comma-delimited list of backends to omit from the request.
+
+</p>
+<h3 class="function"><span class="info"> CUPS 1.1.20 </span><a name="cupsGetFd">cupsGetFd</a></h3>
+<p class="description">Get a file from the server.</p>
+<p class="code">
+http_status_t cupsGetFd (<br>
+ <a href="#http_t">http_t</a> *http,<br>
+ const char *resource,<br>
+ int fd<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>resource</dt>
+<dd class="description">Resource name</dd>
+<dt>fd</dt>
+<dd class="description">File descriptor</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns <code>HTTP_OK</code> when the file is successfully retrieved.
+
+</p>
+<h3 class="function"><span class="info"> CUPS 1.1.20 </span><a name="cupsGetFile">cupsGetFile</a></h3>
+<p class="description">Get a file from the server.</p>
+<p class="code">
+http_status_t cupsGetFile (<br>
+ <a href="#http_t">http_t</a> *http,<br>
+ const char *resource,<br>
+ const char *filename<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>resource</dt>
+<dd class="description">Resource name</dd>
+<dt>filename</dt>
+<dd class="description">Filename</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns <code>HTTP_OK</code> when the file is successfully retrieved.
+
</p>
<h3 class="function"><span class="info"> CUPS 1.4 </span><a name="cupsGetResponse">cupsGetResponse</a></h3>
<p class="description">Get a response to an IPP request.</p>
cupsSendDocument() or cupsSendRequest(). For requests that return
additional data, use httpRead() after getting a successful response.
+</p>
+<h3 class="function"><span class="info"> CUPS 1.1.20 </span><a name="cupsPutFd">cupsPutFd</a></h3>
+<p class="description">Put a file on the server.</p>
+<p class="code">
+http_status_t cupsPutFd (<br>
+ <a href="#http_t">http_t</a> *http,<br>
+ const char *resource,<br>
+ int fd<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>resource</dt>
+<dd class="description">Resource name</dd>
+<dt>fd</dt>
+<dd class="description">File descriptor</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns <code>HTTP_CREATED</code> when the file is stored
+successfully.
+
+</p>
+<h3 class="function"><span class="info"> CUPS 1.1.20 </span><a name="cupsPutFile">cupsPutFile</a></h3>
+<p class="description">Put a file on the server.</p>
+<p class="code">
+http_status_t cupsPutFile (<br>
+ <a href="#http_t">http_t</a> *http,<br>
+ const char *resource,<br>
+ const char *filename<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server or <code>CUPS_HTTP_DEFAULT</code></dd>
+<dt>resource</dt>
+<dd class="description">Resource name</dd>
+<dt>filename</dt>
+<dd class="description">Filename</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">HTTP status</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns <code>HTTP_CREATED</code> when the file is stored
+successfully.
+
</p>
<h3 class="function"><span class="info"> CUPS 1.4 </span><a name="cupsReadResponseData">cupsReadResponseData</a></h3>
<p class="description">Read additional data after the IPP response.</p>
<dt>resource</dt>
<dd class="description">Resource path</dd>
<dt>length</dt>
-<dd class="description">Length of data to follow or CUPS_LENGTH_VARIABLE</dd>
+<dd class="description">Length of data to follow or <code>CUPS_LENGTH_VARIABLE</code></dd>
</dl>
<h4 class="returnvalue">Return Value</h4>
<p class="description">Initial HTTP status</p>
<dd>The client OPTIONALLY supplies a device class keyword to select
which devices are returned.
+ <dt>"exclude-schemes" (1setOf name) :<span class='info'>CUPS 1.4</span>
+
+ <dd>The client OPTIONALLY supplies a set of scheme names that the
+ requestor does not want to discover. If the client omits this attribute,
+ the server responds with devices of all schemes.
+
<dt>"limit" (integer (1:MAX)):
<dd>The client OPTIONALLY supplies this attribute limiting the number of
the client omits this attribute, the server responds as if this
attribute had been supplied with a value of 'all'.
+ <dt>"timeout" (integer (1:MAX)) :<span class='info'>CUPS 1.4</span>
+
+ <dd>The client OPTIONALLY supplies this attribute limiting the number of
+ devices that are returned.
+
</dl>
<h4>CUPS-Get-Devices Response</h4>
*
* Raster error handling for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
* Initialize the global data exactly once...
*/
- DEBUG_printf(("get_error_buffer(): raster_key_once=%d\n",
- raster_key_once));
+ DEBUG_puts("get_error_buffer()");
pthread_once(&raster_key_once, raster_init);
{
pthread_key_create(&raster_key, raster_destructor);
- DEBUG_printf(("raster_init(): raster_key=%x(%u)\n", raster_key,
- raster_key));
+ DEBUG_printf(("raster_init(): raster_key=%x(%u)\n", (unsigned)raster_key,
+ (unsigned)raster_key));
}
while ((obj = scan_ps(st, &codeptr)) != NULL)
{
#ifdef DEBUG
- printf(" (%d): ", st->num_objs);
+ DEBUG_printf(("_cupsRasterExecPS: Stack (%d objects)\n", st->num_objs));
DEBUG_object(obj);
- putchar('\n');
#endif /* DEBUG */
switch (obj->type)
_cupsRasterAddError("cleartomark: Stack underflow!\n");
#ifdef DEBUG
- fputs(" dup: ", stdout);
+ DEBUG_puts(" dup: ");
DEBUG_stack(st);
#endif /* DEBUG */
break;
copy_stack(st, (int)obj->value.number);
#ifdef DEBUG
- fputs(" copy: ", stdout);
+ DEBUG_puts("_cupsRasterExecPS: copy");
DEBUG_stack(st);
#endif /* DEBUG */
}
copy_stack(st, 1);
#ifdef DEBUG
- fputs(" dup: ", stdout);
+ DEBUG_puts("_cupsRasterExecPS: dup");
DEBUG_stack(st);
#endif /* DEBUG */
break;
index_stack(st, (int)obj->value.number);
#ifdef DEBUG
- fputs(" index: ", stdout);
+ DEBUG_puts("_cupsRasterExecPS: index");
DEBUG_stack(st);
#endif /* DEBUG */
}
pop_stack(st);
#ifdef DEBUG
- fputs(" pop: ", stdout);
+ DEBUG_puts("_cupsRasterExecPS: pop");
DEBUG_stack(st);
#endif /* DEBUG */
break;
roll_stack(st, (int)obj->value.number, c);
#ifdef DEBUG
- fputs(" roll:", stdout);
+ DEBUG_puts("_cupsRasterExecPS: roll");
DEBUG_stack(st);
#endif /* DEBUG */
}
setpagedevice(st, h, preferred_bits);
#ifdef DEBUG
- fputs(" setpagedevice: ", stdout);
+ DEBUG_puts("_cupsRasterExecPS: setpagedevice");
DEBUG_stack(st);
#endif /* DEBUG */
break;
case CUPS_PS_OTHER :
_cupsRasterAddError("Unknown operator \"%s\"!\n", obj->value.other);
- DEBUG_printf((" Unknown operator \"%s\"!\n", obj->value.other));
+ DEBUG_printf(("_cupsRasterExecPS: Unknown operator \"%s\"!\n",
+ obj->value.other));
break;
}
error_stack(st, "Stack not empty:");
#ifdef DEBUG
- fputs(" Stack not empty:", stdout);
+ DEBUG_puts("_cupsRasterExecPS: Stack not empty:");
DEBUG_stack(st);
#endif /* DEBUG */
* Now pull /name and value pairs from the dictionary...
*/
- DEBUG_puts(" Dictionary:");
+ DEBUG_puts("setpagedevice: Dictionary:");
for (obj ++; obj < end; obj ++)
{
obj ++;
#ifdef DEBUG
- printf(" /%s ", name);
+ DEBUG_printf(("setpagedevice: /%s ", name));
DEBUG_object(obj);
- putchar('\n');
#endif /* DEBUG */
/*
switch (obj->type)
{
case CUPS_PS_NAME :
- printf("/%s", obj->value.name);
+ DEBUG_printf(("/%s\n", obj->value.name));
break;
case CUPS_PS_NUMBER :
- printf("%g", obj->value.number);
+ DEBUG_printf(("%g\n", obj->value.number));
break;
case CUPS_PS_STRING :
- printf("(%s)", obj->value.string);
+ DEBUG_printf(("(%s)\n", obj->value.string));
break;
case CUPS_PS_BOOLEAN :
if (obj->value.boolean)
- fputs("true", stdout);
+ DEBUG_puts("true");
else
- fputs("false", stdout);
+ DEBUG_puts("false");
break;
case CUPS_PS_NULL :
- fputs("null", stdout);
+ DEBUG_puts("null");
break;
case CUPS_PS_START_ARRAY :
- fputs("[", stdout);
+ DEBUG_puts("[");
break;
case CUPS_PS_END_ARRAY :
- fputs("]", stdout);
+ DEBUG_puts("]");
break;
case CUPS_PS_START_DICT :
- fputs("<<", stdout);
+ DEBUG_puts("<<");
break;
case CUPS_PS_END_DICT :
- fputs(">>", stdout);
+ DEBUG_puts(">>");
break;
case CUPS_PS_START_PROC :
- fputs("{", stdout);
+ DEBUG_puts("{");
break;
case CUPS_PS_END_PROC :
- fputs("}", stdout);
+ DEBUG_puts("}");
break;
case CUPS_PS_CLEARTOMARK :
- fputs("--cleartomark--", stdout);
+ DEBUG_puts("--cleartomark--");
break;
case CUPS_PS_COPY :
- fputs("--copy--", stdout);
+ DEBUG_puts("--copy--");
break;
case CUPS_PS_DUP :
- fputs("--dup--", stdout);
+ DEBUG_puts("--dup--");
break;
case CUPS_PS_INDEX :
- fputs("--index--", stdout);
+ DEBUG_puts("--index--");
break;
case CUPS_PS_POP :
- fputs("--pop--", stdout);
+ DEBUG_puts("--pop--");
break;
case CUPS_PS_ROLL :
- fputs("--roll--", stdout);
+ DEBUG_puts("--roll--");
break;
case CUPS_PS_SETPAGEDEVICE :
- fputs("--setpagedevice--", stdout);
+ DEBUG_puts("--setpagedevice--");
break;
case CUPS_PS_STOPPED :
- fputs("--stopped--", stdout);
+ DEBUG_puts("--stopped--");
break;
case CUPS_PS_OTHER :
- printf("--%s--", obj->value.other);
+ DEBUG_printf(("--%s--\n", obj->value.other));
break;
}
}
for (obj = st->objs, c = st->num_objs; c > 0; c --, obj ++)
- {
- putchar(' ');
DEBUG_object(obj);
- }
-
- putchar('\n');
}
#endif /* DEBUG */
pdfwaitpid, /* Process ID from wait() */
pdfstatus, /* Status from pdftops */
pdfargc; /* Number of args for pdftops */
- char *pdfargv[100], /* Arguments for pdftops */
+ char *pdfargv[100], /* Arguments for pdftops/gs */
+#ifdef HAVE_PDFTOPS
pdfwidth[255], /* Paper width */
pdfheight[255]; /* Paper height */
+#else
+ pdfgeometry[255]; /* Paper width and height */
+#endif /* HAVE_PDFTOPS */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action; /* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
cupsMarkOptions(ppd, num_options, options);
/*
- * Build the command-line for the pdftops filter...
+ * Build the command-line for the pdftops or gs filter...
*/
+#ifdef HAVE_PDFTOPS
pdfargv[0] = (char *)"pdftops";
pdfargc = 1;
+#else
+ pdfargv[0] = (char *)"gs";
+ pdfargv[1] = (char *)"-q";
+ pdfargv[2] = (char *)"-dNOPAUSE";
+ pdfargv[3] = (char *)"-dBATCH";
+ pdfargv[4] = (char *)"-dSAFER";
+ pdfargv[5] = (char *)"-sDEVICE=pswrite";
+ pdfargv[6] = (char *)"-sOUTPUTFILE=%stdout";
+ pdfargc = 7;
+#endif /* HAVE_PDFTOPS */
if (ppd)
{
if (ppd->language_level == 1)
{
+#ifdef HAVE_PDFTOPS
pdfargv[pdfargc++] = (char *)"-level1";
pdfargv[pdfargc++] = (char *)"-noembtt";
+#else
+ pdfargv[pdfargc++] = (char *)"-dLanguageLevel=1";
+#endif /* HAVE_PDFTOPS */
}
else if (ppd->language_level == 2)
{
+#ifdef HAVE_PDFTOPS
pdfargv[pdfargc++] = (char *)"-level2";
if (!ppd->ttrasterizer)
pdfargv[pdfargc++] = (char *)"-noembtt";
+#else
+ pdfargv[pdfargc++] = (char *)"-dLanguageLevel=2";
+#endif /* HAVE_PDFTOPS */
}
else
+#ifdef HAVE_PDFTOPS
pdfargv[pdfargc++] = (char *)"-level3";
+#else
+ pdfargv[pdfargc++] = (char *)"-dLanguageLevel=3";
+#endif /* HAVE_PDFTOPS */
/*
* Set output page size...
orientation ^= 1;
}
+#ifdef HAVE_PDFTOPS
if (orientation & 1)
{
snprintf(pdfwidth, sizeof(pdfwidth), "%.0f", size->length);
pdfargv[pdfargc++] = pdfwidth;
pdfargv[pdfargc++] = (char *)"-paperh";
pdfargv[pdfargc++] = pdfheight;
+#else
+ if (orientation & 1)
+ snprintf(pdfgeometry, sizeof(pdfgeometry), "-g%.0fx%.0f", size->length,
+ size->width);
+ else
+ snprintf(pdfgeometry, sizeof(pdfgeometry), "-g%.0fx%.0f", size->width,
+ size->length);
+
+ pdfargv[pdfargc++] = pdfgeometry;
+#endif /* HAVE_PDFTOPS */
}
}
+#ifdef HAVE_PDFTOPS
if ((val = cupsGetOption("fitplot", num_options, options)) != NULL &&
strcasecmp(val, "no") && strcasecmp(val, "off") &&
strcasecmp(val, "false"))
pdfargv[pdfargc++] = filename;
pdfargv[pdfargc++] = (char *)"-";
- pdfargv[pdfargc] = NULL;
+#else
+ pdfargv[pdfargc++] = (char *)"-c";
+ pdfargv[pdfargc++] = (char *)"save pop";
+ pdfargv[pdfargc++] = (char *)"-f";
+ pdfargv[pdfargc++] = filename;
+#endif /* HAVE_PDFTOPS */
+
+ pdfargv[pdfargc] = NULL;
if ((pdfpid = fork()) == 0)
{
* Child comes here...
*/
+#ifdef HAVE_PDFTOPS
execv(CUPS_PDFTOPS, pdfargv);
- _cupsLangPrintError(_("ERROR: Unable to execute pdftops filter"));
+ _cupsLangPrintError(_("ERROR: Unable to execute pdftops program"));
+#else
+ execv(CUPS_GHOSTSCRIPT, pdfargv);
+ _cupsLangPrintError(_("ERROR: Unable to execute gs program"));
+#endif /* HAVE_PDFTOPS */
+
exit(1);
}
else if (pdfpid < 0)
* Unable to fork!
*/
- _cupsLangPrintError(_("ERROR: Unable to execute pdftops filter"));
+#ifdef HAVE_PDFTOPS
+ _cupsLangPrintError(_("ERROR: Unable to execute pdftops program"));
+#else
+ _cupsLangPrintError(_("ERROR: Unable to execute gs program"));
+#endif /* HAVE_PDFTOPS */
+
pdfstatus = 1;
}
else
void
EndPage(const cups_page_header2_t *header) /* I - Page header */
{
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Actions for POSIX signals */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-
-
if (DotBytes && header)
{
/*
{
int val; /* Option value */
ppd_choice_t *choice; /* Marked choice */
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Actions for POSIX signals */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
switch (ModelNumber)
*
* "mailto" notifier for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2005 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
cupsFilePrintf(fp, "Content-Type: text/plain%s", nl);
cupsFilePuts(fp, nl);
cupsFilePrintf(fp, "%s%s", text, nl);
- cupsFilePrintf(fp, ".\n", nl);
+ cupsFilePrintf(fp, ".%s", nl);
/*
* Close the connection to the mail server...
FILE *fp; /* File pointer */
_cups_rss_t *msg; /* Current message */
char date[1024]; /* Current date */
+ char *href; /* Escaped base URL */
if ((fp = fopen(filename, "w")) == NULL)
fputs("<rss version=\"2.0\">\n", fp);
fputs(" <channel>\n", fp);
fputs(" <title>CUPS RSS Feed</title>\n", fp);
- fprintf(fp, " <link>%s</link>\n", baseurl);
+
+ href = xml_escape(baseurl);
+ fprintf(fp, " <link>%s</link>\n", href);
+ free(href);
+
fputs(" <description>CUPS RSS Feed</description>\n", fp);
fputs(" <generator>" CUPS_SVERSION "</generator>\n", fp);
fputs(" <ttl>1</ttl>\n", fp);
if ((fp = cupsFileOpen(f, "r")) == NULL)
return (-1);
- if ((ptr = strrchr(f, '.')) == NULL)
+ if ((ptr = (char *)strrchr(f, '.')) == NULL)
goto unknown_load_format;
else if (!strcmp(ptr, ".strings"))
{
continue;
// Strip the trailing quote...
- if ((ptr = strrchr(line, '\"')) == NULL)
+ if ((ptr = (char *)strrchr(line, '\"')) == NULL)
{
fprintf(stderr, "ERROR: Expected quoted string on line %d of %s!\n",
linenum, f);
// Open the file...
- if ((ptr = strrchr(f, '.')) == NULL)
+ if ((ptr = (char *)strrchr(f, '.')) == NULL)
return (-1);
if (!strcmp(ptr, ".gz"))
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdWriteClient(con=%p) %d response=%p(%d), file=%d "
"pipe_pid=%d state=%d",
- con, con->http.fd, con->response, con->response->state,
+ con, con->http.fd, con->response,
+ con->response ? con->response->state : -1,
con->file, con->pipe_pid, con->http.state);
#endif /* DEBUG */
return;
}
+ httpFlushWrite(HTTP(con));
+
con->bytes += bytes;
if (con->http.state == HTTP_WAITING)
cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions");
cupsdSetString(&FontPath, CUPS_FONTPATH);
cupsdSetString(&RemoteRoot, "remroot");
- cupsdSetString(&ServerHeader, "CUPS/1.2");
+ cupsdSetString(&ServerHeader, "CUPS/1.4");
cupsdSetString(&StateDir, CUPS_STATEDIR);
#ifdef HAVE_GSSAPI
cupsdSetString(&GSSServiceName, CUPS_DEFAULT_GSSSERVICENAME);
* writable by the user and group in the cupsd.conf file...
*/
+ snprintf(temp, sizeof(temp), "%s/rss", CacheDir);
+
if (cupsdCheckPermissions(RequestRoot, NULL, 0710, RunUser,
Group, 1, 1) < 0 ||
cupsdCheckPermissions(CacheDir, NULL, 0775, RunUser,
Group, 1, 1) < 0 ||
+ cupsdCheckPermissions(temp, NULL, 0775, RunUser,
+ Group, 1, 1) < 0 ||
cupsdCheckPermissions(StateDir, NULL, 0755, RunUser,
Group, 1, 1) < 0 ||
cupsdCheckPermissions(StateDir, "certs", RunUser ? 0711 : 0511, User,
else if (!strcasecmp(value, "Major"))
cupsdSetString(&ServerHeader, "CUPS/1");
else if (!strcasecmp(value, "Minor"))
- cupsdSetString(&ServerHeader, "CUPS/1.2");
+ cupsdSetString(&ServerHeader, "CUPS/1.4");
else if (!strcasecmp(value, "Minimal"))
cupsdSetString(&ServerHeader, CUPS_MINIMAL);
else if (!strcasecmp(value, "OS"))
*
* Contents:
*
- * main() - Scan for devices and return an IPP response.
- * add_dev() - Add a new device to the list.
- * compare_devs() - Compare device names for sorting.
- * run_backend() - Run a backend to gather the available devices.
- * sigalrm_handler() - Handle alarm signals for backends that get hung
+ * main() - Scan for devices and return an IPP response.
+ * add_device() - Add a new device to the list.
+ * compare_devices() - Compare device names to eliminate duplicates.
+ * create_strings_array() - Create a CUPS array of strings.
+ * get_current_time() - Get the current time as a double value in seconds.
+ * get_device() - Get a device from a backend.
+ * process_children() - Process all dead children...
+ * sigchld_handler() - Handle 'child' signals from old processes.
+ * start_backend() - Run a backend to gather the available devices.
*/
/*
#include <cups/array.h>
#include <cups/dir.h>
#include <fcntl.h>
+#include <sys/wait.h>
+#include <poll.h>
+
+
+/*
+ * Constants...
+ */
+
+#define MAX_BACKENDS 200 /* Maximum number of backends we'll run */
+
+
+/*
+ * Backend information...
+ */
+
+typedef struct
+{
+ char *name; /* Name of backend */
+ int pid, /* Process ID */
+ status; /* Exit status */
+ cups_file_t *pipe; /* Pipe from backend stdout */
+ int count; /* Number of devices found */
+} cupsd_backend_t;
/*
device_info[128], /* Device info/description */
device_uri[1024], /* Device URI */
device_id[1024]; /* 1284 Device ID */
-} dev_info_t;
+} cupsd_device_t;
/*
* Local globals...
*/
-static int alarm_tripped; /* Non-zero if alarm was tripped */
-static cups_array_t *devs; /* Device info */
+static int num_backends = 0,
+ /* Total backends */
+ active_backends = 0;
+ /* Active backends */
+static cupsd_backend_t backends[MAX_BACKENDS];
+ /* Array of backends */
+static struct pollfd backend_fds[MAX_BACKENDS];
+ /* Array for poll() */
+static cups_array_t *devices; /* Array of devices */
static int normal_user; /* Normal user ID */
+static int device_limit; /* Maximum number of devices */
+static int send_class, /* Send device-class attribute? */
+ send_info, /* Send device-info attribute? */
+ send_make_and_model,
+ /* Send device-make-and-model attribute? */
+ send_uri, /* Send device-uri attribute? */
+ send_id; /* Send device-id attribute? */
+static int dead_children = 0;
+ /* Dead children? */
/*
* 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,
- const char *device_id);
-static int compare_devs(dev_info_t *p0, dev_info_t *p1);
-static FILE *run_backend(const char *backend, int uid, int *pid);
-static void sigalrm_handler(int sig);
+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);
+static int compare_devices(cupsd_device_t *p0,
+ cupsd_device_t *p1);
+static cups_array_t *create_strings_array(const char *s);
+static double get_current_time(void);
+static int get_device(cupsd_backend_t *backend);
+static void process_children(void);
+static void sigchld_handler(int sig);
+static int start_backend(const char *backend, int root);
/*
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 i; /* Looping var */
int request_id; /* Request ID */
- int count; /* Number of devices from backend */
- int compat; /* Compatibility device? */
- FILE *fp; /* Pipe to device backend */
- int pid; /* Process ID of backend */
+ int timeout; /* Timeout in seconds */
+ const char *server_bin; /* CUPS_SERVERBIN environment variable */
+ char filename[1024]; /* Backend directory filename */
cups_dir_t *dir; /* Directory pointer */
cups_dentry_t *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 */
- device_id[1024]; /* 1284 device ID */
+ double current_time, /* Current time */
+ end_time; /* Ending time */
int num_options; /* Number of options */
cups_option_t *options; /* Options */
- const char *requested; /* requested-attributes option */
- int send_class, /* Send device-class attribute? */
- send_info, /* Send device-info attribute? */
- send_make_and_model, /* Send device-make-and-model attribute? */
- send_uri, /* Send device-uri attribute? */
- send_id; /* Send device-id attribute? */
- dev_info_t *dev; /* Current device */
+ cups_array_t *requested, /* requested-attributes values */
+ *exclude; /* exclude-schemes values */
#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 > 1)
- request_id = atoi(argv[1]);
- else
- request_id = 1;
-
- if (argc != 5)
+ if (argc != 6)
{
- fputs("Usage: cups-deviced request-id limit user-id options\n", stderr);
+ fputs("Usage: cups-deviced request-id limit timeout user-id options\n", stderr);
return (1);
}
+ request_id = atoi(argv[1]);
if (request_id < 1)
{
- fprintf(stderr, "cups-deviced: Bad request ID %d!\n", request_id);
+ fprintf(stderr, "ERROR: [cups-deviced] Bad request ID %d!\n", request_id);
return (1);
}
- normal_user = atoi(argv[3]);
- if (normal_user <= 0)
+ device_limit = atoi(argv[2]);
+ if (device_limit < 0)
{
- fprintf(stderr, "cups-deviced: Bad user %d!\n", normal_user);
+ fprintf(stderr, "ERROR: [cups-deviced] Bad limit %d!\n", device_limit);
return (1);
}
- num_options = cupsParseOptions(argv[4], 0, &options);
- requested = cupsGetOption("requested-attributes", num_options, options);
+ timeout = atoi(argv[3]);
+ if (timeout < 1)
+ {
+ fprintf(stderr, "ERROR: [cups-deviced] Bad timeout %d!\n", timeout);
+
+ return (1);
+ }
- if (!requested || strstr(requested, "all"))
+ normal_user = atoi(argv[4]);
+ if (normal_user <= 0)
{
- send_class = 1;
- send_info = 1;
- send_make_and_model = 1;
- send_uri = 1;
- send_id = 1;
+ fprintf(stderr, "ERROR: [cups-deviced] Bad user %d!\n", normal_user);
+
+ return (1);
}
+
+ num_options = cupsParseOptions(argv[5], 0, &options);
+ requested = create_strings_array(cupsGetOption("requested-attributes",
+ num_options, options));
+ exclude = create_strings_array(cupsGetOption("exclude-schemes",
+ num_options, options));
+
+ if (!requested || cupsArrayFind(requested, "all") != NULL)
+ send_class = send_info = send_make_and_model = send_uri = send_id = 1;
else
{
- send_class = strstr(requested, "device-class") != NULL;
- send_info = strstr(requested, "device-info") != NULL;
- send_make_and_model = strstr(requested, "device-make-and-model") != NULL;
- send_uri = strstr(requested, "device-uri") != NULL;
- send_id = strstr(requested, "device-id") != NULL;
+ send_class = cupsArrayFind(requested, "device-class") != NULL;
+ send_info = cupsArrayFind(requested, "device-info") != NULL;
+ send_make_and_model = cupsArrayFind(requested, "device-make-and-model") != NULL;
+ send_uri = cupsArrayFind(requested, "device-uri") != NULL;
+ send_id = cupsArrayFind(requested, "device-id") != NULL;
}
+ /*
+ * Listen to child signals...
+ */
+
+#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGCHLD, sigchld_handler);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGCHLD);
+ action.sa_handler = sigchld_handler;
+ sigaction(SIGCHLD, &action, NULL);
+#else
+ signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
+#endif /* HAVE_SIGSET */
+
/*
* Try opening the backend directory...
*/
if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
server_bin = CUPS_SERVERBIN;
- snprintf(backends, sizeof(backends), "%s/backend", server_bin);
+ snprintf(filename, sizeof(filename), "%s/backend", server_bin);
- if ((dir = cupsDirOpen(backends)) == NULL)
+ if ((dir = cupsDirOpen(filename)) == NULL)
{
fprintf(stderr, "ERROR: [cups-deviced] Unable to open backend directory "
- "\"%s\": %s", backends, strerror(errno));
+ "\"%s\": %s", filename, strerror(errno));
return (1);
}
* Setup the devices array...
*/
- devs = cupsArrayNew((cups_array_func_t)compare_devs, NULL);
+ devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL);
/*
* Loop through all of the device backends...
*/
if (!S_ISREG(dent->fileinfo.st_mode) ||
+ !isalnum(dent->filename[0] & 255) ||
(dent->fileinfo.st_mode & (S_IRUSR | S_IXUSR)) != (S_IRUSR | S_IXUSR))
continue;
- /*
- * Change effective users depending on the backend permissions...
- */
-
- snprintf(filename, sizeof(filename), "%s/%s", backends, dent->filename);
+ if (cupsArrayFind(exclude, dent->filename))
+ continue;
/*
* Backends without permissions for normal users run as root,
* all others run as the unprivileged user...
*/
- fp = run_backend(filename,
- (dent->fileinfo.st_mode & (S_IRWXG | S_IRWXO))
- ? normal_user : 0,
- &pid);
-
- /*
- * Collect the output from the backend...
- */
-
- if (fp)
- {
- /*
- * 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->filename, "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" ["1284 device ID"]
- */
-
- device_id[0] = '\0';
-
- if (!strncasecmp(line, "Usage", 5))
- compat = 1;
- else if (sscanf(line,
- "%63s%1023s%*[ \t]\"%255[^\"]\"%*[ \t]\"%127[^\"]\""
- "%*[ \t]\"%1023[^\"]",
- dclass, uri, make_model, info, device_id) < 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->filename, line);
- compat = 1;
- break;
- }
- else
- {
- /*
- * Add the device to the array of available devices...
- */
-
- dev = add_dev(dclass, make_model, info, uri, device_id);
- if (!dev)
- {
- cupsDirClose(dir);
- fclose(fp);
- kill(pid, SIGTERM);
- 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->filename);
-
- fclose(fp);
- kill(pid, SIGTERM);
-
- /*
- * 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->filename);
-
- dev = add_dev("network", line, "Unknown", dent->filename, "");
- if (!dev)
- {
- cupsDirClose(dir);
- return (1);
- }
-
- fprintf(stderr, "DEBUG: [cups-deviced] Compatibility device "
- "\"%s\"...\n", dent->filename);
- }
- }
- else
- fprintf(stderr, "WARNING: [cups-deviced] Unable to execute \"%s\" "
- "backend: %s\n", dent->filename, strerror(errno));
+ start_backend(dent->filename,
+ !(dent->fileinfo.st_mode & (S_IRWXG | S_IRWXO)));
}
cupsDirClose(dir);
/*
- * Output the list of devices...
+ * Collect devices...
*/
- puts("Content-Type: application/ipp\n");
+ if (getenv("SOFTWARE"))
+ puts("Content-Type: application/ipp\n");
cupsdSendIPPHeader(IPP_OK, request_id);
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 = cupsArrayCount(devs);
-
- if (count > cupsArrayCount(devs))
- count = cupsArrayCount(devs);
+ end_time = get_current_time() + timeout;
- for (dev = (dev_info_t *)cupsArrayFirst(devs);
- count > 0;
- count --, dev = (dev_info_t *)cupsArrayNext(devs))
+ while (active_backends > 0 && (current_time = get_current_time()) < end_time)
{
/*
- * Add strings to attributes...
+ * Collect the output from the backends...
+ */
+
+ timeout = (int)(1000 * (end_time - current_time));
+
+ if (poll(backend_fds, num_backends, timeout) > 0)
+ {
+ for (i = 0; i < num_backends; i ++)
+ if (backend_fds[i].revents && backends[i].pipe)
+ if (get_device(backends + i))
+ {
+ backend_fds[i].fd = 0;
+ backend_fds[i].events = 0;
+ }
+ }
+
+ /*
+ * Get exit status from children...
*/
- cupsdSendIPPGroup(IPP_TAG_PRINTER);
- if (send_class)
- cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class", dev->device_class);
- if (send_info)
- cupsdSendIPPString(IPP_TAG_TEXT, "device-info", dev->device_info);
- if (send_make_and_model)
- cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model",
- dev->device_make_and_model);
- if (send_uri)
- cupsdSendIPPString(IPP_TAG_URI, "device-uri", dev->device_uri);
- if (send_id)
- cupsdSendIPPString(IPP_TAG_TEXT, "device-id", dev->device_id);
+ if (dead_children)
+ process_children();
}
cupsdSendIPPTrailer();
/*
- * Free the devices array and return...
+ * Terminate any remaining backends and exit...
*/
- for (dev = (dev_info_t *)cupsArrayFirst(devs);
- dev;
- dev = (dev_info_t *)cupsArrayNext(devs))
- free(dev);
-
- cupsArrayDelete(devs);
+ if (active_backends > 0)
+ {
+ for (i = 0; i < num_backends; i ++)
+ if (backends[i].pid)
+ kill(backends[i].pid, SIGTERM);
+ }
return (0);
}
/*
- * 'add_dev()' - Add a new device to the list.
+ * 'add_device()' - Add a new device to the list.
*/
-static dev_info_t * /* O - New device or NULL on error */
-add_dev(
+static int /* O - 0 on success, -1 on error */
+add_device(
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 */
const char *device_id) /* I - 1284 device ID */
{
- dev_info_t *dev, /* New device */
- *temp; /* Found device */
+ cupsd_device_t *device, /* New device */
+ *temp; /* Found device */
/*
* Allocate memory for the device record...
*/
- if ((dev = calloc(1, sizeof(dev_info_t))) == NULL)
+ if ((device = calloc(1, sizeof(cupsd_device_t))) == NULL)
{
fputs("ERROR: [cups-deviced] Ran out of memory allocating a device!\n",
stderr);
- return (NULL);
+ return (-1);
}
/*
* Copy the strings over...
*/
- 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));
- strlcpy(dev->device_id, device_id, sizeof(dev->device_id));
+ 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...
*/
- if ((temp = cupsArrayFind(devs, dev)) != NULL)
+ if ((temp = cupsArrayFind(devices, device)) != NULL)
{
/*
* Avoid duplicates!
*/
- free(dev);
- dev = temp;
+ free(device);
}
else
- cupsArrayAdd(devs, dev);
-
- return (dev);
+ {
+ cupsArrayAdd(devices, device);
+
+ if (device_limit <= 0 || cupsArrayCount(devices) < device_limit)
+ {
+ /*
+ * Send device info...
+ */
+
+ cupsdSendIPPGroup(IPP_TAG_PRINTER);
+ if (send_class)
+ cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class",
+ device->device_class);
+ if (send_info)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-info", device->device_info);
+ if (send_make_and_model)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model",
+ device->device_make_and_model);
+ if (send_uri)
+ cupsdSendIPPString(IPP_TAG_URI, "device-uri", device->device_uri);
+ if (send_id)
+ cupsdSendIPPString(IPP_TAG_TEXT, "device-id", device->device_id);
+
+ fflush(stdout);
+ fputs("DEBUG: Flushed attributes...\n", stderr);
+ }
+ }
+
+ return (0);
}
/*
- * 'compare_devs()' - Compare device names for sorting.
+ * 'compare_devices()' - Compare device names to eliminate duplicates.
*/
static int /* O - Result of comparison */
-compare_devs(dev_info_t *d0, /* I - First device */
- dev_info_t *d1) /* I - Second device */
+compare_devices(cupsd_device_t *d0, /* I - First device */
+ cupsd_device_t *d1) /* I - Second device */
{
int diff; /* Difference between strings */
/*
- * 'run_backend()' - Run a backend to gather the available devices.
+ * 'create_strings_array()' - Create a CUPS array of strings.
*/
-static FILE * /* O - stdout of backend */
-run_backend(const char *backend, /* I - Backend to run */
- int uid, /* I - User ID to run as */
- int *pid) /* O - Process ID of backend */
+static cups_array_t * /* O - CUPS array */
+create_strings_array(const char *s) /* I - Comma-delimited strings */
{
- int fds[2]; /* Pipe file descriptors */
+ cups_array_t *a; /* CUPS array */
+ const char *start, /* Start of string */
+ *end; /* End of string */
+ char *ptr; /* New string */
+
+
+ if (!s)
+ return (NULL);
+
+ if ((a = cupsArrayNew((cups_array_func_t)strcmp, NULL)) != NULL)
+ {
+ for (start = end = s; *end; start = end + 1)
+ {
+ /*
+ * Find the end of the current delimited string...
+ */
+
+ if ((end = strchr(start, ',')) == NULL)
+ end = start + strlen(start);
+
+ /*
+ * Duplicate the string and add it to the array...
+ */
+
+ if ((ptr = calloc(1, end - start + 1)) == NULL)
+ break;
+ memcpy(ptr, start, end - start);
+ cupsArrayAdd(a, ptr);
+ }
+ }
+
+ return (a);
+}
+
+
+/*
+ * 'get_current_time()' - Get the current time as a double value in seconds.
+ */
+
+static double /* O - Time in seconds */
+get_current_time(void)
+{
+ struct timeval curtime; /* Current time */
+
+
+ gettimeofday(&curtime, NULL);
+
+ return (curtime.tv_sec + 0.000001 * curtime.tv_usec);
+}
+
+
+/*
+ * 'get_device()' - Get a device from a backend.
+ */
+
+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 */
+
+
+ if (cupsFileGets(backend->pipe, line, sizeof(line)))
+ {
+ /*
+ * Each line is of the form:
+ *
+ * class URI "make model" "name" ["1284 device ID"]
+ */
+
+ device_id[0] = '\0';
+
+ if (sscanf(line,
+ "%63s%1023s%*[ \t]\"%255[^\"]\"%*[ \t]\"%127[^\"]\""
+ "%*[ \t]\"%1023[^\"]",
+ dclass, uri, make_model, info, device_id) < 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",
+ backend->name, line);
+ }
+ else
+ {
+ /*
+ * Add the device to the array of available devices...
+ */
+
+ if (!add_device(dclass, make_model, info, uri, device_id))
+ fprintf(stderr, "DEBUG: [cups-deviced] Found device \"%s\"...\n", uri);
+ }
+
+ return (0);
+ }
+
+ /*
+ * End of file...
+ */
+
+ cupsFileClose(backend->pipe);
+ backend->pipe = NULL;
+
+ return (-1);
+}
+
+
+/*
+ * 'process_children()' - Process all dead children...
+ */
+
+static void
+process_children(void)
+{
+ int i; /* Looping var */
+ int status; /* Exit status of child */
+ int pid; /* Process ID of child */
+ cupsd_backend_t *backend; /* Current backend */
+ const char *name; /* Name of process */
+
+
+ /*
+ * Reset the dead_children flag...
+ */
+
+ dead_children = 0;
+
+ /*
+ * Collect the exit status of some children...
+ */
+
+#ifdef HAVE_WAITPID
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+#elif defined(HAVE_WAIT3)
+ while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
+#else
+ if ((pid = wait(&status)) > 0)
+#endif /* HAVE_WAITPID */
+ {
+ if (status == SIGTERM)
+ status = 0;
+
+ for (i = num_backends, backend = backends; i > 0; i --, backend ++)
+ if (backend->pid == pid)
+ break;
+
+ if (i > 0)
+ {
+ name = backend->name;
+ backend->pid = 0;
+ backend->status = status;
+
+ active_backends --;
+ }
+ else
+ name = "Unknown";
+
+ if (status)
+ {
+ if (WIFEXITED(status))
+ fprintf(stderr,
+ "ERROR: [cups-deviced] PID %d (%s) stopped with status %d!\n",
+ pid, name, WEXITSTATUS(status));
+ else
+ fprintf(stderr,
+ "ERROR: [cups-deviced] PID %d (%s) crashed on signal %d!\n",
+ pid, name, WTERMSIG(status));
+ }
+ else
+ fprintf(stderr,
+ "DEBUG: [cups-deviced] PID %d (%s) exited with no errors.\n",
+ pid, name);
+ }
+}
+
+
+/*
+ * 'sigchld_handler()' - Handle 'child' signals from old processes.
+ */
+
+static void
+sigchld_handler(int sig) /* I - Signal number */
+{
+ (void)sig;
+
+ /*
+ * Flag that we have dead children...
+ */
+
+ dead_children = 1;
+
+ /*
+ * Reset the signal handler as needed...
+ */
+
+#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
+ signal(SIGCLD, sigchld_handler);
+#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
+}
+
+
+/*
+ * 'start_backend()' - Run a backend to gather the available devices.
+ */
+
+static int /* O - 0 on success, -1 on error */
+start_backend(const char *name, /* I - Backend to run */
+ int root) /* I - Run as root? */
+{
+ const char *server_bin; /* CUPS_SERVERBIN environment variable */
+ char program[1024]; /* Full path to backend */
+ int fds[2]; /* Pipe file descriptors */
+ cupsd_backend_t *backend; /* Current backend */
+
+
+ if (num_backends >= MAX_BACKENDS)
+ {
+ fprintf(stderr, "ERROR: Too many backends (%d)!\n", num_backends);
+ return (-1);
+ }
if (pipe(fds))
{
fprintf(stderr, "ERROR: Unable to create a pipe for \"%s\" - %s\n",
- backend, strerror(errno));
- return (NULL);
+ name, strerror(errno));
+ return (-1);
}
- if ((*pid = fork()) < 0)
+ if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
+ server_bin = CUPS_SERVERBIN;
+
+ snprintf(program, sizeof(program), "%s/backend/%s", server_bin, name);
+
+ backend = backends + num_backends;
+
+ if ((backend->pid = fork()) < 0)
{
/*
* Error!
*/
- fprintf(stderr, "ERROR: Unable to fork for \"%s\" - %s\n", backend,
- strerror(errno));
+ fprintf(stderr, "ERROR: [cups-deviced] Unable to fork for \"%s\" - %s\n",
+ program, strerror(errno));
close(fds[0]);
close(fds[1]);
- return (NULL);
+ return (-1);
}
- else if (!*pid)
+ else if (!backend->pid)
{
/*
* Child comes here...
*/
- if (!getuid() && uid)
- setuid(uid); /* Run as restricted user */
+ if (!getuid() && !root)
+ setuid(normal_user); /* Run as restricted user */
close(0); /* </dev/null */
open("/dev/null", O_RDONLY);
close(fds[0]); /* Close copies of pipes */
close(fds[1]);
- execl(backend, backend, (char *)0); /* Run it! */
- fprintf(stderr, "ERROR: Unable to execute \"%s\" - %s\n", backend,
- strerror(errno));
+ execl(program, name, (char *)0); /* Run it! */
+ fprintf(stderr, "ERROR: [cups-deviced] Unable to execute \"%s\" - %s\n",
+ program, strerror(errno));
exit(1);
}
/*
- * Parent comes here, make a FILE * from the input side of the pipe...
+ * Parent comes here, allocate a backend and open the input side of the
+ * pipe...
*/
- close(fds[1]);
+ fprintf(stderr, "DEBUG: [cups-deviced] Started backend %s (PID %d)\n",
+ program, backend->pid);
- return (fdopen(fds[0], "r"));
-}
+ close(fds[1]);
+ backend_fds[num_backends].fd = fds[0];
+ backend_fds[num_backends].events = POLLIN;
-/*
- * 'sigalrm_handler()' - Handle alarm signals for backends that get hung
- * trying to list the available devices...
- */
+ backend->name = strdup(name);
+ backend->status = 0;
+ backend->pipe = cupsFileOpenFd(fds[0], "r");
+ backend->count = 0;
-static void
-sigalrm_handler(int sig) /* I - Signal number */
-{
- (void)sig; /* remove compiler warnings... */
+ active_backends ++;
+ num_backends ++;
- alarm_tripped = 1;
+ return (0);
}
* Got a direct filter!
*/
- DEBUG_puts("Direct filter found!");
+ DEBUG_puts("find_filters: Direct filter found!");
if ((mintemp = cupsArrayNew(NULL, NULL)) == NULL)
return (NULL);
if (!cost)
return (mintemp);
- DEBUG_puts(" Found direct filter:");
- DEBUG_printf((" %s (cost=%d)\n", current->filter, mincost));
+ DEBUG_puts("find_filters: Found direct filter:");
+ DEBUG_printf(("find_filters: %s (cost=%d)\n", current->filter, mincost));
}
else
{
*/
#ifdef DEBUG
- printf(" Returning %d filters:\n", cupsArrayCount(mintemp));
+ DEBUG_printf(("find_filters: Returning %d filters:\n",
+ cupsArrayCount(mintemp)));
+
for (current = (mime_filter_t *)cupsArrayFirst(mintemp);
current;
current = (mime_filter_t *)cupsArrayNext(mintemp))
- printf(" %s\n", current->filter);
+ DEBUG_printf(("find_filters: %s\n", current->filter));
#endif /* DEBUG */
if (cost)
return (mintemp);
}
- DEBUG_puts(" Returning zippo...");
+ DEBUG_puts("find_filters: Returning zippo...");
return (NULL);
}
get_devices(cupsd_client_t *con) /* I - Client connection */
{
http_status_t status; /* Policy status */
- ipp_attribute_t *limit, /* Limit attribute */
- *requested; /* requested-attributes attribute */
+ ipp_attribute_t *limit, /* limit attribute */
+ *timeout, /* timeout attribute */
+ *requested, /* requested-attributes attribute */
+ *exclude; /* exclude-schemes attribute */
char command[1024], /* cups-deviced command */
options[1024], /* Options to pass to command */
- requested_str[256];
+ requested_str[256],
/* String for requested attributes */
+ exclude_str[512];
+ /* String for excluded attributes */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", con, con->http.fd);
* Run cups-deviced command with the given options...
*/
- limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
+ limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
+ timeout = ippFindAttribute(con->request, "timeout", IPP_TAG_INTEGER);
requested = ippFindAttribute(con->request, "requested-attributes",
IPP_TAG_KEYWORD);
+ exclude = ippFindAttribute(con->request, "exclude-schemes", IPP_TAG_NAME);
if (requested)
url_encode_attr(requested, requested_str, sizeof(requested_str));
else
strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
+ if (exclude)
+ url_encode_attr(exclude, exclude_str, sizeof(exclude_str));
+ else
+ exclude_str[0] = '\0';
+
snprintf(command, sizeof(command), "%s/daemon/cups-deviced", ServerBin);
snprintf(options, sizeof(options),
- "%d+%d+%d+%s",
+ "%d+%d+%d+%d+%s%s%s",
con->request->request.op.request_id,
- limit ? limit->values[0].integer : 0, (int)User,
- requested_str);
+ limit ? limit->values[0].integer : 0,
+ timeout ? timeout->values[0].integer : 10,
+ (int)User,
+ requested_str,
+ exclude_str[0] ? "%20" : "", exclude_str);
if (cupsdSendCommand(con, command, options, 1))
{
*/
static void
-sigchld_handler(int sig) /* I - Signal number */
+sigchld_handler(int sig) /* I - Signal number */
{
(void)sig;
*/
static void
-sighup_handler(int sig) /* I - Signal number */
+sighup_handler(int sig) /* I - Signal number */
{
(void)sig;
*/
static void
-sigterm_handler(int sig) /* I - Signal */
+sigterm_handler(int sig) /* I - Signal number */
{
(void)sig; /* remove compiler warnings... */
* Contents:
*
* main() - Parse options and show information.
+ * device_cb - Device callback.
* show_devices() - Show available devices.
* show_models() - Show available PPDs.
*/
* Local functions...
*/
+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);
static int show_devices(http_t *, int);
static int show_models(http_t *, int);
/*
- * 'show_devices()' - Show available devices.
+ * 'device_cb()' - Device callback.
*/
-static int /* O - 0 on success, 1 on failure */
-show_devices(http_t *http, /* I - HTTP connection to server */
- int long_status) /* I - Long status report? */
+static void
+device_cb(
+ const char *device_class, /* I - device-class string */
+ const char *device_id, /* I - device-id string */
+ 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 */
+ void *user_data) /* I - User data */
{
- ipp_t *request, /* IPP Request */
- *response; /* IPP Response */
- ipp_attribute_t *attr; /* Current attribute */
- const char *device_class, /* Pointer to device-class */
- *device_id, /* Pointer to device-id */
- *device_info, /* Pointer to device-info */
- *device_make, /* Pointer to device-make-and-model */
- *device_uri; /* Pointer to device-uri */
-
+ int *long_status; /* Show verbose info? */
- if (http == NULL)
- return (1);
/*
- * Build a CUPS_GET_DEVICES request, which requires the following
- * attributes:
- *
- * attributes-charset
- * attributes-natural-language
+ * Display the device...
*/
- request = ippNewRequest(CUPS_GET_DEVICES);
-
- /*
- * Do the request and get back a response...
- */
+ long_status = (int *)user_data;
- if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ if (*long_status)
{
- /*
- * Loop through the device list and display them...
- */
-
- if (response->request.status.status_code > IPP_OK_CONFLICT)
- {
- _cupsLangPrintf(stderr, "lpinfo: %s\n", cupsLastErrorString());
- ippDelete(response);
- return (1);
- }
-
- for (attr = response->attrs; attr != NULL; attr = attr->next)
- {
- /*
- * Skip leading attributes until we hit a device...
- */
-
- while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
- attr = attr->next;
-
- if (attr == NULL)
- break;
-
- /*
- * Pull the needed attributes from this device...
- */
-
- device_class = NULL;
- device_info = NULL;
- device_make = NULL;
- device_uri = NULL;
- device_id = "NONE";
-
- while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
- {
- if (!strcmp(attr->name, "device-class") &&
- attr->value_tag == IPP_TAG_KEYWORD)
- device_class = attr->values[0].string.text;
- 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-make-and-model") &&
- attr->value_tag == IPP_TAG_TEXT)
- device_make = attr->values[0].string.text;
- else if (!strcmp(attr->name, "device-uri") &&
- attr->value_tag == IPP_TAG_URI)
- device_uri = attr->values[0].string.text;
- else if (!strcmp(attr->name, "device-id") &&
- attr->value_tag == IPP_TAG_TEXT)
- device_id = attr->values[0].string.text;
-
- attr = attr->next;
- }
-
- /*
- * See if we have everything needed...
- */
-
- if (device_class == NULL || device_info == NULL ||
- device_make == NULL || device_uri == NULL)
- {
- if (attr == NULL)
- break;
- else
- continue;
- }
-
- /*
- * Display the device...
- */
+ _cupsLangPrintf(stdout,
+ _("Device: uri = %s\n"
+ " class = %s\n"
+ " info = %s\n"
+ " make-and-model = %s\n"
+ " device-id = %s\n"),
+ device_uri, device_class, device_info,
+ device_make_and_model, device_id);
+ }
+ else
+ _cupsLangPrintf(stdout, "%s %s\n", device_class, device_uri);
+}
- if (long_status)
- {
- _cupsLangPrintf(stdout,
- _("Device: uri = %s\n"
- " class = %s\n"
- " info = %s\n"
- " make-and-model = %s\n"
- " device-id = %s\n"),
- device_uri, device_class, device_info, device_make,
- device_id);
- }
- else
- _cupsLangPrintf(stdout, "%s %s\n", device_class, device_uri);
- if (attr == NULL)
- break;
- }
+/*
+ * 'show_devices()' - Show available devices.
+ */
- ippDelete(response);
- }
- else
+static int /* O - 0 on success, 1 on failure */
+show_devices(http_t *http, /* I - HTTP connection to server */
+ int long_status) /* I - Long status report? */
+{
+ if (cupsGetDevices(http, CUPS_TIMEOUT_DEFAULT, CUPS_EXCLUDE_NONE, device_cb,
+ &long_status) != IPP_OK)
{
_cupsLangPrintf(stderr, "lpinfo: %s\n", cupsLastErrorString());
return (1);