X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=blobdiff_plain;f=filter%2Fcommandtops.c;h=07979e03abb76876776f842c03ad9f25d022bf3e;hp=47a49072b12d2be58f7ac810c58f963e30b341e4;hb=57b7b66b58a66426494ec13ffb18f730afeab8b5;hpb=0837b7e828b9fc312fcf8f5741d2ba9683742672 diff --git a/filter/commandtops.c b/filter/commandtops.c index 47a49072b..07979e03a 100644 --- a/filter/commandtops.c +++ b/filter/commandtops.c @@ -1,26 +1,13 @@ /* - * "$Id$" + * PostScript command filter for CUPS. * - * PostScript command filter for CUPS. + * Copyright 2008-2014 by Apple Inc. * - * Copyright 2008-2010 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/". - * - * - * Contents: - * - * main() - Process a CUPS command file. - * auto_configure() - Automatically configure the printer using - * PostScript query commands and/or SNMP lookups. - * begin_ps() - Send the standard PostScript prolog. - * end_ps() - Send the standard PostScript trailer. - * print_self_test_page() - Print a self-test page. - * report_levels() - Report supply levels. + * 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 + * missing or damaged, see the license at "http://www.cups.org/". */ /* @@ -36,7 +23,7 @@ * Local functions... */ -static void auto_configure(ppd_file_t *ppd, const char *user); +static int auto_configure(ppd_file_t *ppd, const char *user); static void begin_ps(ppd_file_t *ppd, const char *user); static void end_ps(ppd_file_t *ppd); static void print_self_test_page(ppd_file_t *ppd, const char *user); @@ -51,6 +38,7 @@ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { + int status = 0; /* Exit status */ cups_file_t *fp; /* Command file */ char line[1024], /* Line from file */ *value; /* Value on line */ @@ -70,7 +58,7 @@ main(int argc, /* I - Number of command-line arguments */ */ _cupsLangPrintf(stderr, - _("Usage: %s job-id user title copies options file"), + _("Usage: %s job-id user title copies options [file]"), argv[0]); return (1); } @@ -112,17 +100,21 @@ main(int argc, /* I - Number of command-line arguments */ * Parse the command... */ - if (!strcasecmp(line, "AutoConfigure")) - auto_configure(ppd, argv[2]); - else if (!strcasecmp(line, "PrintSelfTestPage")) + if (!_cups_strcasecmp(line, "AutoConfigure")) + status |= auto_configure(ppd, argv[2]); + else if (!_cups_strcasecmp(line, "PrintSelfTestPage")) print_self_test_page(ppd, argv[2]); - else if (!strcasecmp(line, "ReportLevels")) + else if (!_cups_strcasecmp(line, "ReportLevels")) report_levels(ppd, argv[2]); else - fprintf(stderr, "ERROR: Invalid printer command \"%s\"!\n", line); + { + _cupsLangPrintFilter(stderr, "ERROR", + _("Invalid printer command \"%s\"."), line); + status = 1; + } } - return (0); + return (status); } @@ -131,12 +123,14 @@ main(int argc, /* I - Number of command-line arguments */ * query commands and/or SNMP lookups. */ -static void +static int /* O - Exit status */ auto_configure(ppd_file_t *ppd, /* I - PPD file */ const char *user) /* I - Printing user */ { + int status = 0; /* Exit status */ ppd_option_t *option; /* Current option in PPD */ ppd_attr_t *attr; /* Query command attribute */ + const char *valptr; /* Pointer into attribute value */ char buffer[1024], /* String buffer */ *bufptr; /* Pointer into buffer */ ssize_t bytes; /* Number of bytes read */ @@ -154,7 +148,7 @@ auto_configure(ppd_file_t *ppd, /* I - PPD file */ { fputs("DEBUG: Unable to auto-configure PostScript Printer - no " "bidirectional I/O available!\n", stderr); - return; + return (1); } /* @@ -163,6 +157,38 @@ auto_configure(ppd_file_t *ppd, /* I - PPD file */ begin_ps(ppd, user); + /* + * (STR #4028) + * + * As a lot of PPDs contain bad PostScript query code, we need to prevent one + * bad query sequence from affecting all auto-configuration. The following + * error handler allows us to log PostScript errors to cupsd. + */ + + puts("/cups_handleerror {\n" + " $error /newerror false put\n" + " (:PostScript error in \") print cups_query_keyword print (\": ) " + "print\n" + " $error /errorname get 128 string cvs print\n" + " (; offending command:) print $error /command get 128 string cvs " + "print (\n) print flush\n" + "} bind def\n" + "errordict /timeout {} put\n" + "/cups_query_keyword (?Unknown) def\n"); + fflush(stdout); + + /* + * Wait for the printer to become connected... + */ + + do + { + sleep(1); + datalen = 1; + } + while (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_CONNECTED, buffer, &datalen, + 5.0) == CUPS_SC_STATUS_OK && !buffer[0]); + /* * Then loop through every option in the PPD file and ask for the current * value... @@ -189,7 +215,76 @@ auto_configure(ppd_file_t *ppd, /* I - PPD file */ */ fprintf(stderr, "DEBUG: Querying %s...\n", option->keyword); - fputs(attr->value, stdout); + + for (bufptr = buffer, valptr = attr->value; *valptr; valptr ++) + { + /* + * Log the query code, breaking at newlines... + */ + + if (*valptr == '\n') + { + *bufptr = '\0'; + fprintf(stderr, "DEBUG: %s\\n\n", buffer); + bufptr = buffer; + } + else if (*valptr < ' ') + { + if (bufptr >= (buffer + sizeof(buffer) - 4)) + { + *bufptr = '\0'; + fprintf(stderr, "DEBUG: %s\n", buffer); + bufptr = buffer; + } + + if (*valptr == '\r') + { + *bufptr++ = '\\'; + *bufptr++ = 'r'; + } + else if (*valptr == '\t') + { + *bufptr++ = '\\'; + *bufptr++ = 't'; + } + else + { + *bufptr++ = '\\'; + *bufptr++ = '0' + ((*valptr / 64) & 7); + *bufptr++ = '0' + ((*valptr / 8) & 7); + *bufptr++ = '0' + (*valptr & 7); + } + } + else + { + if (bufptr >= (buffer + sizeof(buffer) - 1)) + { + *bufptr = '\0'; + fprintf(stderr, "DEBUG: %s\n", buffer); + bufptr = buffer; + } + + *bufptr++ = *valptr; + } + } + + if (bufptr > buffer) + { + *bufptr = '\0'; + fprintf(stderr, "DEBUG: %s\n", buffer); + } + + printf("/cups_query_keyword (?%s) def\n", option->keyword); + /* Set keyword for error reporting */ + fputs("{ (", stdout); + for (valptr = attr->value; *valptr; valptr ++) + { + if (*valptr == '(' || *valptr == ')' || *valptr == '\\') + putchar('\\'); + putchar(*valptr); + } + fputs(") cvx exec } stopped { cups_handleerror } if clear\n", stdout); + /* Send query code */ fflush(stdout); datalen = 0; @@ -199,44 +294,117 @@ auto_configure(ppd_file_t *ppd, /* I - PPD file */ * Read the response data... */ - while ((bytes = cupsBackChannelRead(buffer, sizeof(buffer) - 1, 5.0)) > 0) + bufptr = buffer; + buffer[0] = '\0'; + while ((bytes = cupsBackChannelRead(bufptr, sizeof(buffer) - (size_t)(bufptr - buffer) - 1, 10.0)) > 0) { /* - * Trim whitespace from both ends... + * No newline at the end? Go on reading ... + */ + + bufptr += bytes; + *bufptr = '\0'; + + if (bytes == 0 || + (bufptr > buffer && bufptr[-1] != '\r' && bufptr[-1] != '\n')) + continue; + + /* + * Trim whitespace and control characters from both ends... */ - buffer[bytes] = '\0'; + bytes = bufptr - buffer; - for (bufptr = buffer + bytes - 1; bufptr >= buffer; bufptr --) - if (isspace(*bufptr & 255)) + for (bufptr --; bufptr >= buffer; bufptr --) + if (isspace(*bufptr & 255) || iscntrl(*bufptr & 255)) *bufptr = '\0'; else break; - for (bufptr = buffer; isspace(*bufptr & 255); bufptr ++); + for (bufptr = buffer; isspace(*bufptr & 255) || iscntrl(*bufptr & 255); + bufptr ++); + + if (bufptr > buffer) + { + _cups_strcpy(buffer, bufptr); + bufptr = buffer; + } + + fprintf(stderr, "DEBUG: Got %d bytes.\n", (int)bytes); /* * Skip blank lines... */ - if (!*bufptr) + if (!buffer[0]) + continue; + + /* + * Check the response... + */ + + if ((bufptr = strchr(buffer, ':')) != NULL) + { + /* + * PostScript code for this option in the PPD is broken; show the + * interpreter's error message that came back... + */ + + fprintf(stderr, "DEBUG%s\n", bufptr); + break; + } + + /* + * Verify the result is a valid option choice... + */ + + if (!ppdFindChoice(option, buffer)) + { + if (!strcasecmp(buffer, "Unknown")) + break; + + bufptr = buffer; + buffer[0] = '\0'; continue; + } /* * Write out the result and move on to the next option... */ - fprintf(stderr, "DEBUG: Default%s=%s\n", option->keyword, bufptr); - fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, bufptr); + fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, buffer); break; } + + /* + * Printer did not answer this option's query + */ + + if (bytes <= 0) + { + fprintf(stderr, + "DEBUG: No answer to query for option %s within 10 seconds.\n", + option->keyword); + status = 1; + } } /* * Finish the job... */ + fflush(stdout); end_ps(ppd); + + /* + * Return... + */ + + if (status) + _cupsLangPrintFilter(stderr, "WARNING", + _("Unable to configure printer options.")); + + return (0); } @@ -258,6 +426,7 @@ begin_ps(ppd_file_t *ppd, /* I - PPD file */ puts("%!"); puts("userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n"); + fflush(stdout); } @@ -297,7 +466,12 @@ print_self_test_page(ppd_file_t *ppd, /* I - PPD file */ * the product/interpreter information... */ - puts("% You are using the wrong driver for your printer!\n" + puts("\r%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" + "%%%%%%%%%%%%%\n" + "\r%%%% If you can read this, you are using the wrong driver for your " + "printer. %%%%\n" + "\r%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" + "%%%%%%%%%%%%%\n" "0 setgray\n" "2 setlinewidth\n" "initclip newpath clippath gsave stroke grestore pathbbox\n" @@ -342,8 +516,3 @@ report_levels(ppd_file_t *ppd, /* I - PPD file */ end_ps(ppd); } - - -/* - * End of "$Id$". - */