diff options
author | Michael R Sweet <michael.r.sweet@gmail.com> | 2021-04-29 09:03:36 -0400 |
---|---|---|
committer | Michael R Sweet <michael.r.sweet@gmail.com> | 2021-04-29 09:03:36 -0400 |
commit | c033a5c1c532c4777a9ab71009cfeb9ba81e5a35 (patch) | |
tree | 8b19fbf044dd37cefb41613b90d1779f2a81d6bb | |
parent | 2201569857f225c9874bfae19713ffb2f4bdfdeb (diff) | |
download | cups-c033a5c1c532c4777a9ab71009cfeb9ba81e5a35.tar.gz |
Fix a DISPLAY bug in ipptool (OpenPrinting #139)
Also bring over improvements to the MONITOR-PRINTER-STATE support.
-rw-r--r-- | CHANGES.md | 1 | ||||
-rw-r--r-- | tools/ipptool.c | 334 |
2 files changed, 202 insertions, 133 deletions
diff --git a/CHANGES.md b/CHANGES.md index 5e9ede17e..2309154bc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -70,6 +70,7 @@ Changes in CUPS v2.3.5 test (OpenPrinting #153) - Root certificates were incorrectly stored in "~/.cups/ssl". - Fixed a PPD memory leak caused by emulator definitions (OpenPrinting #124) +- Fixed a `DISPLAY` bug in `ipptool` (OpenPrinting #139) - `httpReconnect2` did not reset the socket file descriptor when the TLS negotiation failed (Issue #5907) - `httpUpdate` did not reset the socket file descriptor when the TLS diff --git a/tools/ipptool.c b/tools/ipptool.c index e3692524c..11c93e1ea 100644 --- a/tools/ipptool.c +++ b/tools/ipptool.c @@ -32,6 +32,15 @@ /* + * Limits... + */ + +#define MAX_EXPECT 200 // Maximum number of EXPECT directives +#define MAX_DISPLAY 200 // Maximum number of DISPLAY directives +#define MAX_MONITOR 10 // Maximum number of MONITOR-PRINTER-STATE EXPECT directives + + +/* * Types... */ @@ -136,9 +145,9 @@ typedef struct ipptool_test_s /**** Test Data ****/ char compression[16]; /* COMPRESSION value */ useconds_t delay; /* Initial delay */ int num_displayed; /* Number of displayed attributes */ - char *displayed[200]; /* Displayed attributes */ + char *displayed[MAX_DISPLAY];/* Displayed attributes */ int num_expects; /* Number of expected attributes */ - ipptool_expect_t expects[200], /* Expected attributes */ + ipptool_expect_t expects[MAX_EXPECT], /* Expected attributes */ *expect, /* Current expected attribute */ *last_expect; /* Last EXPECT (for predicates) */ char file[1024], /* Data filename */ @@ -149,7 +158,8 @@ typedef struct ipptool_test_s /**** Test Data ****/ useconds_t repeat_interval; /* Repeat interval (delay) */ int request_id; /* Current request ID */ char resource[512]; /* Resource for request */ - int skip_test, /* Skip this test? */ + int pass_test, /* Pass this test? */ + skip_test, /* Skip this test? */ num_statuses; /* Number of valid status codes */ ipptool_status_t statuses[100], /* Valid status codes */ *last_status; /* Last STATUS (for predicates) */ @@ -162,7 +172,8 @@ typedef struct ipptool_test_s /**** Test Data ****/ useconds_t monitor_delay, /* MONITOR-PRINTER-STATE DELAY value, if any */ monitor_interval; /* MONITOR-PRINTER-STATE DELAY interval */ int num_monitor_expects; /* Number MONITOR-PRINTER-STATE EXPECTs */ - ipptool_expect_t monitor_expects[10]; /* MONITOR-PRINTER-STATE EXPECTs */ + ipptool_expect_t monitor_expects[MAX_MONITOR]; + /* MONITOR-PRINTER-STATE EXPECTs */ } ipptool_test_t; @@ -192,11 +203,11 @@ static char *iso_date(const ipp_uchar_t *date); static int parse_monitor_printer_state(_ipp_file_t *f, ipptool_test_t *data); static void pause_message(const char *message); static void print_attr(cups_file_t *outfile, ipptool_output_t output, ipp_attribute_t *attr, ipp_tag_t *group); -static void print_csv(ipptool_test_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths); +static ipp_attribute_t *print_csv(ipptool_test_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths); static void print_fatal_error(ipptool_test_t *data, const char *s, ...) _CUPS_FORMAT(2, 3); static void print_ippserver_attr(ipptool_test_t *data, ipp_attribute_t *attr, int indent); static void print_ippserver_string(ipptool_test_t *data, const char *s, size_t len); -static void print_line(ipptool_test_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths); +static ipp_attribute_t *print_line(ipptool_test_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths); static void print_xml_header(ipptool_test_t *data); static void print_xml_string(cups_file_t *outfile, const char *element, const char *s); static void print_xml_trailer(ipptool_test_t *data, int success, const char *message); @@ -327,12 +338,12 @@ main(int argc, /* I - Number of command-line args */ break; case 'E' : /* Encrypt with TLS */ -#ifdef HAVE_SSL +#ifdef HAVE_TLS data.encryption = HTTP_ENCRYPT_REQUIRED; #else _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]); -#endif /* HAVE_SSL */ +#endif /* HAVE_TLS */ break; case 'I' : /* Ignore errors */ @@ -375,11 +386,11 @@ main(int argc, /* I - Number of command-line args */ break; case 'S' : /* Encrypt with SSL */ -#ifdef HAVE_SSL +#ifdef HAVE_TLS data.encryption = HTTP_ENCRYPT_ALWAYS; #else _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), "ipptool"); -#endif /* HAVE_SSL */ +#endif /* HAVE_TLS */ break; case 'T' : /* Set timeout */ @@ -623,9 +634,9 @@ main(int argc, /* I - Number of command-line args */ } } else if (!strncmp(argv[i], "ipp://", 6) || !strncmp(argv[i], "http://", 7) -#ifdef HAVE_SSL +#ifdef HAVE_TLS || !strncmp(argv[i], "ipps://", 7) || !strncmp(argv[i], "https://", 8) -#endif /* HAVE_SSL */ +#endif /* HAVE_TLS */ ) { /* @@ -638,10 +649,10 @@ main(int argc, /* I - Number of command-line args */ usage(); } -#ifdef HAVE_SSL +#ifdef HAVE_TLS if (!strncmp(argv[i], "ipps://", 7) || !strncmp(argv[i], "https://", 8)) data.encryption = HTTP_ENCRYPT_ALWAYS; -#endif /* HAVE_SSL */ +#endif /* HAVE_TLS */ if (!_ippVarsSet(data.vars, "uri", argv[i])) { @@ -680,7 +691,12 @@ main(int argc, /* I - Number of command-line args */ else testfile = argv[i]; - if (!do_tests(testfile, &data)) + if (access(testfile, 0)) + { + _cupsLangPrintf(stderr, _("%s: Unable to open \"%s\": %s"), "ipptool", testfile, strerror(errno)); + status = 1; + } + else if (!do_tests(testfile, &data)) status = 1; } } @@ -903,7 +919,7 @@ static void * // O - Thread exit status do_monitor_printer_state( ipptool_test_t *data) // I - Test data { - int i; // Looping var + int i, j; // Looping vars char scheme[32], // URI scheme userpass[32], // URI username:password host[256], // URI hostname/IP address @@ -917,47 +933,8 @@ do_monitor_printer_state( ipp_attribute_t *found; // Found attribute ipptool_expect_t *expect; // Current EXPECT test char buffer[131072]; // Copy buffer - static const char *pattrs[] = // List of attributes we care about - { - "marker-change-time", // "marker-xxx" are a CUPS/AirPrint extension - "marker-colors", - "marker-high-levels", - "marker-levels", - "marker-low-levels", - "marker-message", - "marker-names", - "marker-types", - "printer-alert", - "printer-alert-description", - "printer-config-change-date-time", - "printer-config-change-time", - "printer-config-changes", - "printer-current-time", - "printer-finisher", - "printer-finisher-description", - "printer-finisher-supplies", - "printer-finisher-supplies-description", - "printer-impressions-completed", - "printer-impressions-completed-col", - "printer-input-tray", - "printer-is-accepting-jobs", - "printer-media-sheets-completed", - "printer-media-sheets-completed-col", - "printer-message-date-time", - "printer-message-from-operator", - "printer-message-time", - "printer-output-tray", - "printer-pages-completed", - "printer-pages-completed-col", - "printer-state", - "printer-state-change-date-time", - "printer-state-change-time", - "printer-state-reasons", - "printer-supply", - "printer-supply-description", - "printer-up-time", - "queued-job-count" - }; + int num_pattrs; // Number of printer attributes + const char *pattrs[100]; // Printer attributes we care about // Connect to the printer... @@ -993,15 +970,33 @@ do_monitor_printer_state( // Create a query request that we'll reuse... request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippSetRequestId(request, data->request_id * 100 - 1); ippSetVersion(request, data->version / 10, data->version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, data->monitor_uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); - ippAddStrings(request, IPP_TAG_OPERATION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); + + for (i = data->num_monitor_expects, expect = data->monitor_expects, num_pattrs = 0; i > 0; i --, expect ++) + { + // Add EXPECT attribute names... + for (j = 0; j < num_pattrs; j ++) + { + if (!strcmp(expect->name, pattrs[j])) + break; + } + + if (j >= num_pattrs && num_pattrs < (int)(sizeof(pattrs) / sizeof(pattrs[0]))) + pattrs[num_pattrs ++] = expect->name; + } + + if (num_pattrs > 0) + ippAddStrings(request, IPP_TAG_OPERATION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "requested-attributes", num_pattrs, NULL, pattrs); // Loop until we need to stop... while (!data->monitor_done && !Cancel) { // Poll the printer state... + ippSetRequestId(request, ippGetRequestId(request) + 1); + if ((status = cupsSendRequest(http, request, resource, ippLength(request))) != HTTP_STATUS_ERROR) { response = cupsGetResponse(http, resource); @@ -1191,7 +1186,7 @@ do_test(_ipp_file_t *f, /* I - IPP data file */ if (data->pause[0]) { - if (!data->skip_test) + if (!data->skip_test && !data->pass_test) pause_message(data->pause); data->pause[0] = '\0'; @@ -1266,9 +1261,10 @@ do_test(_ipp_file_t *f, /* I - IPP data file */ cupsFilePrintf(cupsFileStdout(), " %-68.68s [", data->name); } - if ((data->skip_previous && !data->prev_pass) || data->skip_test) + if ((data->skip_previous && !data->prev_pass) || data->skip_test || data->pass_test) { - data->skip_count ++; + if (!data->pass_test) + data->skip_count ++; ippDelete(request); request = NULL; @@ -1279,15 +1275,26 @@ do_test(_ipp_file_t *f, /* I - IPP data file */ cupsFilePuts(data->outfile, "<key>Successful</key>\n"); cupsFilePuts(data->outfile, "<true />\n"); cupsFilePuts(data->outfile, "<key>Skipped</key>\n"); - cupsFilePuts(data->outfile, "<true />\n"); + if (data->pass_test) + cupsFilePuts(data->outfile, "<false />\n"); + else + cupsFilePuts(data->outfile, "<true />\n"); cupsFilePuts(data->outfile, "<key>StatusCode</key>\n"); - print_xml_string(data->outfile, "string", "skip"); + if (data->pass_test) + print_xml_string(data->outfile, "string", "pass"); + else + print_xml_string(data->outfile, "string", "skip"); cupsFilePuts(data->outfile, "<key>ResponseAttributes</key>\n"); cupsFilePuts(data->outfile, "<dict />\n"); } if (data->output == IPPTOOL_OUTPUT_TEST || (data->output == IPPTOOL_OUTPUT_PLIST && data->outfile != cupsFileStdout())) - cupsFilePuts(cupsFileStdout(), "SKIP]\n"); + { + if (data->pass_test) + cupsFilePuts(cupsFileStdout(), "PASS]\n"); + else + cupsFilePuts(cupsFileStdout(), "SKIP]\n"); + } goto skip_error; } @@ -2038,9 +2045,9 @@ do_test(_ipp_file_t *f, /* I - IPP data file */ if (attrptr) { if (data->output == IPPTOOL_OUTPUT_CSV) - print_csv(data, response, attrptr, data->num_displayed, data->displayed, widths); + attrptr = print_csv(data, response, attrptr, data->num_displayed, data->displayed, widths); else - print_line(data, response, attrptr, data->num_displayed, data->displayed, widths); + attrptr = print_line(data, response, attrptr, data->num_displayed, data->displayed, widths); while (attrptr && ippGetGroupTag(attrptr) > IPP_TAG_OPERATION) attrptr = ippNextAttribute(response); @@ -2672,7 +2679,8 @@ parse_monitor_printer_state( if (strcmp(temp, "{")) { // Got a printer URI so copy it... - data->monitor_uri = strdup(temp); + _ippVarsExpand(data->vars, value, temp, sizeof(value)); + data->monitor_uri = strdup(value); // Then see if we have an opening brace... if (!_ippFileReadToken(f, temp, sizeof(temp)) || strcmp(temp, "{")) @@ -3162,10 +3170,10 @@ pause_message(const char *message) /* I - Message */ */ static void -print_attr(cups_file_t *outfile, /* I - Output file */ - ipptool_output_t output, /* I - Output format */ - ipp_attribute_t *attr, /* I - Attribute to print */ - ipp_tag_t *group) /* IO - Current group */ +print_attr(cups_file_t *outfile, /* I - Output file */ + ipptool_output_t output, /* I - Output format */ + ipp_attribute_t *attr, /* I - Attribute to print */ + ipp_tag_t *group) /* IO - Current group */ { int i, /* Looping var */ count; /* Number of values */ @@ -3319,21 +3327,20 @@ print_attr(cups_file_t *outfile, /* I - Output file */ * 'print_csv()' - Print a line of CSV text. */ -static void +static ipp_attribute_t * /* O - Next attribute */ print_csv( - ipptool_test_t *data, /* I - Test data */ - ipp_t *ipp, /* I - Response message */ - ipp_attribute_t *attr, /* I - First attribute for line */ - int num_displayed, /* I - Number of attributes to display */ - char **displayed, /* I - Attributes to display */ - size_t *widths) /* I - Column widths */ + ipptool_test_t *data, /* I - Test data */ + ipp_t *ipp, /* I - Response message */ + ipp_attribute_t *attr, /* I - First attribute for line */ + int num_displayed, /* I - Number of attributes to display */ + char **displayed, /* I - Attributes to display */ + size_t *widths) /* I - Column widths */ { int i; /* Looping var */ size_t maxlength; /* Max length of all columns */ - char *buffer, /* String buffer */ - *bufptr; /* Pointer into buffer */ - ipp_attribute_t *current; /* Current attribute */ - + ipp_attribute_t *current = attr; /* Current attribute */ + char *values[MAX_DISPLAY], /* Strings to display */ + *valptr; /* Pointer into value */ /* * Get the maximum string length we have to show and allocate... @@ -3345,63 +3352,76 @@ print_csv( maxlength += 2; - if ((buffer = malloc(maxlength)) == NULL) - return; - /* * Loop through the attributes to display... */ if (attr) { - for (i = 0; i < num_displayed; i ++) - { - if (i) - cupsFilePutChar(data->outfile, ','); + // Collect the values... + memset(values, 0, sizeof(values)); - buffer[0] = '\0'; + for (; current; current = ippNextAttribute(ipp)) + { + if (!ippGetName(current)) + break; - for (current = attr; current; current = ippNextAttribute(ipp)) + for (i = 0; i < num_displayed; i ++) { - if (!ippGetName(current)) - break; - else if (!strcmp(ippGetName(current), displayed[i])) + if (!strcmp(ippGetName(current), displayed[i])) { - ippAttributeString(current, buffer, maxlength); + if ((values[i] = (char *)calloc(1, maxlength)) != NULL) + ippAttributeString(current, values[i], maxlength); break; - } + } } + } + + // Output the line... + for (i = 0; i < num_displayed; i ++) + { + if (i) + cupsFilePutChar(data->outfile, ','); - if (strchr(buffer, ',') != NULL || strchr(buffer, '\"') != NULL || - strchr(buffer, '\\') != NULL) + if (!values[i]) + continue; + + if (strchr(values[i], ',') != NULL || strchr(values[i], '\"') != NULL || strchr(values[i], '\\') != NULL) { - cupsFilePutChar(cupsFileStdout(), '\"'); - for (bufptr = buffer; *bufptr; bufptr ++) + // Quoted value... + cupsFilePutChar(data->outfile, '\"'); + for (valptr = values[i]; *valptr; valptr ++) { - if (*bufptr == '\\' || *bufptr == '\"') - cupsFilePutChar(cupsFileStdout(), '\\'); - cupsFilePutChar(cupsFileStdout(), *bufptr); + if (*valptr == '\\' || *valptr == '\"') + cupsFilePutChar(data->outfile, '\\'); + cupsFilePutChar(data->outfile, *valptr); } - cupsFilePutChar(cupsFileStdout(), '\"'); + cupsFilePutChar(data->outfile, '\"'); } else - cupsFilePuts(data->outfile, buffer); + { + // Unquoted value... + cupsFilePuts(data->outfile, values[i]); + } + + free(values[i]); } - cupsFilePutChar(cupsFileStdout(), '\n'); + cupsFilePutChar(data->outfile, '\n'); } else { + // Show column headings... for (i = 0; i < num_displayed; i ++) { if (i) - cupsFilePutChar(cupsFileStdout(), ','); + cupsFilePutChar(data->outfile, ','); cupsFilePuts(data->outfile, displayed[i]); } - cupsFilePutChar(cupsFileStdout(), '\n'); + cupsFilePutChar(data->outfile, '\n'); } - free(buffer); + return (current); } @@ -3580,7 +3600,7 @@ print_ippserver_string( * 'print_line()' - Print a line of formatted or CSV text. */ -static void +static ipp_attribute_t * /* O - Next attribute */ print_line( ipptool_test_t *data, /* I - Test data */ ipp_t *ipp, /* I - Response message */ @@ -3591,8 +3611,8 @@ print_line( { int i; /* Looping var */ size_t maxlength; /* Max length of all columns */ - char *buffer; /* String buffer */ - ipp_attribute_t *current; /* Current attribute */ + ipp_attribute_t *current = attr; /* Current attribute */ + char *values[MAX_DISPLAY]; /* Strings to display */ /* @@ -3605,61 +3625,74 @@ print_line( maxlength += 2; - if ((buffer = malloc(maxlength)) == NULL) - return; - /* * Loop through the attributes to display... */ if (attr) { - for (i = 0; i < num_displayed; i ++) - { - if (i) - cupsFilePutChar(cupsFileStdout(), ' '); + // Collect the values... + memset(values, 0, sizeof(values)); - buffer[0] = '\0'; + for (; current; current = ippNextAttribute(ipp)) + { + if (!ippGetName(current)) + break; - for (current = attr; current; current = ippNextAttribute(ipp)) + for (i = 0; i < num_displayed; i ++) { - if (!ippGetName(current)) - break; - else if (!strcmp(ippGetName(current), displayed[i])) + if (!strcmp(ippGetName(current), displayed[i])) { - ippAttributeString(current, buffer, maxlength); + if ((values[i] = (char *)calloc(1, maxlength)) != NULL) + ippAttributeString(current, values[i], maxlength); break; - } + } } + } + + // Output the line... + for (i = 0; i < num_displayed; i ++) + { + if (i) + cupsFilePutChar(data->outfile, ' '); - cupsFilePrintf(data->outfile, "%*s", (int)-widths[i], buffer); + cupsFilePrintf(data->outfile, "%*s", (int)-widths[i], values[i] ? values[i] : ""); + free(values[i]); } - cupsFilePutChar(cupsFileStdout(), '\n'); + cupsFilePutChar(data->outfile, '\n'); } else { + // Show column headings... + char *buffer = (char *)malloc(maxlength); + // Buffer for separator lines + + if (!buffer) + return (current); + for (i = 0; i < num_displayed; i ++) { if (i) - cupsFilePutChar(cupsFileStdout(), ' '); + cupsFilePutChar(data->outfile, ' '); cupsFilePrintf(data->outfile, "%*s", (int)-widths[i], displayed[i]); } - cupsFilePutChar(cupsFileStdout(), '\n'); + cupsFilePutChar(data->outfile, '\n'); for (i = 0; i < num_displayed; i ++) { if (i) - cupsFilePutChar(cupsFileStdout(), ' '); + cupsFilePutChar(data->outfile, ' '); memset(buffer, '-', widths[i]); buffer[widths[i]] = '\0'; cupsFilePuts(data->outfile, buffer); } - cupsFilePutChar(cupsFileStdout(), '\n'); + cupsFilePutChar(data->outfile, '\n'); + free(buffer); } - free(buffer); + return (current); } @@ -4061,6 +4094,40 @@ token_cb(_ipp_file_t *f, /* I - IPP file data */ return (0); } } + else if (!strcmp(token, "PASS-IF-DEFINED")) + { + /* + * PASS-IF-DEFINED variable + */ + + if (_ippFileReadToken(f, name, sizeof(name))) + { + if (_ippVarsGet(vars, name)) + data->pass_test = 1; + } + else + { + print_fatal_error(data, "Missing PASS-IF-DEFINED value on line %d of \"%s\".", f->linenum, f->filename); + return (0); + } + } + else if (!strcmp(token, "PASS-IF-NOT-DEFINED")) + { + /* + * PASS-IF-NOT-DEFINED variable + */ + + if (_ippFileReadToken(f, name, sizeof(name))) + { + if (!_ippVarsGet(vars, name)) + data->pass_test = 1; + } + else + { + print_fatal_error(data, "Missing PASS-IF-NOT-DEFINED value on line %d of \"%s\".", f->linenum, f->filename); + return (0); + } + } else if (!strcmp(token, "SKIP-IF-DEFINED")) { /* @@ -4890,6 +4957,7 @@ token_cb(_ipp_file_t *f, /* I - IPP file data */ data->repeat_interval = 5000000; strlcpy(data->resource, data->vars->resource, sizeof(data->resource)); data->skip_previous = 0; + data->pass_test = 0; data->skip_test = 0; data->num_statuses = 0; data->last_status = NULL; |