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