/*1* TBCP port monitor for CUPS.2*3* Copyright 2007-2014 by Apple Inc.4* Copyright 1993-2006 by Easy Software Products.5*6* Licensed under Apache License v2.0. See the file "LICENSE" for more information.7*/89/*10* Include necessary headers...11*/1213#include <cups/cups-private.h>14#include <cups/ppd.h>151617/*18* Local functions...19*/2021static char *psgets(char *buf, size_t *bytes, FILE *fp);22static ssize_t pswrite(const char *buf, size_t bytes);232425/*26* 'main()' - Main entry...27*/2829int /* O - Exit status */30main(int argc, /* I - Number of command-line args */31char *argv[]) /* I - Command-line arguments */32{33FILE *fp; /* File to print */34int copies; /* Number of copies left */35char line[1024]; /* Line/buffer from stream/file */36size_t linelen; /* Length of line */373839/*40* Check command-line...41*/4243if (argc < 6 || argc > 7)44{45_cupsLangPrintf(stderr,46_("Usage: %s job-id user title copies options [file]"),47argv[0]);48return (1);49}5051if (argc == 6)52{53copies = 1;54fp = stdin;55}56else57{58copies = atoi(argv[4]);59fp = fopen(argv[6], "rb");6061if (!fp)62{63perror(argv[6]);64return (1);65}66}6768/*69* Copy the print file to stdout...70*/7172while (copies > 0)73{74copies --;7576/*77* Read the first line...78*/7980linelen = sizeof(line);81if (!psgets(line, &linelen, fp))82break;8384/*85* Handle leading PJL fun...86*/8788if (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5))89{90/*91* Yup, we have leading PJL fun, so copy it until we hit a line92* with "ENTER LANGUAGE"...93*/9495while (strstr(line, "ENTER LANGUAGE") == NULL)96{97fwrite(line, 1, linelen, stdout);9899linelen = sizeof(line);100if (psgets(line, &linelen, fp) == NULL)101break;102}103}104else105{106/*107* No PJL stuff, just add the UEL...108*/109110fputs("\033%-12345X", stdout);111}112113/*114* Switch to TBCP mode...115*/116117fputs("\001M", stdout);118119/*120* Loop until we see end-of-file...121*/122123while (pswrite(line, linelen) > 0)124{125linelen = sizeof(line);126if (psgets(line, &linelen, fp) == NULL)127break;128}129130fflush(stdout);131}132133return (0);134}135136137/*138* 'psgets()' - Get a line from a file.139*140* Note:141*142* This function differs from the gets() function in that it143* handles any combination of CR, LF, or CR LF to end input144* lines.145*/146147static char * /* O - String or NULL if EOF */148psgets(char *buf, /* I - Buffer to read into */149size_t *bytes, /* IO - Length of buffer */150FILE *fp) /* I - File to read from */151{152char *bufptr; /* Pointer into buffer */153int ch; /* Character from file */154size_t len; /* Max length of string */155156157len = *bytes - 1;158bufptr = buf;159ch = EOF;160161while ((size_t)(bufptr - buf) < len)162{163if ((ch = getc(fp)) == EOF)164break;165166if (ch == '\r')167{168/*169* Got a CR; see if there is a LF as well...170*/171172ch = getc(fp);173174if (ch != EOF && ch != '\n')175{176ungetc(ch, fp); /* Nope, save it for later... */177ch = '\r';178}179else180*bufptr++ = '\r';181break;182}183else if (ch == '\n')184break;185else186*bufptr++ = (char)ch;187}188189/*190* Add a trailing newline if it is there...191*/192193if (ch == '\n' || ch == '\r')194{195if ((size_t)(bufptr - buf) < len)196*bufptr++ = (char)ch;197else198ungetc(ch, fp);199}200201/*202* Nul-terminate the string and return it (or NULL for EOF).203*/204205*bufptr = '\0';206*bytes = (size_t)(bufptr - buf);207208if (ch == EOF && bufptr == buf)209return (NULL);210else211return (buf);212}213214215/*216* 'pswrite()' - Write data from a file.217*/218219static ssize_t /* O - Number of bytes written */220pswrite(const char *buf, /* I - Buffer to write */221size_t bytes) /* I - Bytes to write */222{223size_t count; /* Remaining bytes */224225226for (count = bytes; count > 0; count --, buf ++)227switch (*buf)228{229case 0x04 : /* CTRL-D */230if (bytes == 1)231{232/*233* Don't quote the last CTRL-D...234*/235236putchar(0x04);237break;238}239240case 0x01 : /* CTRL-A */241case 0x03 : /* CTRL-C */242case 0x05 : /* CTRL-E */243case 0x11 : /* CTRL-Q */244case 0x13 : /* CTRL-S */245case 0x14 : /* CTRL-T */246case 0x1b : /* CTRL-[ (aka ESC) */247case 0x1c : /* CTRL-\ */248if (putchar(0x01) < 0)249return (-1);250if (putchar(*buf ^ 0x40) < 0)251return (-1);252break;253254default :255if (putchar(*buf) < 0)256return (-1);257break;258}259260return ((ssize_t)bytes);261}262263264