#include <cups/cups-private.h>
#include <cups/ppd.h>
#include <cups/sidechannel.h>
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);
static void report_levels(ppd_file_t *ppd, const char *user);
int
main(int argc,
char *argv[])
{
int status = 0;
cups_file_t *fp;
char line[1024],
*value;
int linenum;
ppd_file_t *ppd;
if (argc < 6 || argc > 7)
{
_cupsLangPrintf(stderr,
_("Usage: %s job-id user title copies options [file]"),
argv[0]);
return (1);
}
if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL)
{
fputs("ERROR: Unable to open PPD file!\n", stderr);
return (1);
}
if (argc == 7)
{
if ((fp = cupsFileOpen(argv[6], "r")) == NULL)
{
perror("ERROR: Unable to open command file - ");
return (1);
}
}
else
fp = cupsFileStdin();
linenum = 0;
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
{
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 (!_cups_strcasecmp(line, "ReportLevels"))
report_levels(ppd, argv[2]);
else
{
_cupsLangPrintFilter(stderr, "ERROR",
_("Invalid printer command \"%s\"."), line);
status = 1;
}
}
return (status);
}
static int
auto_configure(ppd_file_t *ppd,
const char *user)
{
int status = 0;
ppd_option_t *option;
ppd_attr_t *attr;
const char *valptr;
char buffer[1024],
*bufptr;
ssize_t bytes;
int datalen;
datalen = 1;
if (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, buffer, &datalen,
30.0) != CUPS_SC_STATUS_OK ||
buffer[0] != CUPS_SC_BIDI_SUPPORTED)
{
fputs("DEBUG: Unable to auto-configure PostScript Printer - no "
"bidirectional I/O available!\n", stderr);
return (1);
}
begin_ps(ppd, user);
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);
do
{
sleep(1);
datalen = 1;
}
while (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_CONNECTED, buffer, &datalen,
5.0) == CUPS_SC_STATUS_OK && !buffer[0]);
fputs("DEBUG: Auto-configuring PostScript printer...\n", stderr);
for (option = ppdFirstOption(ppd); option; option = ppdNextOption(ppd))
{
snprintf(buffer, sizeof(buffer), "?%s", option->keyword);
if ((attr = ppdFindAttr(ppd, buffer, NULL)) == NULL || !attr->value)
{
fprintf(stderr, "DEBUG: Skipping %s option...\n", option->keyword);
continue;
}
fprintf(stderr, "DEBUG: Querying %s...\n", option->keyword);
for (bufptr = buffer, valptr = attr->value; *valptr; valptr ++)
{
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);
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);
fflush(stdout);
datalen = 0;
cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer, &datalen, 5.0);
bufptr = buffer;
buffer[0] = '\0';
while ((bytes = cupsBackChannelRead(bufptr, sizeof(buffer) - (size_t)(bufptr - buffer) - 1, 10.0)) > 0)
{
bufptr += bytes;
*bufptr = '\0';
if (bytes == 0 ||
(bufptr > buffer && bufptr[-1] != '\r' && bufptr[-1] != '\n'))
continue;
bytes = bufptr - buffer;
for (bufptr --; bufptr >= buffer; bufptr --)
if (isspace(*bufptr & 255) || iscntrl(*bufptr & 255))
*bufptr = '\0';
else
break;
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);
if (!buffer[0])
continue;
if ((bufptr = strchr(buffer, ':')) != NULL)
{
fprintf(stderr, "DEBUG%s\n", bufptr);
break;
}
if (!ppdFindChoice(option, buffer))
{
if (!strcasecmp(buffer, "Unknown"))
break;
bufptr = buffer;
buffer[0] = '\0';
continue;
}
fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, buffer);
break;
}
if (bytes <= 0)
{
fprintf(stderr,
"DEBUG: No answer to query for option %s within 10 seconds.\n",
option->keyword);
status = 1;
}
}
fflush(stdout);
end_ps(ppd);
if (status)
_cupsLangPrintFilter(stderr, "WARNING",
_("Unable to configure printer options."));
return (0);
}
static void
begin_ps(ppd_file_t *ppd,
const char *user)
{
(void)user;
if (ppd->jcl_begin)
{
fputs(ppd->jcl_begin, stdout);
fputs(ppd->jcl_ps, stdout);
}
puts("%!");
puts("userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n");
fflush(stdout);
}
static void
end_ps(ppd_file_t *ppd)
{
if (ppd->jcl_end)
fputs(ppd->jcl_end, stdout);
else
putchar(0x04);
fflush(stdout);
}
static void
print_self_test_page(ppd_file_t *ppd,
const char *user)
{
begin_ps(ppd, user);
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"
"exch pop exch pop exch 9 add exch 9 sub moveto\n"
"/Courier findfont 12 scalefont setfont\n"
"0 -12 rmoveto gsave product show grestore\n"
"0 -12 rmoveto gsave version show ( ) show revision 20 string cvs show "
"grestore\n"
"0 -12 rmoveto gsave serialnumber 20 string cvs show grestore\n"
"showpage");
end_ps(ppd);
}
static void
report_levels(ppd_file_t *ppd,
const char *user)
{
begin_ps(ppd, user);
end_ps(ppd);
}