1/*
2 * "$Id: tbcp.c 11093 2013-07-03 20:48:42Z msweet $"
3 *
4 *   TBCP port monitor for CUPS.
5 *
6 *   Copyright 2007-2012 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 * Contents:
18 *
19 *   main()    - Main entry...
20 *   psgets()  - Get a line from a file.
21 *   pswrite() - Write data from a file.
22 */
23
24/*
25 * Include necessary headers...
26 */
27
28#include <cups/cups-private.h>
29#include <cups/ppd.h>
30
31
32/*
33 * Local functions...
34 */
35
36static char		*psgets(char *buf, size_t *bytes, FILE *fp);
37static size_t		pswrite(const char *buf, size_t bytes, FILE *fp);
38
39
40/*
41 * 'main()' - Main entry...
42 */
43
44int					/* O - Exit status */
45main(int  argc,				/* I - Number of command-line args */
46     char *argv[])			/* I - Command-line arguments */
47{
48  FILE		*fp;			/* File to print */
49  int		copies;			/* Number of copies left */
50  char		line[1024];		/* Line/buffer from stream/file */
51  size_t	linelen;		/* Length of line */
52
53
54 /*
55  * Check command-line...
56  */
57
58  if (argc < 6 || argc > 7)
59  {
60    _cupsLangPrintf(stderr,
61                    _("Usage: %s job-id user title copies options [file]"),
62		    argv[0]);
63    return (1);
64  }
65
66  if (argc == 6)
67  {
68    copies = 1;
69    fp     = stdin;
70  }
71  else
72  {
73    copies = atoi(argv[4]);
74    fp     = fopen(argv[6], "rb");
75
76    if (!fp)
77    {
78      perror(argv[6]);
79      return (1);
80    }
81  }
82
83 /*
84  * Copy the print file to stdout...
85  */
86
87  while (copies > 0)
88  {
89    copies --;
90
91   /*
92    * Read the first line...
93    */
94
95    linelen = sizeof(line);
96    if (!psgets(line, &linelen, fp))
97      break;
98
99   /*
100    * Handle leading PJL fun...
101    */
102
103    if (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5))
104    {
105     /*
106      * Yup, we have leading PJL fun, so copy it until we hit a line
107      * with "ENTER LANGUAGE"...
108      */
109
110      while (strstr(line, "ENTER LANGUAGE") == NULL)
111      {
112        fwrite(line, 1, linelen, stdout);
113
114	linelen = sizeof(line);
115	if (psgets(line, &linelen, fp) == NULL)
116          break;
117      }
118    }
119    else
120    {
121     /*
122      * No PJL stuff, just add the UEL...
123      */
124
125      fputs("\033%-12345X", stdout);
126    }
127
128   /*
129    * Switch to TBCP mode...
130    */
131
132    fputs("\001M", stdout);
133
134   /*
135    * Loop until we see end-of-file...
136    */
137
138    while (pswrite(line, linelen, stdout) > 0)
139    {
140      linelen = sizeof(line);
141      if (psgets(line, &linelen, fp) == NULL)
142	break;
143    }
144
145    fflush(stdout);
146  }
147
148  return (0);
149}
150
151
152/*
153 * 'psgets()' - Get a line from a file.
154 *
155 * Note:
156 *
157 *   This function differs from the gets() function in that it
158 *   handles any combination of CR, LF, or CR LF to end input
159 *   lines.
160 */
161
162static char *				/* O  - String or NULL if EOF */
163psgets(char   *buf,			/* I  - Buffer to read into */
164       size_t *bytes,			/* IO - Length of buffer */
165       FILE   *fp)			/* I  - File to read from */
166{
167  char		*bufptr;		/* Pointer into buffer */
168  int		ch;			/* Character from file */
169  size_t	len;			/* Max length of string */
170
171
172  len    = *bytes - 1;
173  bufptr = buf;
174  ch     = EOF;
175
176  while ((bufptr - buf) < len)
177  {
178    if ((ch = getc(fp)) == EOF)
179      break;
180
181    if (ch == '\r')
182    {
183     /*
184      * Got a CR; see if there is a LF as well...
185      */
186
187      ch = getc(fp);
188
189      if (ch != EOF && ch != '\n')
190      {
191        ungetc(ch, fp);	/* Nope, save it for later... */
192        ch = '\r';
193      }
194      else
195        *bufptr++ = '\r';
196      break;
197    }
198    else if (ch == '\n')
199      break;
200    else
201      *bufptr++ = ch;
202  }
203
204 /*
205  * Add a trailing newline if it is there...
206  */
207
208  if (ch == '\n' || ch == '\r')
209  {
210    if ((bufptr - buf) < len)
211      *bufptr++ = ch;
212    else
213      ungetc(ch, fp);
214  }
215
216 /*
217  * Nul-terminate the string and return it (or NULL for EOF).
218  */
219
220  *bufptr = '\0';
221  *bytes  = bufptr - buf;
222
223  if (ch == EOF && bufptr == buf)
224    return (NULL);
225  else
226    return (buf);
227}
228
229
230/*
231 * 'pswrite()' - Write data from a file.
232 */
233
234static size_t				/* O - Number of bytes written */
235pswrite(const char *buf,		/* I - Buffer to write */
236        size_t     bytes,		/* I - Bytes to write */
237	FILE       *fp)			/* I - File to write to */
238{
239  size_t	count;			/* Remaining bytes */
240
241
242  for (count = bytes; count > 0; count --, buf ++)
243    switch (*buf)
244    {
245      case 0x04 : /* CTRL-D */
246          if (bytes == 1)
247	  {
248	   /*
249	    * Don't quote the last CTRL-D...
250	    */
251
252	    putchar(0x04);
253	    break;
254	  }
255
256      case 0x01 : /* CTRL-A */
257      case 0x03 : /* CTRL-C */
258      case 0x05 : /* CTRL-E */
259      case 0x11 : /* CTRL-Q */
260      case 0x13 : /* CTRL-S */
261      case 0x14 : /* CTRL-T */
262      case 0x1b : /* CTRL-[ (aka ESC) */
263      case 0x1c : /* CTRL-\ */
264	  if (putchar(0x01) < 0)
265	    return (-1);
266	  if (putchar(*buf ^ 0x40) < 0)
267	    return (-1);
268	  break;
269
270      default :
271	  if (putchar(*buf) < 0)
272	    return (-1);
273	  break;
274    }
275
276  return (bytes);
277}
278
279
280/*
281 * End of "$Id: tbcp.c 11093 2013-07-03 20:48:42Z msweet $".
282 */
283