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