From 5a662dc06039959a7a12925c21abf9d2e233b618 Mon Sep 17 00:00:00 2001
From: msweet
Date: Wed, 16 Dec 2009 00:13:28 +0000
Subject: [PATCH] Merge changes from CUPS 1.5svn-r8933.
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@1788 a1ca3aef-8c08-0410-bb20-df032aa958be
---
CHANGES-1.4.txt | 6 +
berkeley/lpq.c | 18 +-
config-scripts/cups-common.m4 | 2 +
config-scripts/cups-defaults.m4 | 15 +-
cups/dest.c | 6 +
cups/util.c | 41 ++-
doc/help/ref-cupsd-conf.html.in | 6 +-
doc/help/spec-ppd.html | 16 +-
scheduler/ipp.c | 21 +-
scheduler/job.c | 2 +-
scheduler/main.c | 30 ++-
scheduler/printers.c | 18 +-
scheduler/printers.h | 1 -
systemv/lpstat.c | 6 +-
test/4.3-job-ops.test | 3 +
test/Dependencies | 1 +
test/ipptest.c | 440 ++++++++++++++++++++++++++------
17 files changed, 503 insertions(+), 129 deletions(-)
diff --git a/CHANGES-1.4.txt b/CHANGES-1.4.txt
index 74c595971..5508abe0e 100644
--- a/CHANGES-1.4.txt
+++ b/CHANGES-1.4.txt
@@ -6,6 +6,12 @@ CHANGES IN CUPS V1.4.3
- SECURITY: The scheduler could try responding on a closed client
connection, leading to a crash (STR #3200)
- Localization updates (STR #3352, STR #3409, STR #3422)
+ - Documentation update (STR #3451)
+ - IPP conformance: Get-Jobs has a default value for requested-attributes
+ (STR #3383)
+ - cupsPrintFiles() did not report all errors (STR #3449)
+ - cupsAddDest() could read freed memory (STR #3448)
+ - The DBUS notifier did not build (STR #3447)
- The scheduler would crash when an active printer was deleted.
- The snmp backend did not work with some printers (STR #3413)
- The web interface did not show the conflicting values when setting
diff --git a/berkeley/lpq.c b/berkeley/lpq.c
index b744848f7..8304bdc4e 100644
--- a/berkeley/lpq.c
+++ b/berkeley/lpq.c
@@ -340,7 +340,18 @@ show_jobs(const char *command, /* I - Command name */
char resource[1024]; /* Resource string */
char rankstr[255]; /* Rank string */
char namestr[1024]; /* Job name string */
- static const char *ranks[10] = /* Ranking strings */
+ static const char * const jobattrs[] =/* Job attributes we want to see */
+ {
+ "copies",
+ "job-id",
+ "job-k-octets",
+ "job-name",
+ "job-originating-user-name",
+ "job-printer-uri",
+ "job-priority",
+ "job-state"
+ };
+ static const char * const ranks[10] = /* Ranking strings */
{
"th",
"st",
@@ -368,6 +379,7 @@ show_jobs(const char *command, /* I - Command name */
* attributes-charset
* attributes-natural-language
* job-uri or printer-uri
+ * requested-attributes
*/
request = ippNewRequest(id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS);
@@ -397,6 +409,10 @@ show_jobs(const char *command, /* I - Command name */
ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1);
}
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes",
+ (int)(sizeof(jobattrs) / sizeof(jobattrs[0])), NULL, jobattrs);
+
/*
* Do the request and get back a response...
*/
diff --git a/config-scripts/cups-common.m4 b/config-scripts/cups-common.m4
index 8583acfaf..51b108beb 100644
--- a/config-scripts/cups-common.m4
+++ b/config-scripts/cups-common.m4
@@ -262,6 +262,8 @@ if test "x$enable_dbus" != xno; then
AC_DEFINE(HAVE_DBUS)
CFLAGS="$CFLAGS `$PKGCONFIG --cflags dbus-1` -DDBUS_API_SUBJECT_TO_CHANGE"
CUPSDLIBS="$CUPSDLIBS `$PKGCONFIG --libs dbus-1`"
+ DBUS_NOTIFIER="dbus"
+ DBUS_NOTIFIERLIBS="`$PKGCONFIG --libs dbus-1`"
AC_CHECK_LIB(dbus-1,
dbus_message_iter_init_append,
AC_DEFINE(HAVE_DBUS_MESSAGE_ITER_INIT_APPEND),,
diff --git a/config-scripts/cups-defaults.m4 b/config-scripts/cups-defaults.m4
index 1a4eb7b89..4f455a823 100644
--- a/config-scripts/cups-defaults.m4
+++ b/config-scripts/cups-defaults.m4
@@ -208,6 +208,10 @@ AC_ARG_WITH(cups_user, [ --with-cups-user set default user for CUPS],
AC_MSG_RESULT(no password file, using "$CUPS_USER")
fi)
+if test "x$CUPS_USER" = "xroot" -o "x$CUPS_USER" = "x0"; then
+ AC_MSG_ERROR([The default user for CUPS cannot be root!])
+fi
+
AC_ARG_WITH(cups_group, [ --with-cups-group set default group for CUPS],
CUPS_GROUP="$withval",
AC_MSG_CHECKING(for default print group)
@@ -238,6 +242,10 @@ AC_ARG_WITH(cups_group, [ --with-cups-group set default group for CUPS],
AC_MSG_RESULT(no group file, using "$CUPS_GROUP")
fi)
+if test "x$CUPS_GROUP" = "xroot" -o "x$CUPS_GROUP" = "xwheel" -o "x$CUPS_GROUP" = "x0"; then
+ AC_MSG_ERROR([The default group for CUPS cannot be root!])
+fi
+
AC_ARG_WITH(system_groups, [ --with-system-groups set default system groups for CUPS],
CUPS_SYSTEM_GROUPS="$withval",
if test x$uname = xDarwin; then
@@ -269,9 +277,14 @@ AC_ARG_WITH(system_groups, [ --with-system-groups set default system groups
fi
fi)
-
CUPS_PRIMARY_SYSTEM_GROUP="`echo $CUPS_SYSTEM_GROUPS | awk '{print $1}'`"
+for group in $CUPS_SYSTEM_GROUPS; do
+ if test "x$CUPS_GROUP" = "x$group"; then
+ AC_MSG_ERROR([The default system groups cannot contain the default CUPS group!])
+ fi
+done
+
AC_SUBST(CUPS_USER)
AC_SUBST(CUPS_GROUP)
AC_SUBST(CUPS_SYSTEM_GROUPS)
diff --git a/cups/dest.c b/cups/dest.c
index 099f451d8..85a2b3836 100644
--- a/cups/dest.c
+++ b/cups/dest.c
@@ -144,6 +144,12 @@ cupsAddDest(const char *name, /* I - Destination name */
dest = cups_add_dest(name, instance, &num_dests, dests);
+ /*
+ * Find the base dest again now the array has been realloc'd.
+ */
+
+ parent = cupsGetDest(name, NULL, num_dests, *dests);
+
if (instance && parent && parent->num_options > 0)
{
/*
diff --git a/cups/util.c b/cups/util.c
index 87ba2c0ce..7bfbe29a2 100644
--- a/cups/util.c
+++ b/cups/util.c
@@ -570,17 +570,17 @@ cupsGetJobs2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_D
_cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
static const char * const attrs[] = /* Requested attributes */
{
+ "document-format",
"job-id",
- "job-priority",
"job-k-octets",
+ "job-name",
+ "job-originating-user-name",
+ "job-printer-uri",
+ "job-priority",
"job-state",
"time-at-completed",
"time-at-creation",
- "time-at-processing",
- "job-printer-uri",
- "document-format",
- "job-name",
- "job-originating-user-name"
+ "time-at-processing"
};
@@ -1456,6 +1456,9 @@ cupsPrintFiles2(
char buffer[8192]; /* Copy buffer */
ssize_t bytes; /* Bytes in buffer */
http_status_t status; /* Status of write */
+ _cups_globals_t *cg = _cupsGlobals(); /* Global data */
+ ipp_status_t cancel_status; /* Status code to preserve */
+ char *cancel_message; /* Error message to preserve */
DEBUG_printf(("cupsPrintFiles2(http=%p, name=\"%s\", num_files=%d, "
@@ -1507,8 +1510,8 @@ cupsPrintFiles2(
* Unable to open print file, cancel the job and return...
*/
- cupsCancelJob2(http, name, job_id, 0);
- return (0);
+ _cupsSetError(IPP_DOCUMENT_ACCESS_ERROR, NULL, 0);
+ goto cancel_job;
}
do
@@ -1550,12 +1553,30 @@ cupsPrintFiles2(
* Unable to queue, cancel the job and return...
*/
- cupsCancelJob2(http, name, job_id, 0);
- return (0);
+ goto cancel_job;
}
}
return (job_id);
+
+ /*
+ * If we get here, something happened while sending the print job so we need
+ * to cancel the job without setting the last error (since we need to preserve
+ * the current error...
+ */
+
+ cancel_job:
+
+ cancel_status = cg->last_error;
+ cancel_message = cg->last_status_message ?
+ _cupsStrRetain(cg->last_status_message) : NULL;
+
+ cupsCancelJob2(http, name, job_id, 0);
+
+ cg->last_error = cancel_status;
+ cg->last_status_message = cancel_message;
+
+ return (0);
}
diff --git a/doc/help/ref-cupsd-conf.html.in b/doc/help/ref-cupsd-conf.html.in
index 4f880b461..6b3384bbc 100644
--- a/doc/help/ref-cupsd-conf.html.in
+++ b/doc/help/ref-cupsd-conf.html.in
@@ -123,7 +123,8 @@ to the access log file. The following levels are defined:
Allow from nnn.nnn.nnn.nnn
Allow from nnn.nnn.nnn.nnn/mm
Allow from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
- Allow from xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
+ Allow from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]
+ Allow from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]/mmm
Allow from @LOCAL
Allow from @IF(name)
</Location>
@@ -1071,7 +1072,8 @@ printers are shared (published) by default. The default is
Deny from nnn.nnn.nnn.nnn
Deny from nnn.nnn.nnn.nnn/mm
Deny from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
- Deny from xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
+ Deny from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]
+ Deny from [xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]/mmm
Deny from @LOCAL
Deny from @IF(name)
</Location>
diff --git a/doc/help/spec-ppd.html b/doc/help/spec-ppd.html
index 9fce558dc..2ac011e77 100644
--- a/doc/help/spec-ppd.html
+++ b/doc/help/spec-ppd.html
@@ -161,9 +161,8 @@ based on well-known colorspaces such as sRGB and Adobe RGB.
Note:
-At this time, none of the CUPS raster
-filters support ICC profiles. This will be addressed as time
-and resources permit.
+At this time, none of the CUPS raster filters support ICC profiles. This
+will be addressed as time and resources permit.
@@ -174,7 +173,7 @@ gamma m00 m01 m02 m10 m11 m12 m20 m21 m22"
This string attribute specifies an sRGB-based color profile
consisting of gamma and density controls and a 3x3 CMY color
-transform matrix.
+transform matrix. This attribute is not supported on Mac OS X.
The Resolution and MediaType values may be "-"
to act as a wildcard. Otherwise they must match one of the
@@ -277,6 +276,15 @@ data as requested by the driver. The APCustomColorMatchingProfile
and APDefaultColorMatchingProfile attributes specify alternate
color profiles (sRGB or AdobeRGB) to use for 3-color (RGB) raster data.
+Note:
+
+Prior to Mac OS X 10.6, the default RGB color space was Apple's "GenericRGB".
+The new default in Mac OS X 10.6 and later is "sRGB". For more information, see
+"Mac OS X v10.6: About gamma
+2.2" on Apple's support site.
+
+
+
*APCustomColorMatchingName name/text: ""
diff --git a/scheduler/ipp.c b/scheduler/ipp.c
index f95417e64..b4659fe3f 100644
--- a/scheduler/ipp.c
+++ b/scheduler/ipp.c
@@ -5430,14 +5430,6 @@ copy_printer_attrs(
curtime = time(NULL);
-#ifdef __APPLE__
- if ((!ra || cupsArrayFind(ra, "com.apple.print.recoverable-message")) &&
- printer->recoverable)
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT,
- "com.apple.print.recoverable-message", NULL,
- printer->recoverable);
-#endif /* __APPLE__ */
-
if (!ra || cupsArrayFind(ra, "marker-change-time"))
ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"marker-change-time", printer->marker_time);
@@ -7007,7 +6999,18 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */
else
username[0] = '\0';
- ra = create_requested_array(con->request);
+ if ((ra = create_requested_array(con->request)) == NULL &&
+ !ippFindAttribute(con->request, "requested-attributes", IPP_TAG_KEYWORD))
+ {
+ /*
+ * IPP conformance - Get-Jobs has a default requested-attributes value of
+ * "job-id" and "job-uri".
+ */
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-uri");
+ }
/*
* OK, build a list of jobs for this printer...
diff --git a/scheduler/job.c b/scheduler/job.c
index b33856707..dd3df67a8 100644
--- a/scheduler/job.c
+++ b/scheduler/job.c
@@ -2441,7 +2441,7 @@ cupsdSetJobState(
* Finalize the job immediately if we forced things...
*/
- if (action >= CUPSD_JOB_FORCE)
+ if (action >= CUPSD_JOB_FORCE && job->printer)
finalize_job(job, 0);
/*
diff --git a/scheduler/main.c b/scheduler/main.c
index 28ae983f0..60e97d095 100644
--- a/scheduler/main.c
+++ b/scheduler/main.c
@@ -134,7 +134,7 @@ main(int argc, /* I - Number of command-line args */
senddoc_time, /* Send-Document time */
expire_time, /* Subscription expire time */
report_time, /* Malloc/client/job report time */
- event_time; /* Last time an event notification was done */
+ event_time; /* Last event notification time */
long timeout; /* Timeout for cupsdDoSelect() */
struct rlimit limit; /* Runtime limit */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
@@ -270,19 +270,22 @@ main(int argc, /* I - Number of command-line args */
break;
case 'p' : /* Stop immediately for profiling */
- puts("Warning: -p (startup profiling) is for internal testing use only!");
+ fputs("cupsd: -p (startup profiling) is for internal testing "
+ "use only!\n", stderr);
stop_scheduler = 1;
fg = 1;
break;
case 'P' : /* Disable security profiles */
- puts("Warning: -P (disable security profiles) is for internal testing use only!");
+ fputs("cupsd: -P (disable security profiles) is for internal "
+ "testing use only!\n", stderr);
UseProfiles = 0;
break;
#ifdef __APPLE__
case 'S' : /* Disable system management functions */
- puts("Warning: -S (disable system management) for internal testing use only!");
+ fputs("cupsd: -S (disable system management) for internal "
+ "testing use only!\n", stderr);
use_sysman = 0;
break;
#endif /* __APPLE__ */
@@ -763,7 +766,8 @@ main(int argc, /* I - Number of command-line args */
if (Launchd)
{
/*
- * If we were started by launchd get the listen sockets file descriptors...
+ * If we were started by launchd, get the listen socket file
+ * descriptors...
*/
launchd_checkin();
@@ -1566,8 +1570,8 @@ launchd_checkin(void)
if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "launchd_checkin: Unable to allocate listener - %s.",
- strerror(errno));
+ "launchd_checkin: Unable to allocate listener - "
+ "%s.", strerror(errno));
exit(EXIT_FAILURE);
}
@@ -1623,7 +1627,8 @@ launchd_checkout(void)
(BrowseLocalProtocols && NumBrowsers && cupsArrayCount(Printers))))))
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
- "Creating launchd keepalive file \"" CUPS_KEEPALIVE "\"...");
+ "Creating launchd keepalive file \"" CUPS_KEEPALIVE
+ "\"...");
if ((fd = open(CUPS_KEEPALIVE, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR)) >= 0)
close(fd);
@@ -1631,7 +1636,8 @@ launchd_checkout(void)
else
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
- "Removing launchd keepalive file \"" CUPS_KEEPALIVE "\"...");
+ "Removing launchd keepalive file \"" CUPS_KEEPALIVE
+ "\"...");
unlink(CUPS_KEEPALIVE);
}
@@ -1767,7 +1773,7 @@ process_children(void)
job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB,
IPP_TAG_TEXT,
"job-printer-state-message",
- NULL, "");
+ NULL, NULL);
}
if (job->printer_message)
@@ -1781,7 +1787,7 @@ process_children(void)
* filters are done, and if so move to the next file.
*/
- if (job->current_file < job->num_files)
+ if (job->current_file < job->num_files && job->printer)
{
for (i = 0; job->filters[i] < 0; i ++);
@@ -1794,7 +1800,7 @@ process_children(void)
cupsdContinueJob(job);
}
}
- else if (job->state_value == IPP_JOB_CANCELED)
+ else if (job->state_value >= IPP_JOB_CANCELED)
{
/*
* Remove the job from the active list if there are no processes still
diff --git a/scheduler/printers.c b/scheduler/printers.c
index b12a5498e..1e615ebe0 100644
--- a/scheduler/printers.c
+++ b/scheduler/printers.c
@@ -205,11 +205,6 @@ cupsdAddPrinterHistory(
ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-shared", p->shared);
ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message",
NULL, p->state_message);
-#ifdef __APPLE__
- if (p->recoverable)
- ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT,
- "com.apple.print.recoverable-message", NULL, p->recoverable);
-#endif /* __APPLE__ */
if (p->num_reasons == 0)
ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"printer-state-reasons", NULL, "none");
@@ -649,7 +644,10 @@ cupsdDeleteAllPrinters(void)
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ {
+ p->op_policy_ptr = DefaultPolicyPtr;
cupsdDeletePrinter(p, 0);
+ }
}
@@ -841,10 +839,6 @@ cupsdDeletePrinter(
if (p->browse_attrs)
free(p->browse_attrs);
-#ifdef __APPLE__
- cupsdClearString(&p->recoverable);
-#endif /* __APPLE__ */
-
cupsFreeOptions(p->num_options, p->options);
free(p);
@@ -1094,7 +1088,6 @@ cupsdLoadAllPrinters(void)
else if (!strcasecmp(line, "Reason"))
{
if (value &&
- strcmp(value, "com.apple.print.recoverable-warning") &&
strcmp(value, "connecting-to-device") &&
strcmp(value, "cups-insecure-filter-warning") &&
strcmp(value, "cups-missing-filter-warning"))
@@ -1599,8 +1592,7 @@ cupsdSaveAllPrinters(void)
cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time);
for (i = 0; i < printer->num_reasons; i ++)
- if (strcmp(printer->reasons[i], "com.apple.print.recoverable-warning") &&
- strcmp(printer->reasons[i], "connecting-to-device") &&
+ if (strcmp(printer->reasons[i], "connecting-to-device") &&
strcmp(printer->reasons[i], "cups-insecure-filter-warning") &&
strcmp(printer->reasons[i], "cups-missing-filter-warning"))
cupsFilePutConf(fp, "Reason", printer->reasons[i]);
@@ -3756,7 +3748,7 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */
filter;
filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters))
{
- if (filter->dst == p->filetype && filter->filter &&
+ if (filter->dst == p->filetype && filter->filter &&
strstr(filter->filter, "PrintJobMgr"))
break;
}
diff --git a/scheduler/printers.h b/scheduler/printers.h
index 292a4b562..713539941 100644
--- a/scheduler/printers.h
+++ b/scheduler/printers.h
@@ -94,7 +94,6 @@ typedef struct cupsd_printer_s
time_t marker_time; /* Last time marker attributes were updated */
cups_array_t *filters, /* Filters for queue */
*pre_filters; /* Pre-filters for queue */
- char *recoverable; /* com.apple.print.recoverable-message */
#ifdef HAVE_DNSSD
char *reg_name, /* Name used for service registration */
diff --git a/systemv/lpstat.c b/systemv/lpstat.c
index 603ecdd25..e98aaa70d 100644
--- a/systemv/lpstat.c
+++ b/systemv/lpstat.c
@@ -1287,10 +1287,10 @@ show_jobs(const char *dests, /* I - Destinations */
"job-id",
"job-k-octets",
"job-name",
- "time-at-creation",
- "job-printer-uri",
"job-originating-user-name",
- "job-state-reasons"
+ "job-printer-uri",
+ "job-state-reasons",
+ "time-at-creation"
};
diff --git a/test/4.3-job-ops.test b/test/4.3-job-ops.test
index 1b0a71afa..2f2236b0c 100644
--- a/test/4.3-job-ops.test
+++ b/test/4.3-job-ops.test
@@ -296,6 +296,7 @@
# What attributes do we expect?
EXPECT attributes-charset
EXPECT attributes-natural-language
+ EXPECT !job-printer-uri
}
{
# The name of the test...
@@ -310,6 +311,7 @@
ATTR charset attributes-charset utf-8
ATTR language attributes-natural-language en
ATTR uri printer-uri $scheme://$hostname:$port/
+ ATTR keyword requested-attributes all
# What statuses are OK?
STATUS successful-ok
@@ -320,6 +322,7 @@
EXPECT job-uri
EXPECT job-id
EXPECT job-state
+ EXPECT job-printer-uri
}
#
diff --git a/test/Dependencies b/test/Dependencies
index 43ea40074..a395277e9 100644
--- a/test/Dependencies
+++ b/test/Dependencies
@@ -3,3 +3,4 @@
ipptest.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h
ipptest.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h ../cups/array.h
ipptest.o: ../cups/file.h ../cups/language.h ../cups/language.h
+ipptest.o: ../cups/http-private.h ../cups/md5.h ../cups/ipp-private.h
diff --git a/test/ipptest.c b/test/ipptest.c
index 59f2fb803..28404388d 100644
--- a/test/ipptest.c
+++ b/test/ipptest.c
@@ -14,11 +14,13 @@
*
* Contents:
*
- * main() - Parse options and do tests.
- * do_tests() - Do tests as specified in the test file.
- * get_token() - Get a token from a file.
- * print_attr() - Print an attribute on the screen.
- * usage() - Show program usage.
+ * main() - Parse options and do tests.
+ * do_tests() - Do tests as specified in the test file.
+ * expect_matches() - Return true if the tag matches the specification.
+ * get_token() - Get a token from a file.
+ * print_attr() - Print an attribute on the screen.
+ * print_col() - Print a collection attribute on the screen.
+ * usage() - Show program usage.
*/
/*
@@ -33,12 +35,31 @@
#include
#include
+#include
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif /* !O_BINARY */
+
+
+/*
+ * Types...
+ */
+
+typedef struct _cups_expect_s /**** Expected attribute info ****/
+{
+ int not_expect; /* Don't expect attribute? */
+ char *name, /* Attribute name */
+ *of_type, /* Type name */
+ *same_count_as, /* Parallel attribute name */
+ *if_defined; /* Only required if variable defined */
+} _cups_expect_t;
/*
* Globals...
*/
+int Chunking = 0; /* Use chunked requests */
int Verbosity = 0; /* Show all attributes? */
@@ -46,13 +67,13 @@ int Verbosity = 0; /* Show all attributes? */
* Local functions...
*/
-int do_tests(const char *, const char *);
-ipp_op_t ippOpValue(const char *);
-ipp_status_t ippErrorValue(const char *);
-char *get_token(FILE *, char *, int, int *linenum);
-void print_attr(ipp_attribute_t *);
-void print_col(ipp_t *col);
-void usage(const char *option);
+static int do_tests(const char *uri, const char *testfile);
+static int expect_matches(_cups_expect_t *expect, ipp_tag_t value_tag);
+static char *get_token(FILE *fp, char *buf, int buflen,
+ int *linenum);
+static void print_attr(ipp_attribute_t *attr);
+static void print_col(ipp_t *col);
+static void usage(void);
/*
@@ -60,13 +81,14 @@ void usage(const char *option);
*/
int /* O - Exit status */
-main(int argc, /* I - Number of command-line arguments */
+main(int argc, /* I - Number of command-line args */
char *argv[]) /* I - Command-line arguments */
{
int i; /* Looping var */
int status; /* Status of tests... */
- const char *uri; /* URI to use */
- const char *testfile; /* Test file to use */
+ char *opt; /* Current option */
+ const char *uri, /* URI to use */
+ *testfile; /* Test file to use */
int interval; /* Test interval */
@@ -85,28 +107,48 @@ main(int argc, /* I - Number of command-line arguments */
{
if (argv[i][0] == '-')
{
- if (!strcmp(argv[i], "-v"))
- Verbosity ++;
- else if (!strcmp(argv[i], "-d"))
+ for (opt = argv[i] + 1; *opt; opt ++)
{
- i ++;
+ switch (*opt)
+ {
+ case 'c' : /* Enable HTTP chunking */
+ Chunking = 1;
+ break;
- if (i >= argc)
- usage(NULL);
- else
- putenv(argv[i]);
- }
- else if (!strcmp(argv[i], "-i"))
- {
- i++;
+ case 'd' : /* Define a variable */
+ i ++;
- if (i >= argc)
- usage(NULL);
- else
- interval = atoi(argv[i]);
+ if (i >= argc)
+ {
+ fputs("ipptest: Missing name=value for \"-d\"!\n", stderr);
+ usage();
+ }
+ else
+ putenv(argv[i]);
+ break;
+
+ case 'i' : /* Test every N seconds */
+ i++;
+
+ if (i >= argc)
+ {
+ fputs("ipptest: Missing seconds for \"-i\"!\n", stderr);
+ usage();
+ }
+ else
+ interval = atoi(argv[i]);
+ break;
+
+ case 'v' : /* Be verbose */
+ Verbosity ++;
+ break;
+
+ default :
+ fprintf(stderr, "ipptest: Unknown option \"-%c\"!\n", *opt);
+ usage();
+ break;
+ }
}
- else
- usage(argv[i]);
}
else if (!strncmp(argv[i], "ipp://", 6) ||
!strncmp(argv[i], "http://", 7) ||
@@ -117,7 +159,11 @@ main(int argc, /* I - Number of command-line arguments */
*/
if (!testfile && uri)
- usage(NULL);
+ {
+ fputs("ipptest: May only specify a single URI before a test!\n",
+ stderr);
+ usage();
+ }
uri = argv[i];
testfile = NULL;
@@ -136,7 +182,7 @@ main(int argc, /* I - Number of command-line arguments */
}
if (!uri || !testfile)
- usage(NULL);
+ usage();
/*
* Loop if the interval is set...
@@ -158,12 +204,12 @@ main(int argc, /* I - Number of command-line arguments */
return (status);
}
-
+
/*
* 'do_tests()' - Do tests as specified in the test file.
*/
-int /* 1 = success, 0 = failure */
+static int /* 1 = success, 0 = failure */
do_tests(const char *uri, /* I - URI to connect on */
const char *testfile) /* I - Test file to use */
{
@@ -186,12 +232,15 @@ do_tests(const char *uri, /* I - URI to connect on */
ipp_op_t op; /* Operation */
ipp_tag_t group; /* Current group */
ipp_tag_t value; /* Current value type */
- ipp_attribute_t *attrptr; /* Attribute pointer */
+ ipp_attribute_t *attrptr, /* Attribute pointer */
+ *found; /* Found attribute */
char attr[128]; /* Attribute name */
int num_statuses; /* Number of valid status codes */
ipp_status_t statuses[100]; /* Valid status codes */
int num_expects; /* Number of expected attributes */
- char *expects[100]; /* Expected attributes */
+ _cups_expect_t expects[100], /* Expected attributes */
+ *expect, /* Current expected attribute */
+ *last_expect; /* Last EXPECT (for predicates) */
int num_displayed; /* Number of displayed attributes */
char *displayed[100]; /* Displayed attributes */
char name[1024]; /* Name of test */
@@ -265,6 +314,7 @@ do_tests(const char *uri, /* I - URI to connect on */
num_statuses = 0;
num_expects = 0;
num_displayed = 0;
+ last_expect = NULL;
filename[0] = '\0';
strcpy(name, testfile);
@@ -277,6 +327,12 @@ do_tests(const char *uri, /* I - URI to connect on */
while (get_token(fp, token, sizeof(token), &linenum) != NULL)
{
+ if (strcasecmp(token, "EXPECT") &&
+ strcasecmp(token, "IF-DEFINED") &&
+ strcasecmp(token, "OF-TYPE") &&
+ strcasecmp(token, "SAME-COUNT-AS"))
+ last_expect = NULL;
+
if (!strcmp(token, "}"))
break;
else if (!strcasecmp(token, "NAME"))
@@ -526,16 +582,87 @@ do_tests(const char *uri, /* I - URI to connect on */
statuses[num_statuses] = ippErrorValue(token);
num_statuses ++;
}
- else if (!strcasecmp(token, "EXPECT") &&
- num_expects < (int)(sizeof(expects) / sizeof(expects[0])))
+ else if (!strcasecmp(token, "EXPECT"))
{
/*
* Expected attributes...
*/
+ if (num_expects >= (int)(sizeof(expects) / sizeof(expects[0])))
+ {
+ fprintf(stderr, "ipptest: Too many EXPECT's on line %d\n", linenum);
+ httpClose(http);
+ ippDelete(request);
+ return (0);
+ }
+
get_token(fp, token, sizeof(token), &linenum);
- expects[num_expects] = strdup(token);
+
+ last_expect = expects + num_expects;
num_expects ++;
+
+ if (token[0] == '!')
+ {
+ last_expect->not_expect = 1;
+ last_expect->name = strdup(token + 1);
+ }
+ else
+ {
+ last_expect->not_expect = 0;
+ last_expect->name = strdup(token);
+ }
+
+ last_expect->of_type = NULL;
+ last_expect->same_count_as = NULL;
+ last_expect->if_defined = NULL;
+ }
+ else if (!strcasecmp(token, "OF-TYPE"))
+ {
+ get_token(fp, token, sizeof(token), &linenum);
+
+ if (last_expect)
+ last_expect->of_type = strdup(token);
+ else
+ {
+ fprintf(stderr,
+ "ipptest: OF-TYPE without a preceding EXPECT on line %d\n",
+ linenum);
+ httpClose(http);
+ ippDelete(request);
+ return (0);
+ }
+ }
+ else if (!strcasecmp(token, "SAME-COUNT-AS"))
+ {
+ get_token(fp, token, sizeof(token), &linenum);
+
+ if (last_expect)
+ last_expect->same_count_as = strdup(token);
+ else
+ {
+ fprintf(stderr,
+ "ipptest: SAME-COUNT-AS without a preceding EXPECT on line "
+ "%d\n", linenum);
+ httpClose(http);
+ ippDelete(request);
+ return (0);
+ }
+ }
+ else if (!strcasecmp(token, "IF-DEFINED"))
+ {
+ get_token(fp, token, sizeof(token), &linenum);
+
+ if (last_expect)
+ last_expect->if_defined = strdup(token);
+ else
+ {
+ fprintf(stderr,
+ "ipptest: IF-DEFINED without a preceding EXPECT on line %d\n",
+ linenum);
+ httpClose(http);
+ ippDelete(request);
+ return (0);
+ }
}
else if (!strcasecmp(token, "DISPLAY") &&
num_displayed < (int)(sizeof(displayed) / sizeof(displayed[0])))
@@ -550,8 +677,9 @@ do_tests(const char *uri, /* I - URI to connect on */
}
else
{
- printf("Unexpected token %s seen on line %d - aborting test!\n", token,
- linenum);
+ fprintf(stderr,
+ "ipptest: Unexpected token %s seen on line %d - aborting "
+ "test!\n", token, linenum);
httpClose(http);
ippDelete(request);
return (0);
@@ -569,7 +697,7 @@ do_tests(const char *uri, /* I - URI to connect on */
if (Verbosity)
{
- printf("%s:\n", ippOpString(op));
+ printf(" %s:\n", ippOpString(op));
for (attrptr = request->attrs; attrptr; attrptr = attrptr->next)
print_attr(attrptr);
@@ -578,7 +706,36 @@ do_tests(const char *uri, /* I - URI to connect on */
printf(" %-60.60s [", name);
fflush(stdout);
- if (filename[0])
+ if (Chunking)
+ {
+ http_status_t status = cupsSendRequest(http, request, resource, 0);
+
+ if (status == HTTP_CONTINUE && filename[0])
+ {
+ int fd; /* File to send */
+ char buffer[8192]; /* Copy buffer */
+ ssize_t bytes; /* Bytes read/written */
+
+
+ if ((fd = open(filename, O_RDONLY | O_BINARY)) >= 0)
+ {
+ while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
+ if ((status = cupsWriteRequestData(http, buffer,
+ bytes)) != HTTP_CONTINUE)
+ break;
+ }
+ else
+ status = HTTP_ERROR;
+ }
+
+ ippDelete(request);
+
+ if (status == HTTP_CONTINUE)
+ response = cupsGetResponse(http, resource);
+ else
+ response = NULL;
+ }
+ else if (filename[0])
response = cupsDoFileRequest(http, request, resource, filename);
else
response = cupsDoIORequest(http, request, resource, -1,
@@ -597,6 +754,9 @@ do_tests(const char *uri, /* I - URI to connect on */
}
else
{
+ if (http->version != HTTP_1_1)
+ pass = 0;
+
if ((attrptr = ippFindAttribute(response, "job-id",
IPP_TAG_INTEGER)) != NULL)
job_id = attrptr->values[0].integer;
@@ -613,12 +773,32 @@ do_tests(const char *uri, /* I - URI to connect on */
pass = 0;
else
{
- for (i = 0; i < num_expects; i ++)
- if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL)
- {
- pass = 0;
- break;
- }
+ for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+ {
+ if (expect->if_defined && !getenv(expect->if_defined))
+ continue;
+
+ found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
+
+ if ((found == NULL) != expect->not_expect ||
+ (found && !expect_matches(expect, found->value_tag)))
+ {
+ pass = 0;
+ break;
+ }
+
+ if (found && expect->same_count_as)
+ {
+ attrptr = ippFindAttribute(response, expect->same_count_as,
+ IPP_TAG_ZERO);
+
+ if (!attrptr || attrptr->num_values != found->num_values)
+ {
+ pass = 0;
+ break;
+ }
+ }
+ }
}
if (pass)
@@ -629,21 +809,31 @@ do_tests(const char *uri, /* I - URI to connect on */
if (Verbosity)
{
- for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
+ for (attrptr = response->attrs;
+ attrptr != NULL;
+ attrptr = attrptr->next)
+ {
print_attr(attrptr);
+ }
}
else if (num_displayed > 0)
{
- for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
+ for (attrptr = response->attrs;
+ attrptr != NULL;
+ attrptr = attrptr->next)
+ {
if (attrptr->name)
{
for (i = 0; i < num_displayed; i ++)
+ {
if (!strcmp(displayed[i], attrptr->name))
{
print_attr(attrptr);
break;
}
+ }
}
+ }
}
}
else
@@ -652,6 +842,10 @@ do_tests(const char *uri, /* I - URI to connect on */
printf(" RECEIVED: %lu bytes in response\n",
(unsigned long)ippLength(response));
+ if (http->version != HTTP_1_1)
+ printf(" BAD HTTP VERSION (%d.%d)\n", http->version / 100,
+ http->version % 100);
+
for (i = 0; i < num_statuses; i ++)
if (response->request.status.status_code == statuses[i])
break;
@@ -662,9 +856,43 @@ do_tests(const char *uri, /* I - URI to connect on */
printf(" status-code = %04x (%s)\n",
cupsLastError(), ippErrorString(cupsLastError()));
- for (i = 0; i < num_expects; i ++)
- if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL)
- printf(" EXPECTED: %s\n", expects[i]);
+ for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+ {
+ if (expect->if_defined && !getenv(expect->if_defined))
+ continue;
+
+ found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
+
+ if ((found == NULL) != expect->not_expect)
+ {
+ if (expect->not_expect)
+ printf(" NOT EXPECTED: %s\n", expect->name);
+ else
+ printf(" EXPECTED: %s\n", expect->name);
+ }
+ else if (found)
+ {
+ if (!expect_matches(expect, found->value_tag))
+ printf(" EXPECTED: %s of type %s but got %s\n",
+ expect->name, expect->of_type,
+ ippTagString(found->value_tag));
+ else if (expect->same_count_as)
+ {
+ attrptr = ippFindAttribute(response, expect->same_count_as,
+ IPP_TAG_ZERO);
+
+ if (!attrptr)
+ printf(" EXPECTED: %s (%d values) same count as %s "
+ "(not returned)\n",
+ expect->name, found->num_values, expect->same_count_as);
+ else if (attrptr->num_values != found->num_values)
+ printf(" EXPECTED: %s (%d values) same count as %s "
+ "(%d values)\n",
+ expect->name, found->num_values, expect->same_count_as,
+ attrptr->num_values);
+ }
+ }
+ }
for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
print_attr(attrptr);
@@ -673,9 +901,16 @@ do_tests(const char *uri, /* I - URI to connect on */
ippDelete(response);
}
- for (i = 0; i < num_expects; i ++)
- free(expects[i]);
-
+ for (i = num_expects, expect = expects; i > 0; i --, expect ++)
+ {
+ free(expect->name);
+ if (expect->of_type)
+ free(expect->of_type);
+ if (expect->same_count_as)
+ free(expect->same_count_as);
+ if (expect->if_defined)
+ free(expect->if_defined);
+ }
if (!pass)
break;
}
@@ -687,11 +922,71 @@ do_tests(const char *uri, /* I - URI to connect on */
}
+/*
+ * 'expect_matches()' - Return true if the tag matches the specification.
+ */
+
+static int /* O - 1 if matches, 0 otherwise */
+expect_matches(
+ _cups_expect_t *expect, /* I - Expected attribute */
+ ipp_tag_t value_tag) /* I - Value tag for attribute */
+{
+ int match; /* Match? */
+ char *of_type, /* Type name to match */
+ *next; /* Next name to match */
+
+
+ /*
+ * If we don't expect a particular type, return immediately...
+ */
+
+ if (!expect->of_type)
+ return (1);
+
+ /*
+ * Parse the "of_type" value since the string can contain multiple attribute
+ * types separated by "|"...
+ */
+
+ for (of_type = expect->of_type, match = 0; !match && of_type; of_type = next)
+ {
+ /*
+ * Find the next separator, and set it (temporarily) to nul if present.
+ */
+
+ if ((next = strchr(of_type, '|')) != NULL)
+ *next = '\0';
+
+ /*
+ * Support some meta-types to make it easier to write the test file.
+ */
+
+ if (!strcmp(of_type, "text"))
+ match = value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_TEXT;
+ else if (!strcmp(of_type, "name"))
+ match = value_tag == IPP_TAG_NAMELANG || value_tag == IPP_TAG_NAME;
+ else if (!strcmp(of_type, "collection"))
+ match = value_tag == IPP_TAG_BEGIN_COLLECTION;
+ else
+ match = value_tag == ippTagValue(of_type);
+
+ /*
+ * Restore the separator if we have one...
+ */
+
+ if (next)
+ *next++ = '|';
+ }
+
+ return (match);
+}
+
+
/*
* 'get_token()' - Get a token from a file.
*/
-char * /* O - Token from file or NULL on EOF */
+static char * /* O - Token from file or NULL on EOF */
get_token(FILE *fp, /* I - File to read from */
char *buf, /* I - Buffer to read into */
int buflen, /* I - Length of buffer */
@@ -783,7 +1078,7 @@ get_token(FILE *fp, /* I - File to read from */
* 'print_attr()' - Print an attribute on the screen.
*/
-void
+static void
print_attr(ipp_attribute_t *attr) /* I - Attribute to print */
{
int i; /* Looping var */
@@ -861,7 +1156,7 @@ print_attr(ipp_attribute_t *attr) /* I - Attribute to print */
print_col(attr->values[i].collection);
}
break;
-
+
default :
break; /* anti-compiler-warning-code */
}
@@ -874,7 +1169,7 @@ print_attr(ipp_attribute_t *attr) /* I - Attribute to print */
* 'print_col()' - Print a collection attribute on the screen.
*/
-void
+static void
print_col(ipp_t *col) /* I - Collection attribute to print */
{
int i; /* Looping var */
@@ -947,7 +1242,7 @@ print_col(ipp_t *col) /* I - Collection attribute to print */
putchar(' ');
}
break;
-
+
default :
break; /* anti-compiler-warning-code */
}
@@ -961,17 +1256,18 @@ print_col(ipp_t *col) /* I - Collection attribute to print */
* 'usage()' - Show program usage.
*/
-void
-usage(const char *option) /* I - Option string or NULL */
+static void
+usage(void)
{
- if (option)
- fprintf(stderr, "ipptest: Unknown option \"%s\"!\n", option);
-
fputs("Usage: ipptest [options] URL testfile [ ... testfileN ]\n", stderr);
fputs("Options:\n", stderr);
fputs("\n", stderr);
- fputs("-i N Repeat the last test file once every N seconds.\n", stderr);
- fputs("-v Show all attributes in response, even on success.\n", stderr);
+ fputs("-c Send requests using chunking.\n", stderr);
+ fputs("-d name=value Define variable.\n", stderr);
+ fputs("-i seconds Repeat the last test file with the given interval.\n",
+ stderr);
+ fputs("-v Show all attributes in response, even on success.\n",
+ stderr);
exit(1);
}
--
2.39.2