1/*
2 * "$Id: bcp.c 11560 2014-02-06 20:10:19Z msweet $"
3 *
4 * TBCP port monitor for CUPS.
5 *
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1993-2006 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file.  If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 */
17
18/*
19 * Include necessary headers...
20 */
21
22#include <cups/cups-private.h>
23#include <cups/ppd.h>
24
25
26/*
27 * Local functions...
28 */
29
30static char		*psgets(char *buf, size_t *bytes, FILE *fp);
31static ssize_t		pswrite(const char *buf, size_t bytes);
32
33
34/*
35 * 'main()' - Main entry...
36 */
37
38int					/* O - Exit status */
39main(int  argc,				/* I - Number of command-line args */
40     char *argv[])			/* I - Command-line arguments */
41{
42  FILE		*fp;			/* File to print */
43  int		copies;			/* Number of copies left */
44  char		line[1024];		/* Line/buffer from stream/file */
45  size_t	linelen;		/* Length of line */
46  ppd_file_t	*ppd;			/* PPD file */
47
48
49 /*
50  * Check command-line...
51  */
52
53  if (argc < 6 || argc > 7)
54  {
55    _cupsLangPrintf(stderr,
56                    _("Usage: %s job-id user title copies options [file]"),
57		    argv[0]);
58    return (1);
59  }
60
61  if (argc == 6)
62  {
63    copies = 1;
64    fp     = stdin;
65  }
66  else
67  {
68    copies = atoi(argv[4]);
69    fp     = fopen(argv[6], "rb");
70
71    if (!fp)
72    {
73      perror(argv[6]);
74      return (1);
75    }
76  }
77
78 /*
79  * Open the PPD file as needed...
80  */
81
82  ppd = ppdOpenFile(getenv("PPD"));
83
84 /*
85  * Copy the print file to stdout...
86  */
87
88  while (copies > 0)
89  {
90    copies --;
91
92    if (ppd && ppd->jcl_begin)
93      fputs(ppd->jcl_begin, stdout);
94    if (ppd && ppd->jcl_ps)
95      fputs(ppd->jcl_ps, stdout);
96
97    if (!ppd || ppd->language_level == 1)
98    {
99     /*
100      * Use setsoftwareiomode for BCP mode...
101      */
102
103      puts("%!PS-Adobe-3.0 ExitServer");
104      puts("%%Title: (BCP - Level 1)");
105      puts("%%EndComments");
106      puts("%%BeginExitServer: 0");
107      puts("serverdict begin 0 exitserver");
108      puts("%%EndExitServer");
109      puts("statusdict begin");
110      puts("/setsoftwareiomode known {100 setsoftwareiomode}");
111      puts("end");
112      puts("%EOF");
113    }
114    else
115    {
116     /*
117      * Use setdevparams for BCP mode...
118      */
119
120      puts("%!PS-Adobe-3.0");
121      puts("%%Title: (BCP - Level 2)");
122      puts("%%EndComments");
123      puts("currentsysparams");
124      puts("/CurInputDevice 2 copy known {");
125      puts("get");
126      puts("<</Protocol /Binary>> setdevparams");
127      puts("}{");
128      puts("pop pop");
129      puts("} ifelse");
130      puts("%EOF");
131    }
132
133    if (ppd && ppd->jcl_end)
134      fputs(ppd->jcl_end, stdout);
135    else if (!ppd || ppd->num_filters == 0)
136      putchar(0x04);
137
138   /*
139    * Loop until we see end-of-file...
140    */
141
142    do
143    {
144      linelen = sizeof(line);
145      if (psgets(line, &linelen, fp) == NULL)
146	break;
147    }
148    while (pswrite(line, linelen) > 0);
149
150    fflush(stdout);
151  }
152
153  return (0);
154}
155
156
157/*
158 * 'psgets()' - Get a line from a file.
159 *
160 * Note:
161 *
162 *   This function differs from the gets() function in that it
163 *   handles any combination of CR, LF, or CR LF to end input
164 *   lines.
165 */
166
167static char *				/* O  - String or NULL if EOF */
168psgets(char   *buf,			/* I  - Buffer to read into */
169       size_t *bytes,			/* IO - Length of buffer */
170       FILE   *fp)			/* I  - File to read from */
171{
172  char		*bufptr;		/* Pointer into buffer */
173  int		ch;			/* Character from file */
174  size_t	len;			/* Max length of string */
175
176
177  len    = *bytes - 1;
178  bufptr = buf;
179  ch     = EOF;
180
181  while ((size_t)(bufptr - buf) < len)
182  {
183    if ((ch = getc(fp)) == EOF)
184      break;
185
186    if (ch == '\r')
187    {
188     /*
189      * Got a CR; see if there is a LF as well...
190      */
191
192      ch = getc(fp);
193
194      if (ch != EOF && ch != '\n')
195      {
196        ungetc(ch, fp);	/* Nope, save it for later... */
197        ch = '\r';
198      }
199      else
200        *bufptr++ = '\r';
201      break;
202    }
203    else if (ch == '\n')
204      break;
205    else
206      *bufptr++ = (char)ch;
207  }
208
209 /*
210  * Add a trailing newline if it is there...
211  */
212
213  if (ch == '\n' || ch == '\r')
214  {
215    if ((size_t)(bufptr - buf) < len)
216      *bufptr++ = (char)ch;
217    else
218      ungetc(ch, fp);
219  }
220
221 /*
222  * Nul-terminate the string and return it (or NULL for EOF).
223  */
224
225  *bufptr = '\0';
226  *bytes  = (size_t)(bufptr - buf);
227
228  if (ch == EOF && bufptr == buf)
229    return (NULL);
230  else
231    return (buf);
232}
233
234
235/*
236 * 'pswrite()' - Write data from a file.
237 */
238
239static ssize_t				/* O - Number of bytes written */
240pswrite(const char *buf,		/* I - Buffer to write */
241        size_t     bytes)		/* I - Bytes to write */
242{
243  size_t	count;			/* Remaining bytes */
244
245
246  for (count = bytes; count > 0; count --, buf ++)
247    switch (*buf)
248    {
249      case 0x04 : /* CTRL-D */
250          if (bytes == 1)
251	  {
252	   /*
253	    * Don't quote the last CTRL-D...
254	    */
255
256	    putchar(0x04);
257	    break;
258	  }
259
260      case 0x01 : /* CTRL-A */
261      case 0x03 : /* CTRL-C */
262      case 0x05 : /* CTRL-E */
263      case 0x11 : /* CTRL-Q */
264      case 0x13 : /* CTRL-S */
265      case 0x14 : /* CTRL-T */
266      case 0x1c : /* CTRL-\ */
267	  if (putchar(0x01) < 0)
268	    return (-1);
269	  if (putchar(*buf ^ 0x40) < 0)
270	    return (-1);
271	  break;
272
273      default :
274	  if (putchar(*buf) < 0)
275	    return (-1);
276	  break;
277    }
278
279  return ((ssize_t)bytes);
280}
281
282
283/*
284 * End of "$Id: bcp.c 11560 2014-02-06 20:10:19Z msweet $".
285 */
286