/*
* ipptool command for CUPS.
*
- * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 2007-2019 by Apple Inc.
* Copyright © 1997-2007 by Easy Software Products.
*
* Licensed under Apache License v2.0. See the file "LICENSE" for more
*/
#include <cups/cups-private.h>
-#include <cups/file-private.h>
#include <regex.h>
#include <sys/stat.h>
-#ifdef WIN32
+#ifdef _WIN32
# include <windows.h>
# ifndef R_OK
# define R_OK 0
#else
# include <signal.h>
# include <termios.h>
-#endif /* WIN32 */
+#endif /* _WIN32 */
#ifndef O_BINARY
# define O_BINARY 0
#endif /* !O_BINARY */
static void print_xml_header(_cups_testdata_t *data);
static void print_xml_string(cups_file_t *outfile, const char *element, const char *s);
static void print_xml_trailer(_cups_testdata_t *data, int success, const char *message);
-#ifndef WIN32
+#ifndef _WIN32
static void sigterm_handler(int sig);
-#endif /* WIN32 */
+#endif /* _WIN32 */
static int timeout_cb(http_t *http, void *user_data);
static int token_cb(_ipp_file_t *f, _ipp_vars_t *vars, _cups_testdata_t *data, const char *token);
static void usage(void) _CUPS_NORETURN;
/* Global data */
-#ifndef WIN32
+#ifndef _WIN32
/*
* Catch SIGINT and SIGTERM...
*/
signal(SIGINT, sigterm_handler);
signal(SIGTERM, sigterm_handler);
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
/*
* Initialize the locale and variables...
snprintf(filename, sizeof(filename), "%s.gz", argv[i]);
if (access(filename, 0) && filename[0] != '/'
-#ifdef WIN32
+#ifdef _WIN32
&& (!isalpha(filename[0] & 255) || filename[1] != ':')
-#endif /* WIN32 */
+#endif /* _WIN32 */
)
{
snprintf(filename, sizeof(filename), "%s/ipptool/%s", cg->cups_datadir, argv[i]);
}
if (access(argv[i], 0) && argv[i][0] != '/'
-#ifdef WIN32
+#ifdef _WIN32
&& (!isalpha(argv[i][0] & 255) || argv[i][1] != ':')
-#endif /* WIN32 */
+#endif /* _WIN32 */
)
{
snprintf(testname, sizeof(testname), "%s/ipptool/%s", cg->cups_datadir, argv[i]);
if (*dataptr < 0x20 || *dataptr >= 0x7f)
break;
- if (*dataptr)
+ if (dataptr < dataend)
{
/*
* Yes, encode as hex...
if ((size_t)datalen > bufsize)
datalen = (int)bufsize - 1;
- memcpy(buffer, data, datalen);
+ memcpy(buffer, data, (size_t)datalen);
buffer[datalen] = '\0';
}
}
}
if (!Cancel && status == HTTP_STATUS_ERROR && httpError(data->http) != EINVAL &&
-#ifdef WIN32
+#ifdef _WIN32
httpError(data->http) != WSAETIMEDOUT)
#else
httpError(data->http) != ETIMEDOUT)
-#endif /* WIN32 */
+#endif /* _WIN32 */
{
if (httpReconnect2(data->http, 30000, NULL))
data->prev_pass = 0;
}
if (!Cancel && status == HTTP_STATUS_ERROR && httpError(data->http) != EINVAL &&
-#ifdef WIN32
+#ifdef _WIN32
httpError(data->http) != WSAETIMEDOUT)
#else
httpError(data->http) != ETIMEDOUT)
-#endif /* WIN32 */
+#endif /* _WIN32 */
{
if (httpReconnect2(data->http, 30000, NULL))
data->prev_pass = 0;
*dstptr = '\0';
}
else if (!access(src, R_OK) || *src == '/'
-#ifdef WIN32
+#ifdef _WIN32
|| (isalpha(*src & 255) && src[1] == ':')
-#endif /* WIN32 */
+#endif /* _WIN32 */
)
{
/*
static void
pause_message(const char *message) /* I - Message */
{
-#ifdef WIN32
+#ifdef _WIN32
HANDLE tty; /* Console handle */
DWORD mode; /* Console mode */
char key; /* Key press */
close(tty);
return;
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
/*
* Display the prompt...
cupsFilePrintf(cupsFileStdout(), "%s\n---- PRESS ANY KEY ----", message);
-#ifdef WIN32
+#ifdef _WIN32
/*
* Read a key...
*/
tcsetattr(tty, TCSAFLUSH, &original);
close(tty);
-#endif /* WIN32 */
+#endif /* _WIN32 */
/*
* Erase the "press any key" prompt...
}
-#ifndef WIN32
+#ifndef _WIN32
/*
* 'sigterm_handler()' - Handle SIGINT and SIGTERM.
*/
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
}
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
/*
!_cups_strcasecmp(token, "WITH-VALUE"))
{
off_t lastpos; /* Last file position */
+ int lastline; /* Last line number */
if (data->last_expect)
{
for (;;)
{
- lastpos = cupsFileTell(f->fp);
- ptr += strlen(ptr);
+ lastpos = cupsFileTell(f->fp);
+ lastline = f->linenum;
+ ptr += strlen(ptr);
if (!_ippFileReadToken(f, ptr, (sizeof(temp) - (size_t)(ptr - temp))))
break;
*/
cupsFileSeek(f->fp, lastpos);
+ f->linenum = lastline;
*ptr = '\0';
break;
}
{
_cupsLangPuts(stderr, _("Usage: ipptool [options] URI filename [ ... filenameN ]"));
_cupsLangPuts(stderr, _("Options:"));
- _cupsLangPuts(stderr, _(" --help Show help."));
- _cupsLangPuts(stderr, _(" --ippserver filename Produce ippserver attribute file."));
- _cupsLangPuts(stderr, _(" --stop-after-include-error\n"
- " Stop tests after a failed INCLUDE."));
- _cupsLangPuts(stderr, _(" --version Show version."));
- _cupsLangPuts(stderr, _(" -4 Connect using IPv4."));
- _cupsLangPuts(stderr, _(" -6 Connect using IPv6."));
- _cupsLangPuts(stderr, _(" -C Send requests using "
- "chunking (default)."));
- _cupsLangPuts(stderr, _(" -E Test with encryption using HTTP Upgrade to TLS."));
- _cupsLangPuts(stderr, _(" -I Ignore errors."));
- _cupsLangPuts(stderr, _(" -L Send requests using content-length."));
- _cupsLangPuts(stderr, _(" -P filename.plist Produce XML plist to a file and test report to standard output."));
- _cupsLangPuts(stderr, _(" -S Test with encryption using HTTPS."));
- _cupsLangPuts(stderr, _(" -T seconds Set the receive/send timeout in seconds."));
- _cupsLangPuts(stderr, _(" -V version Set default IPP version."));
- _cupsLangPuts(stderr, _(" -X Produce XML plist instead of plain text."));
- _cupsLangPuts(stderr, _(" -c Produce CSV output."));
- _cupsLangPuts(stderr, _(" -d name=value Set named variable to value."));
- _cupsLangPuts(stderr, _(" -f filename Set default request filename."));
- _cupsLangPuts(stderr, _(" -h Validate HTTP response headers."));
- _cupsLangPuts(stderr, _(" -i seconds Repeat the last file with the given time interval."));
- _cupsLangPuts(stderr, _(" -l Produce plain text output."));
- _cupsLangPuts(stderr, _(" -n count Repeat the last file the given number of times."));
- _cupsLangPuts(stderr, _(" -q Run silently."));
- _cupsLangPuts(stderr, _(" -t Produce a test report."));
- _cupsLangPuts(stderr, _(" -v Be verbose."));
+ _cupsLangPuts(stderr, _("--ippserver filename Produce ippserver attribute file"));
+ _cupsLangPuts(stderr, _("--stop-after-include-error\n"
+ " Stop tests after a failed INCLUDE"));
+ _cupsLangPuts(stderr, _("--version Show version"));
+ _cupsLangPuts(stderr, _("-4 Connect using IPv4"));
+ _cupsLangPuts(stderr, _("-6 Connect using IPv6"));
+ _cupsLangPuts(stderr, _("-C Send requests using chunking (default)"));
+ _cupsLangPuts(stderr, _("-E Test with encryption using HTTP Upgrade to TLS"));
+ _cupsLangPuts(stderr, _("-I Ignore errors"));
+ _cupsLangPuts(stderr, _("-L Send requests using content-length"));
+ _cupsLangPuts(stderr, _("-P filename.plist Produce XML plist to a file and test report to standard output"));
+ _cupsLangPuts(stderr, _("-S Test with encryption using HTTPS"));
+ _cupsLangPuts(stderr, _("-T seconds Set the receive/send timeout in seconds"));
+ _cupsLangPuts(stderr, _("-V version Set default IPP version"));
+ _cupsLangPuts(stderr, _("-X Produce XML plist instead of plain text"));
+ _cupsLangPuts(stderr, _("-c Produce CSV output"));
+ _cupsLangPuts(stderr, _("-d name=value Set named variable to value"));
+ _cupsLangPuts(stderr, _("-f filename Set default request filename"));
+ _cupsLangPuts(stderr, _("-h Validate HTTP response headers"));
+ _cupsLangPuts(stderr, _("-i seconds Repeat the last file with the given time interval"));
+ _cupsLangPuts(stderr, _("-l Produce plain text output"));
+ _cupsLangPuts(stderr, _("-n count Repeat the last file the given number of times"));
+ _cupsLangPuts(stderr, _("-q Run silently"));
+ _cupsLangPuts(stderr, _("-t Produce a test report"));
+ _cupsLangPuts(stderr, _("-v Be verbose"));
exit(1);
}
case IPP_TAG_BOOLEAN :
for (i = 0; i < count; i ++)
{
- if ((!strcmp(value, "true")) == ippGetBoolean(attr, i))
+ if ((!strcmp(value, "true") || !strcmp(value, "1")) == ippGetBoolean(attr, i))
{
if (!matchbuf[0])
strlcpy(matchbuf, value, matchlen);
break;
case IPP_TAG_STRING :
+ if (flags & _CUPS_WITH_REGEX)
+ {
+ /*
+ * Value is an extended, case-sensitive POSIX regular expression...
+ */
+
+ regex_t re; /* Regular expression */
+
+ if ((i = regcomp(&re, value, REG_EXTENDED | REG_NOSUB)) != 0)
+ {
+ regerror(i, &re, temp, sizeof(temp));
+
+ print_fatal_error(data, "Unable to compile WITH-VALUE regular expression \"%s\" - %s", value, temp);
+ return (0);
+ }
+
+ /*
+ * See if ALL of the values match the given regular expression.
+ */
+
+ for (i = 0; i < count; i ++)
+ {
+ void *data; /* Pointer to octetString data */
+ int datalen; /* Length of octetString */
+
+ if ((data = ippGetOctetString(attr, i, &datalen)) == NULL || datalen >= (int)sizeof(temp))
+ {
+ match = 0;
+ break;
+ }
+ memcpy(temp, data, (size_t)datalen);
+ temp[datalen] = '\0';
+
+ if (!regexec(&re, temp, 0, NULL, 0))
+ {
+ if (!matchbuf[0])
+ strlcpy(matchbuf, temp, matchlen);
+
+ if (!(flags & _CUPS_WITH_ALL))
+ {
+ match = 1;
+ break;
+ }
+ }
+ else if (flags & _CUPS_WITH_ALL)
+ {
+ match = 0;
+ break;
+ }
+ }
+
+ regfree(&re);
+
+ if (!match && errors)
+ {
+ for (i = 0; i < count; i ++)
+ {
+ int adatalen;
+ void *adata = ippGetOctetString(attr, i, &adatalen);
+
+ copy_hex_string(temp, adata, adatalen, sizeof(temp));
+ add_stringf(data->errors, "GOT: %s=\"%s\"", name, temp);
+ }
+ }
+ }
+ else
{
+ /*
+ * Value is a literal or hex-encoded string...
+ */
+
unsigned char withdata[1023], /* WITH-VALUE data */
*adata; /* Pointer to octetString data */
int withlen, /* Length of WITH-VALUE data */
* Grab hex-encoded value...
*/
- if ((withlen = (int)strlen(value)) & 1 || withlen > (2 * (sizeof(withdata) + 1)))
+ if ((withlen = (int)strlen(value)) & 1 || withlen > (int)(2 * (sizeof(withdata) + 1)))
{
print_fatal_error(data, "Bad WITH-VALUE hex value.");
return (0);
withlen = (int)strlen(value);
- memcpy(withdata, value, withlen);
+ memcpy(withdata, value, (size_t)withlen);
}
for (i = 0; i < count; i ++)
if (withlen == adatalen && !memcmp(withdata, adata, (size_t)withlen))
{
if (!matchbuf[0])
- copy_hex_string(matchbuf, adata, adatalen, matchlen);
+ copy_hex_string(matchbuf, adata, adatalen, matchlen);
if (!(flags & _CUPS_WITH_ALL))
{