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 ppd_file_t *ppd; /* PPD file */
40
41
42 /*
43 * Check command-line...
44 */
45
46 if (argc != 6 && argc != 7)
47 {
48 _cupsLangPrintf(stderr,
49 _("Usage: %s job-id user title copies options [file]"),
50 argv[0]);
51 return (1);
52 }
53
54 if (argc == 6)
55 {
56 copies = 1;
57 fp = stdin;
58 }
59 else
60 {
61 copies = atoi(argv[4]);
62 fp = fopen(argv[6], "rb");
63
64 if (!fp)
65 {
66 perror(argv[6]);
67 return (1);
68 }
69 }
70
71 /*
72 * Open the PPD file as needed...
73 */
74
75 ppd = ppdOpenFile(getenv("PPD"));
76
77 /*
78 * Copy the print file to stdout...
79 */
80
81 while (copies > 0)
82 {
83 copies --;
84
85 if (ppd && ppd->jcl_begin)
86 fputs(ppd->jcl_begin, stdout);
87 if (ppd && ppd->jcl_ps)
88 fputs(ppd->jcl_ps, stdout);
89
90 if (!ppd || ppd->language_level == 1)
91 {
92 /*
93 * Use setsoftwareiomode for BCP mode...
94 */
95
96 puts("%!PS-Adobe-3.0 ExitServer");
97 puts("%%Title: (BCP - Level 1)");
98 puts("%%EndComments");
99 puts("%%BeginExitServer: 0");
100 puts("serverdict begin 0 exitserver");
101 puts("%%EndExitServer");
102 puts("statusdict begin");
103 puts("/setsoftwareiomode known {100 setsoftwareiomode}");
104 puts("end");
105 puts("%EOF");
106 }
107 else
108 {
109 /*
110 * Use setdevparams for BCP mode...
111 */
112
113 puts("%!PS-Adobe-3.0");
114 puts("%%Title: (BCP - Level 2)");
115 puts("%%EndComments");
116 puts("currentsysparams");
117 puts("/CurInputDevice 2 copy known {");
118 puts("get");
119 puts("<</Protocol /Binary>> setdevparams");
120 puts("}{");
121 puts("pop pop");
122 puts("} ifelse");
123 puts("%EOF");
124 }
125
126 if (ppd && ppd->jcl_end)
127 fputs(ppd->jcl_end, stdout);
128 else if (!ppd || ppd->num_filters == 0)
129 putchar(0x04);
130
131 /*
132 * Loop until we see end-of-file...
133 */
134
135 do
136 {
137 linelen = sizeof(line);
138 if (psgets(line, &linelen, fp) == NULL)
139 break;
140 }
141 while (pswrite(line, linelen) > 0);
142
143 fflush(stdout);
144 }
145
146 return (0);
147 }
148
149
150 /*
151 * 'psgets()' - Get a line from a file.
152 *
153 * Note:
154 *
155 * This function differs from the gets() function in that it
156 * handles any combination of CR, LF, or CR LF to end input
157 * lines.
158 */
159
160 static char * /* O - String or NULL if EOF */
psgets(char * buf,size_t * bytes,FILE * fp)161 psgets(char *buf, /* I - Buffer to read into */
162 size_t *bytes, /* IO - Length of buffer */
163 FILE *fp) /* I - File to read from */
164 {
165 char *bufptr; /* Pointer into buffer */
166 int ch; /* Character from file */
167 size_t len; /* Max length of string */
168
169
170 len = *bytes - 1;
171 bufptr = buf;
172 ch = EOF;
173
174 while ((size_t)(bufptr - buf) < len)
175 {
176 if ((ch = getc(fp)) == EOF)
177 break;
178
179 if (ch == '\r')
180 {
181 /*
182 * Got a CR; see if there is a LF as well...
183 */
184
185 ch = getc(fp);
186
187 if (ch != EOF && ch != '\n')
188 {
189 ungetc(ch, fp); /* Nope, save it for later... */
190 ch = '\r';
191 }
192 else
193 *bufptr++ = '\r';
194 break;
195 }
196 else if (ch == '\n')
197 break;
198 else
199 *bufptr++ = (char)ch;
200 }
201
202 /*
203 * Add a trailing newline if it is there...
204 */
205
206 if (ch == '\n' || ch == '\r')
207 {
208 if ((size_t)(bufptr - buf) < len)
209 *bufptr++ = (char)ch;
210 else
211 ungetc(ch, fp);
212 }
213
214 /*
215 * Nul-terminate the string and return it (or NULL for EOF).
216 */
217
218 *bufptr = '\0';
219 *bytes = (size_t)(bufptr - buf);
220
221 if (ch == EOF && bufptr == buf)
222 return (NULL);
223 else
224 return (buf);
225 }
226
227
228 /*
229 * 'pswrite()' - Write data from a file.
230 */
231
232 static ssize_t /* O - Number of bytes written */
pswrite(const char * buf,size_t bytes)233 pswrite(const char *buf, /* I - Buffer to write */
234 size_t bytes) /* I - Bytes to write */
235 {
236 size_t count; /* Remaining bytes */
237
238
239 for (count = bytes; count > 0; count --, buf ++)
240 switch (*buf)
241 {
242 case 0x04 : /* CTRL-D */
243 if (bytes == 1)
244 {
245 /*
246 * Don't quote the last CTRL-D...
247 */
248
249 putchar(0x04);
250 break;
251 }
252
253 case 0x01 : /* CTRL-A */
254 case 0x03 : /* CTRL-C */
255 case 0x05 : /* CTRL-E */
256 case 0x11 : /* CTRL-Q */
257 case 0x13 : /* CTRL-S */
258 case 0x14 : /* CTRL-T */
259 case 0x1c : /* CTRL-\ */
260 if (putchar(0x01) < 0)
261 return (-1);
262 if (putchar(*buf ^ 0x40) < 0)
263 return (-1);
264 break;
265
266 default :
267 if (putchar(*buf) < 0)
268 return (-1);
269 break;
270 }
271
272 return ((ssize_t)bytes);
273 }
274