]> git.ipfire.org Git - thirdparty/cups.git/blame - berkeley/lpr.c
Merge pull request #5621 from zdohnal/cgigetarray-sigsegv
[thirdparty/cups.git] / berkeley / lpr.c
CommitLineData
ef416fc2 1/*
7e86f2f6 2 * "lpr" command for CUPS.
ef416fc2 3 *
13e6d13e 4 * Copyright © 2007-2019 by Apple Inc.
860f3d3b 5 * Copyright © 1997-2007 by Easy Software Products.
ef416fc2 6 *
860f3d3b
MS
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
ef416fc2 9 */
10
11/*
12 * Include necessary headers...
13 */
14
71e16022 15#include <cups/cups-private.h>
ef416fc2 16
ef416fc2 17
860f3d3b
MS
18/*
19 * Local functions...
20 */
21
22static void usage(void) _CUPS_NORETURN;
23
24
ef416fc2 25/*
26 * 'main()' - Parse options and send files for printing.
27 */
28
29int
fa73b229 30main(int argc, /* I - Number of command-line arguments */
31 char *argv[]) /* I - Command-line arguments */
ef416fc2 32{
fa73b229 33 int i, j; /* Looping var */
34 int job_id; /* Job ID */
35 char ch; /* Option character */
36 char *printer, /* Destination printer or class */
bdbfacc7
MS
37 *instance, /* Instance */
38 *opt; /* Option pointer */
d6db9ea1 39 const char *title; /* Job title */
fa73b229 40 int num_copies; /* Number of copies per file */
41 int num_files; /* Number of files to print */
42 const char *files[1000]; /* Files to print */
a4924f6c 43 cups_dest_t *dest; /* Selected destination */
fa73b229 44 int num_options; /* Number of options */
45 cups_option_t *options; /* Options */
46 int deletefile; /* Delete file after print? */
47 char buffer[8192]; /* Copy buffer */
ef416fc2 48
49
07725fee 50 _cupsSetLocale(argv);
d09495fa 51
ef416fc2 52 deletefile = 0;
53 printer = NULL;
a4924f6c 54 dest = NULL;
ef416fc2 55 num_options = 0;
56 options = NULL;
57 num_files = 0;
58 title = NULL;
ef416fc2 59
60 for (i = 1; i < argc; i ++)
bdbfacc7 61 {
860f3d3b
MS
62 if (!strcmp(argv[i], "--help"))
63 usage();
64 else if (argv[i][0] == '-')
c606bcae 65 {
bdbfacc7 66 for (opt = argv[i] + 1; *opt; opt ++)
ef416fc2 67 {
bdbfacc7
MS
68 switch (ch = *opt)
69 {
70 case 'E' : /* Encrypt */
ef416fc2 71#ifdef HAVE_SSL
bdbfacc7 72 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
ef416fc2 73#else
bdbfacc7 74 _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
ef416fc2 75#endif /* HAVE_SSL */
bdbfacc7
MS
76 break;
77
78 case 'U' : /* Username */
79 if (opt[1] != '\0')
fa73b229 80 {
bdbfacc7
MS
81 cupsSetUser(opt + 1);
82 opt += strlen(opt) - 1;
fa73b229 83 }
bdbfacc7
MS
84 else
85 {
86 i ++;
87 if (i >= argc)
88 {
89 _cupsLangPrintf(stderr, _("%s: Error - expected username after \"-U\" option."), argv[0]);
860f3d3b 90 usage();
bdbfacc7
MS
91 }
92
93 cupsSetUser(argv[i]);
94 }
95 break;
fa73b229 96
bdbfacc7
MS
97 case 'H' : /* Connect to host */
98 if (opt[1] != '\0')
99 {
100 cupsSetServer(opt + 1);
101 opt += strlen(opt) - 1;
102 }
103 else
104 {
105 i ++;
106
107 if (i >= argc)
108 {
109 _cupsLangPrintf(stderr, _("%s: Error - expected hostname after \"-H\" option."), argv[0]);
860f3d3b 110 usage();
bdbfacc7
MS
111 }
112 else
113 cupsSetServer(argv[i]);
114 }
115 break;
116
117 case '1' : /* TROFF font set 1 */
118 case '2' : /* TROFF font set 2 */
119 case '3' : /* TROFF font set 3 */
120 case '4' : /* TROFF font set 4 */
121 case 'i' : /* indent */
122 case 'w' : /* width */
123 if (opt[1] != '\0')
124 {
125 opt += strlen(opt) - 1;
126 }
127 else
128 {
129 i ++;
130
131 if (i >= argc)
132 {
133 _cupsLangPrintf(stderr,
134 _("%s: Error - expected value after \"-%c\" "
135 "option."), argv[0], ch);
860f3d3b 136 usage();
bdbfacc7
MS
137 }
138 }
fa73b229 139
bdbfacc7
MS
140 case 'c' : /* CIFPLOT */
141 case 'd' : /* DVI */
142 case 'f' : /* FORTRAN */
143 case 'g' : /* plot */
144 case 'n' : /* Ditroff */
145 case 't' : /* Troff */
146 case 'v' : /* Raster image */
147 _cupsLangPrintf(stderr, _("%s: Warning - \"%c\" format modifier not supported - output may not be correct."), argv[0], ch);
148 break;
149
150 case 'o' : /* Option */
151 if (opt[1] != '\0')
fa73b229 152 {
bdbfacc7
MS
153 num_options = cupsParseOptions(opt + 1, num_options, &options);
154 opt += strlen(opt) - 1;
155 }
fa73b229 156 else
ef416fc2 157 {
bdbfacc7
MS
158 i ++;
159 if (i >= argc)
160 {
161 _cupsLangPrintf(stderr, _("%s: Error - expected option=value after \"-o\" option."), argv[0]);
860f3d3b 162 usage();
bdbfacc7
MS
163 }
164
165 num_options = cupsParseOptions(argv[i], num_options, &options);
ef416fc2 166 }
bdbfacc7
MS
167 break;
168
169 case 'l' : /* Literal/raw */
170 num_options = cupsAddOption("raw", "true", num_options, &options);
171 break;
172
173 case 'p' : /* Prettyprint */
174 num_options = cupsAddOption("prettyprint", "true", num_options, &options);
175 break;
176
177 case 'h' : /* Suppress burst page */
178 num_options = cupsAddOption("job-sheets", "none", num_options, &options);
179 break;
180
181 case 's' : /* Don't use symlinks */
182 break;
183
184 case 'm' : /* Mail on completion */
ef416fc2 185 {
bdbfacc7
MS
186 char email[1024]; /* EMail address */
187
188 snprintf(email, sizeof(email), "mailto:%s@%s", cupsUser(), httpGetHostname(NULL, buffer, sizeof(buffer)));
189 num_options = cupsAddOption("notify-recipient-uri", email, num_options, &options);
ef416fc2 190 }
bdbfacc7 191 break;
ef416fc2 192
bdbfacc7
MS
193 case 'q' : /* Queue file but don't print */
194 num_options = cupsAddOption("job-hold-until", "indefinite", num_options, &options);
195 break;
196
197 case 'r' : /* Remove file after printing */
198 deletefile = 1;
199 break;
200
201 case 'P' : /* Destination printer or class */
202 if (opt[1] != '\0')
ef416fc2 203 {
bdbfacc7
MS
204 printer = opt + 1;
205 opt += strlen(opt) - 1;
206 }
207 else
208 {
209 i ++;
210 if (i >= argc)
211 {
212 _cupsLangPrintf(stderr, _("%s: Error - expected destination after \"-P\" option."), argv[0]);
860f3d3b 213 usage();
bdbfacc7
MS
214 }
215
216 printer = argv[i];
ef416fc2 217 }
218
bdbfacc7
MS
219 if ((instance = strrchr(printer, '/')) != NULL)
220 *instance++ = '\0';
221
222 if ((dest = cupsGetNamedDest(NULL, printer, instance)) != NULL)
223 {
224 for (j = 0; j < dest->num_options; j ++)
225 if (cupsGetOption(dest->options[j].name, num_options,
226 options) == NULL)
227 num_options = cupsAddOption(dest->options[j].name,
228 dest->options[j].value,
229 num_options, &options);
230 }
231 else if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
232 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
ef416fc2 233 {
bdbfacc7 234 _cupsLangPrintf(stderr, _("%s: Error - add '/version=1.1' to server name."), argv[0]);
ef416fc2 235 return (1);
236 }
bdbfacc7
MS
237 break;
238
239 case '#' : /* Number of copies */
240 if (opt[1] != '\0')
241 {
242 num_copies = atoi(opt + 1);
243 opt += strlen(opt) - 1;
244 }
245 else
246 {
247 i ++;
248 if (i >= argc)
249 {
250 _cupsLangPrintf(stderr, _("%s: Error - expected copies after \"-#\" option."), argv[0]);
860f3d3b 251 usage();
bdbfacc7
MS
252 }
253
254 num_copies = atoi(argv[i]);
255 }
ef416fc2 256
bdbfacc7 257 if (num_copies < 1)
ef416fc2 258 {
bdbfacc7 259 _cupsLangPrintf(stderr, _("%s: Error - copies must be 1 or more."), argv[0]);
ef416fc2 260 return (1);
261 }
262
bdbfacc7
MS
263 sprintf(buffer, "%d", num_copies);
264 num_options = cupsAddOption("copies", buffer, num_options, &options);
265 break;
ef416fc2 266
bdbfacc7
MS
267 case 'C' : /* Class */
268 case 'J' : /* Job name */
269 case 'T' : /* Title */
270 if (opt[1] != '\0')
271 {
272 title = opt + 1;
273 opt += strlen(opt) - 1;
274 }
275 else
276 {
277 i ++;
278 if (i >= argc)
279 {
280 _cupsLangPrintf(stderr, _("%s: Error - expected name after \"-%c\" option."), argv[0], ch);
860f3d3b 281 usage();
bdbfacc7
MS
282 }
283
284 title = argv[i];
285 }
286 break;
287
288 default :
289 _cupsLangPrintf(stderr, _("%s: Error - unknown option \"%c\"."), argv[0], *opt);
290 return (1);
291 }
ef416fc2 292 }
c606bcae 293 }
ef416fc2 294 else if (num_files < 1000)
295 {
296 /*
297 * Print a file...
298 */
299
300 if (access(argv[i], R_OK) != 0)
301 {
fa73b229 302 _cupsLangPrintf(stderr,
84315f46 303 _("%s: Error - unable to access \"%s\" - %s"),
fa73b229 304 argv[0], argv[i], strerror(errno));
ef416fc2 305 return (1);
306 }
307
308 files[num_files] = argv[i];
309 num_files ++;
310
311 if (title == NULL)
312 {
313 if ((title = strrchr(argv[i], '/')) != NULL)
314 title ++;
315 else
316 title = argv[i];
317 }
318 }
319 else
bdbfacc7
MS
320 {
321 _cupsLangPrintf(stderr, _("%s: Error - too many files - \"%s\"."), argv[0], argv[i]);
322 }
323 }
324
ef416fc2 325 /*
326 * See if we have any files to print; if not, print from stdin...
327 */
328
329 if (printer == NULL)
330 {
a4924f6c 331 if ((dest = cupsGetNamedDest(NULL, NULL, NULL)) != NULL)
ef416fc2 332 {
333 printer = dest->name;
334
335 for (j = 0; j < dest->num_options; j ++)
336 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
337 num_options = cupsAddOption(dest->options[j].name,
338 dest->options[j].value,
339 num_options, &options);
340 }
c606bcae
MS
341 else if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
342 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
343 {
344 _cupsLangPrintf(stderr,
345 _("%s: Error - add '/version=1.1' to server "
346 "name."), argv[0]);
347 return (1);
348 }
ef416fc2 349 }
350
351 if (printer == NULL)
352 {
d6db9ea1
MS
353 if (!cupsGetNamedDest(NULL, NULL, NULL) && cupsLastError() == IPP_STATUS_ERROR_NOT_FOUND)
354 _cupsLangPrintf(stderr, _("%s: Error - %s"), argv[0], cupsLastErrorString());
ef416fc2 355 else
d6db9ea1 356 _cupsLangPrintf(stderr, _("%s: Error - scheduler not responding."), argv[0]);
ef416fc2 357
358 return (1);
359 }
360
361 if (num_files > 0)
362 {
363 job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
364
365 if (deletefile && job_id > 0)
366 {
367 /*
368 * Delete print files after printing...
369 */
370
371 for (i = 0; i < num_files; i ++)
372 unlink(files[i]);
373 }
374 }
3d052e43
MS
375 else if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, printer,
376 title ? title : "(stdin)",
377 num_options, options)) > 0)
ef416fc2 378 {
3d052e43
MS
379 http_status_t status; /* Write status */
380 const char *format; /* Document format */
381 ssize_t bytes; /* Bytes read */
ef416fc2 382
3d052e43
MS
383 if (cupsGetOption("raw", num_options, options))
384 format = CUPS_FORMAT_RAW;
385 else if ((format = cupsGetOption("document-format", num_options,
386 options)) == NULL)
387 format = CUPS_FORMAT_AUTO;
388
389 status = cupsStartDocument(CUPS_HTTP_DEFAULT, printer, job_id, NULL,
390 format, 1);
ef416fc2 391
3d052e43
MS
392 while (status == HTTP_CONTINUE &&
393 (bytes = read(0, buffer, sizeof(buffer))) > 0)
7e86f2f6 394 status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, (size_t)bytes);
3d052e43
MS
395
396 if (status != HTTP_CONTINUE)
ef416fc2 397 {
0837b7e8 398 _cupsLangPrintf(stderr, _("%s: Error - unable to queue from stdin - %s."),
3d052e43 399 argv[0], httpStatus(status));
12f89d24
MS
400 cupsFinishDocument(CUPS_HTTP_DEFAULT, printer);
401 cupsCancelJob2(CUPS_HTTP_DEFAULT, printer, job_id, 0);
ef416fc2 402 return (1);
403 }
404
3d052e43 405 if (cupsFinishDocument(CUPS_HTTP_DEFAULT, printer) != IPP_OK)
12f89d24 406 {
a29fd7dd 407 _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
12f89d24 408 cupsCancelJob2(CUPS_HTTP_DEFAULT, printer, job_id, 0);
a29fd7dd 409 return (1);
12f89d24 410 }
ef416fc2 411 }
412
413 if (job_id < 1)
414 {
0837b7e8 415 _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
ef416fc2 416 return (1);
417 }
418
419 return (0);
420}
860f3d3b
MS
421
422
423/*
424 * 'usage()' - Show program usage and exit.
425 */
426
427static void
428usage(void)
429{
430 _cupsLangPuts(stdout, _("Usage: lpr [options] [file(s)]"));
431 _cupsLangPuts(stdout, _("Options:"));
432 _cupsLangPuts(stdout, _("-# num-copies Specify the number of copies to print"));
433 _cupsLangPuts(stdout, _("-E Encrypt the connection to the server"));
434 _cupsLangPuts(stdout, _("-H server[:port] Connect to the named server and port"));
435 _cupsLangPuts(stdout, _("-m Send an email notification when the job completes"));
436 _cupsLangPuts(stdout, _("-o option[=value] Specify a printer-specific option"));
437 _cupsLangPuts(stdout, _("-o job-sheets=standard Print a banner page with the job"));
438 _cupsLangPuts(stdout, _("-o media=size Specify the media size to use"));
439 _cupsLangPuts(stdout, _("-o number-up=N Specify that input pages should be printed N-up (1, 2, 4, 6, 9, and 16 are supported)"));
440 _cupsLangPuts(stdout, _("-o orientation-requested=N\n"
441 " Specify portrait (3) or landscape (4) orientation"));
442 _cupsLangPuts(stdout, _("-o print-quality=N Specify the print quality - draft (3), normal (4), or best (5)"));
443 _cupsLangPuts(stdout, _("-o sides=one-sided Specify 1-sided printing"));
444 _cupsLangPuts(stdout, _("-o sides=two-sided-long-edge\n"
445 " Specify 2-sided portrait printing"));
446 _cupsLangPuts(stdout, _("-o sides=two-sided-short-edge\n"
447 " Specify 2-sided landscape printing"));
13e6d13e 448 _cupsLangPuts(stdout, _("-P destination Specify the destination"));
860f3d3b
MS
449 _cupsLangPuts(stdout, _("-q Specify the job should be held for printing"));
450 _cupsLangPuts(stdout, _("-r Remove the file(s) after submission"));
860f3d3b
MS
451 _cupsLangPuts(stdout, _("-T title Specify the job title"));
452 _cupsLangPuts(stdout, _("-U username Specify the username to use for authentication"));
453
454 exit(1);
455}