/*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 */37ppd_file_t *ppd; /* PPD file */383940/*41* Check command-line...42*/4344if (argc < 6 || argc > 7)45{46_cupsLangPrintf(stderr,47_("Usage: %s job-id user title copies options [file]"),48argv[0]);49return (1);50}5152if (argc == 6)53{54copies = 1;55fp = stdin;56}57else58{59copies = atoi(argv[4]);60fp = fopen(argv[6], "rb");6162if (!fp)63{64perror(argv[6]);65return (1);66}67}6869/*70* Open the PPD file as needed...71*/7273ppd = ppdOpenFile(getenv("PPD"));7475/*76* Copy the print file to stdout...77*/7879while (copies > 0)80{81copies --;8283if (ppd && ppd->jcl_begin)84fputs(ppd->jcl_begin, stdout);85if (ppd && ppd->jcl_ps)86fputs(ppd->jcl_ps, stdout);8788if (!ppd || ppd->language_level == 1)89{90/*91* Use setsoftwareiomode for BCP mode...92*/9394puts("%!PS-Adobe-3.0 ExitServer");95puts("%%Title: (BCP - Level 1)");96puts("%%EndComments");97puts("%%BeginExitServer: 0");98puts("serverdict begin 0 exitserver");99puts("%%EndExitServer");100puts("statusdict begin");101puts("/setsoftwareiomode known {100 setsoftwareiomode}");102puts("end");103puts("%EOF");104}105else106{107/*108* Use setdevparams for BCP mode...109*/110111puts("%!PS-Adobe-3.0");112puts("%%Title: (BCP - Level 2)");113puts("%%EndComments");114puts("currentsysparams");115puts("/CurInputDevice 2 copy known {");116puts("get");117puts("<</Protocol /Binary>> setdevparams");118puts("}{");119puts("pop pop");120puts("} ifelse");121puts("%EOF");122}123124if (ppd && ppd->jcl_end)125fputs(ppd->jcl_end, stdout);126else if (!ppd || ppd->num_filters == 0)127putchar(0x04);128129/*130* Loop until we see end-of-file...131*/132133do134{135linelen = sizeof(line);136if (psgets(line, &linelen, fp) == NULL)137break;138}139while (pswrite(line, linelen) > 0);140141fflush(stdout);142}143144return (0);145}146147148/*149* 'psgets()' - Get a line from a file.150*151* Note:152*153* This function differs from the gets() function in that it154* handles any combination of CR, LF, or CR LF to end input155* lines.156*/157158static char * /* O - String or NULL if EOF */159psgets(char *buf, /* I - Buffer to read into */160size_t *bytes, /* IO - Length of buffer */161FILE *fp) /* I - File to read from */162{163char *bufptr; /* Pointer into buffer */164int ch; /* Character from file */165size_t len; /* Max length of string */166167168len = *bytes - 1;169bufptr = buf;170ch = EOF;171172while ((size_t)(bufptr - buf) < len)173{174if ((ch = getc(fp)) == EOF)175break;176177if (ch == '\r')178{179/*180* Got a CR; see if there is a LF as well...181*/182183ch = getc(fp);184185if (ch != EOF && ch != '\n')186{187ungetc(ch, fp); /* Nope, save it for later... */188ch = '\r';189}190else191*bufptr++ = '\r';192break;193}194else if (ch == '\n')195break;196else197*bufptr++ = (char)ch;198}199200/*201* Add a trailing newline if it is there...202*/203204if (ch == '\n' || ch == '\r')205{206if ((size_t)(bufptr - buf) < len)207*bufptr++ = (char)ch;208else209ungetc(ch, fp);210}211212/*213* Nul-terminate the string and return it (or NULL for EOF).214*/215216*bufptr = '\0';217*bytes = (size_t)(bufptr - buf);218219if (ch == EOF && bufptr == buf)220return (NULL);221else222return (buf);223}224225226/*227* 'pswrite()' - Write data from a file.228*/229230static ssize_t /* O - Number of bytes written */231pswrite(const char *buf, /* I - Buffer to write */232size_t bytes) /* I - Bytes to write */233{234size_t count; /* Remaining bytes */235236237for (count = bytes; count > 0; count --, buf ++)238switch (*buf)239{240case 0x04 : /* CTRL-D */241if (bytes == 1)242{243/*244* Don't quote the last CTRL-D...245*/246247putchar(0x04);248break;249}250251case 0x01 : /* CTRL-A */252case 0x03 : /* CTRL-C */253case 0x05 : /* CTRL-E */254case 0x11 : /* CTRL-Q */255case 0x13 : /* CTRL-S */256case 0x14 : /* CTRL-T */257case 0x1c : /* CTRL-\ */258if (putchar(0x01) < 0)259return (-1);260if (putchar(*buf ^ 0x40) < 0)261return (-1);262break;263264default :265if (putchar(*buf) < 0)266return (-1);267break;268}269270return ((ssize_t)bytes);271}272273274