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