]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
2 | * "$Id: lpr.c 4906 2006-01-10 20:53:28Z mike $" | |
3 | * | |
4 | * "lpr" command for the Common UNIX Printing System (CUPS). | |
5 | * | |
6 | * Copyright 1997-2006 by Easy Software Products. | |
7 | * | |
8 | * These coded instructions, statements, and computer programs are the | |
9 | * property of Easy Software Products and are protected by Federal | |
10 | * copyright law. Distribution and use rights are outlined in the file | |
11 | * "LICENSE.txt" which should have been included with this file. If this | |
12 | * file is missing or damaged please contact Easy Software Products | |
13 | * at: | |
14 | * | |
15 | * Attn: CUPS Licensing Information | |
16 | * Easy Software Products | |
17 | * 44141 Airport View Drive, Suite 204 | |
18 | * Hollywood, Maryland 20636 USA | |
19 | * | |
20 | * Voice: (301) 373-9600 | |
21 | * EMail: cups-info@cups.org | |
22 | * WWW: http://www.cups.org | |
23 | * | |
24 | * Contents: | |
25 | * | |
26 | * main() - Parse options and send files for printing. | |
27 | * sighandler() - Signal catcher for when we print from stdin... | |
28 | */ | |
29 | ||
30 | /* | |
31 | * Include necessary headers... | |
32 | */ | |
33 | ||
34 | #include <stdio.h> | |
35 | #include <stdlib.h> | |
36 | #include <errno.h> | |
37 | ||
38 | #include <cups/string.h> | |
39 | #include <cups/cups.h> | |
40 | #include <cups/i18n.h> | |
41 | ||
42 | #ifndef WIN32 | |
43 | # include <unistd.h> | |
44 | # include <signal.h> | |
45 | ||
46 | ||
47 | /* | |
48 | * Local functions. | |
49 | */ | |
50 | ||
51 | void sighandler(int); | |
52 | #endif /* !WIN32 */ | |
53 | ||
54 | ||
55 | /* | |
56 | * Globals... | |
57 | */ | |
58 | ||
59 | char tempfile[1024]; /* Temporary file for printing from stdin */ | |
60 | ||
61 | ||
62 | /* | |
63 | * 'main()' - Parse options and send files for printing. | |
64 | */ | |
65 | ||
66 | int | |
67 | main(int argc, /* I - Number of command-line arguments */ | |
68 | char *argv[]) /* I - Command-line arguments */ | |
69 | { | |
70 | int i, j; /* Looping var */ | |
71 | int job_id; /* Job ID */ | |
72 | char ch; /* Option character */ | |
73 | char *printer, /* Destination printer or class */ | |
74 | *instance; /* Instance */ | |
75 | const char *title, /* Job title */ | |
76 | *val; /* Environment variable name */ | |
77 | int num_copies; /* Number of copies per file */ | |
78 | int num_files; /* Number of files to print */ | |
79 | const char *files[1000]; /* Files to print */ | |
80 | int num_dests; /* Number of destinations */ | |
81 | cups_dest_t *dests, /* Destinations */ | |
82 | *dest; /* Selected destination */ | |
83 | int num_options; /* Number of options */ | |
84 | cups_option_t *options; /* Options */ | |
85 | int deletefile; /* Delete file after print? */ | |
86 | char buffer[8192]; /* Copy buffer */ | |
87 | int temp; /* Temporary file descriptor */ | |
88 | cups_lang_t *language; /* Language information */ | |
89 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) | |
90 | struct sigaction action; /* Signal action */ | |
91 | struct sigaction oldaction; /* Old signal action */ | |
92 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
93 | ||
94 | ||
95 | deletefile = 0; | |
96 | printer = NULL; | |
97 | num_dests = 0; | |
98 | dests = NULL; | |
99 | num_options = 0; | |
100 | options = NULL; | |
101 | num_files = 0; | |
102 | title = NULL; | |
103 | language = cupsLangDefault(); | |
104 | ||
105 | for (i = 1; i < argc; i ++) | |
106 | if (argv[i][0] == '-') | |
107 | switch (ch = argv[i][1]) | |
108 | { | |
109 | case 'E' : /* Encrypt */ | |
110 | #ifdef HAVE_SSL | |
111 | cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); | |
112 | #else | |
113 | _cupsLangPrintf(stderr, language, | |
114 | _("%s: Sorry, no encryption support compiled in!\n"), | |
115 | argv[0]); | |
116 | #endif /* HAVE_SSL */ | |
117 | break; | |
118 | ||
119 | case '1' : /* TROFF font set 1 */ | |
120 | case '2' : /* TROFF font set 2 */ | |
121 | case '3' : /* TROFF font set 3 */ | |
122 | case '4' : /* TROFF font set 4 */ | |
123 | case 'i' : /* indent */ | |
124 | case 'w' : /* width */ | |
125 | if (argv[i][2] == '\0') | |
126 | { | |
127 | i ++; | |
128 | ||
129 | if (i >= argc) | |
130 | { | |
131 | _cupsLangPrintf(stderr, language, | |
132 | _("lpr: error - expected value after -%c " | |
133 | "option!\n"), ch); | |
134 | return (1); | |
135 | } | |
136 | } | |
137 | ||
138 | case 'c' : /* CIFPLOT */ | |
139 | case 'd' : /* DVI */ | |
140 | case 'f' : /* FORTRAN */ | |
141 | case 'g' : /* plot */ | |
142 | case 'n' : /* Ditroff */ | |
143 | case 't' : /* Troff */ | |
144 | case 'v' : /* Raster image */ | |
145 | _cupsLangPrintf(stderr, language, | |
146 | _("lpr: warning - \'%c\' format modifier not " | |
147 | "supported - output may not be correct!\n"), ch); | |
148 | break; | |
149 | ||
150 | case 'o' : /* Option */ | |
151 | if (argv[i][2] != '\0') | |
152 | num_options = cupsParseOptions(argv[i] + 2, num_options, &options); | |
153 | else | |
154 | { | |
155 | i ++; | |
156 | if (i >= argc) | |
157 | { | |
158 | _cupsLangPuts(stderr, language, | |
159 | _("lpr: error - expected option=value after " | |
160 | "-o option!\n")); | |
161 | return (1); | |
162 | } | |
163 | ||
164 | num_options = cupsParseOptions(argv[i], num_options, &options); | |
165 | } | |
166 | break; | |
167 | ||
168 | case 'l' : /* Literal/raw */ | |
169 | num_options = cupsAddOption("raw", "", num_options, &options); | |
170 | break; | |
171 | ||
172 | case 'p' : /* Prettyprint */ | |
173 | num_options = cupsAddOption("prettyprint", "", num_options, &options); | |
174 | break; | |
175 | ||
176 | case 'h' : /* Suppress burst page */ | |
177 | num_options = cupsAddOption("job-sheets", "none", num_options, &options); | |
178 | break; | |
179 | ||
180 | case 's' : /* Don't use symlinks */ | |
181 | break; | |
182 | ||
183 | case 'm' : /* Mail on completion */ | |
184 | _cupsLangPuts(stderr, language, | |
185 | _("lpr: warning - email notification is not " | |
186 | "currently supported!\n")); | |
187 | break; | |
188 | ||
189 | case 'q' : /* Queue file but don't print */ | |
190 | num_options = cupsAddOption("job-hold-until", "indefinite", | |
191 | num_options, &options); | |
192 | break; | |
193 | ||
194 | case 'r' : /* Remove file after printing */ | |
195 | deletefile = 1; | |
196 | break; | |
197 | ||
198 | case 'P' : /* Destination printer or class */ | |
199 | if (argv[i][2] != '\0') | |
200 | printer = argv[i] + 2; | |
201 | else | |
202 | { | |
203 | i ++; | |
204 | if (i >= argc) | |
205 | { | |
206 | _cupsLangPuts(stderr, language, | |
207 | _("lpr: error - expected destination after -P " | |
208 | "option!\n")); | |
209 | return (1); | |
210 | } | |
211 | ||
212 | printer = argv[i]; | |
213 | } | |
214 | ||
215 | if ((instance = strrchr(printer, '/')) != NULL) | |
216 | *instance++ = '\0'; | |
217 | ||
218 | if (num_dests == 0) | |
219 | num_dests = cupsGetDests(&dests); | |
220 | ||
221 | if ((dest = cupsGetDest(printer, instance, num_dests, dests)) != NULL) | |
222 | { | |
223 | for (j = 0; j < dest->num_options; j ++) | |
224 | if (cupsGetOption(dest->options[j].name, num_options, options) == NULL) | |
225 | num_options = cupsAddOption(dest->options[j].name, | |
226 | dest->options[j].value, | |
227 | num_options, &options); | |
228 | } | |
229 | break; | |
230 | ||
231 | case '#' : /* Number of copies */ | |
232 | if (argv[i][2] != '\0') | |
233 | num_copies = atoi(argv[i] + 2); | |
234 | else | |
235 | { | |
236 | i ++; | |
237 | if (i >= argc) | |
238 | { | |
239 | _cupsLangPuts(stderr, language, | |
240 | _("lpr: error - expected copy count after -# " | |
241 | "option!\n")); | |
242 | return (1); | |
243 | } | |
244 | ||
245 | num_copies = atoi(argv[i]); | |
246 | } | |
247 | ||
248 | sprintf(buffer, "%d", num_copies); | |
249 | num_options = cupsAddOption("copies", buffer, num_options, &options); | |
250 | break; | |
251 | ||
252 | case 'C' : /* Class */ | |
253 | case 'J' : /* Job name */ | |
254 | case 'T' : /* Title */ | |
255 | if (argv[i][2] != '\0') | |
256 | title = argv[i] + 2; | |
257 | else | |
258 | { | |
259 | i ++; | |
260 | if (i >= argc) | |
261 | { | |
262 | _cupsLangPrintf(stderr, language, | |
263 | _("lpr: error - expected name after -%c " | |
264 | "option!\n"), ch); | |
265 | return (1); | |
266 | } | |
267 | ||
268 | title = argv[i]; | |
269 | } | |
270 | break; | |
271 | ||
272 | case 'U' : /* User */ | |
273 | if (argv[i][2] != '\0') | |
274 | cupsSetUser(argv[i] + 2); | |
275 | else | |
276 | { | |
277 | i ++; | |
278 | if (i >= argc) | |
279 | { | |
280 | _cupsLangPuts(stderr, language, | |
281 | _("lpr: error - expected username after -U " | |
282 | "option!\n")); | |
283 | return (1); | |
284 | } | |
285 | ||
286 | cupsSetUser(argv[i]); | |
287 | } | |
288 | break; | |
289 | ||
290 | default : | |
291 | _cupsLangPrintf(stderr, language, | |
292 | _("lpr: error - unknown option \'%c\'!\n"), | |
293 | argv[i][1]); | |
294 | return (1); | |
295 | } | |
296 | else if (num_files < 1000) | |
297 | { | |
298 | /* | |
299 | * Print a file... | |
300 | */ | |
301 | ||
302 | if (access(argv[i], R_OK) != 0) | |
303 | { | |
304 | _cupsLangPrintf(stderr, language, | |
305 | _("lpr: error - unable to access \"%s\" - %s\n"), | |
306 | argv[i], strerror(errno)); | |
307 | return (1); | |
308 | } | |
309 | ||
310 | files[num_files] = argv[i]; | |
311 | num_files ++; | |
312 | ||
313 | if (title == NULL) | |
314 | { | |
315 | if ((title = strrchr(argv[i], '/')) != NULL) | |
316 | title ++; | |
317 | else | |
318 | title = argv[i]; | |
319 | } | |
320 | } | |
321 | else | |
322 | _cupsLangPrintf(stderr, language, | |
323 | _("lpr: error - too many files - \"%s\"\n"), argv[i]); | |
324 | /* | |
325 | * See if we have any files to print; if not, print from stdin... | |
326 | */ | |
327 | ||
328 | if (printer == NULL) | |
329 | { | |
330 | if (num_dests == 0) | |
331 | num_dests = cupsGetDests(&dests); | |
332 | ||
333 | if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL) | |
334 | { | |
335 | printer = dest->name; | |
336 | ||
337 | for (j = 0; j < dest->num_options; j ++) | |
338 | if (cupsGetOption(dest->options[j].name, num_options, options) == NULL) | |
339 | num_options = cupsAddOption(dest->options[j].name, | |
340 | dest->options[j].value, | |
341 | num_options, &options); | |
342 | } | |
343 | } | |
344 | ||
345 | if (printer == NULL) | |
346 | { | |
347 | val = NULL; | |
348 | ||
349 | if ((printer = getenv("LPDEST")) == NULL) | |
350 | { | |
351 | if ((printer = getenv("PRINTER")) != NULL) | |
352 | { | |
353 | if (!strcmp(printer, "lp")) | |
354 | printer = NULL; | |
355 | else | |
356 | val = "PRINTER"; | |
357 | } | |
358 | } | |
359 | else | |
360 | val = "LPDEST"; | |
361 | ||
362 | if (printer && !cupsGetDest(printer, NULL, num_dests, dests)) | |
363 | _cupsLangPrintf(stderr, language, | |
364 | _("lpr: error - %s environment variable names " | |
365 | "non-existent destination \"%s\"!\n"), | |
366 | val, printer); | |
367 | else if (cupsLastError() == IPP_NOT_FOUND) | |
368 | _cupsLangPuts(stderr, language, | |
369 | _("lpr: error - no default destination available.\n")); | |
370 | else | |
371 | _cupsLangPuts(stderr, language, | |
372 | _("lpr: error - scheduler not responding!\n")); | |
373 | ||
374 | return (1); | |
375 | } | |
376 | ||
377 | if (num_files > 0) | |
378 | { | |
379 | job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options); | |
380 | ||
381 | if (deletefile && job_id > 0) | |
382 | { | |
383 | /* | |
384 | * Delete print files after printing... | |
385 | */ | |
386 | ||
387 | for (i = 0; i < num_files; i ++) | |
388 | unlink(files[i]); | |
389 | } | |
390 | } | |
391 | else | |
392 | { | |
393 | num_files = 1; | |
394 | ||
395 | #ifndef WIN32 | |
396 | # if defined(HAVE_SIGSET) | |
397 | sigset(SIGHUP, sighandler); | |
398 | if (sigset(SIGINT, sighandler) == SIG_IGN) | |
399 | sigset(SIGINT, SIG_IGN); | |
400 | sigset(SIGTERM, sighandler); | |
401 | # elif defined(HAVE_SIGACTION) | |
402 | memset(&action, 0, sizeof(action)); | |
403 | action.sa_handler = sighandler; | |
404 | ||
405 | sigaction(SIGHUP, &action, NULL); | |
406 | sigaction(SIGINT, NULL, &oldaction); | |
407 | if (oldaction.sa_handler != SIG_IGN) | |
408 | sigaction(SIGINT, &action, NULL); | |
409 | sigaction(SIGTERM, &action, NULL); | |
410 | # else | |
411 | signal(SIGHUP, sighandler); | |
412 | if (signal(SIGINT, sighandler) == SIG_IGN) | |
413 | signal(SIGINT, SIG_IGN); | |
414 | signal(SIGTERM, sighandler); | |
415 | # endif | |
416 | #endif /* !WIN32 */ | |
417 | ||
418 | if ((temp = cupsTempFd(tempfile, sizeof(tempfile))) < 0) | |
419 | { | |
420 | _cupsLangPrintf(stderr, language, | |
421 | _("lpr: error - unable to create temporary file " | |
422 | "\"%s\" - %s\n"), | |
423 | tempfile, strerror(errno)); | |
424 | return (1); | |
425 | } | |
426 | ||
427 | while ((i = read(0, buffer, sizeof(buffer))) > 0) | |
428 | if (write(temp, buffer, i) < 0) | |
429 | { | |
430 | _cupsLangPrintf(stderr, language, | |
431 | _("lpr: error - unable to write to temporary file " | |
432 | "\"%s\" - %s\n"), | |
433 | tempfile, strerror(errno)); | |
434 | close(temp); | |
435 | unlink(tempfile); | |
436 | return (1); | |
437 | } | |
438 | ||
439 | i = lseek(temp, 0, SEEK_CUR); | |
440 | close(temp); | |
441 | ||
442 | if (i == 0) | |
443 | { | |
444 | _cupsLangPuts(stderr, language, | |
445 | _("lpr: error - stdin is empty, so no job has been sent.\n")); | |
446 | unlink(tempfile); | |
447 | return (1); | |
448 | } | |
449 | ||
450 | if (title) | |
451 | job_id = cupsPrintFile(printer, tempfile, title, num_options, options); | |
452 | else | |
453 | job_id = cupsPrintFile(printer, tempfile, "(stdin)", num_options, options); | |
454 | ||
455 | unlink(tempfile); | |
456 | } | |
457 | ||
458 | if (job_id < 1) | |
459 | { | |
460 | _cupsLangPrintf(stderr, language, | |
461 | _("lpr: error - unable to print file: %s\n"), | |
462 | ippErrorString(cupsLastError())); | |
463 | return (1); | |
464 | } | |
465 | ||
466 | return (0); | |
467 | } | |
468 | ||
469 | ||
470 | #ifndef WIN32 | |
471 | /* | |
472 | * 'sighandler()' - Signal catcher for when we print from stdin... | |
473 | */ | |
474 | ||
475 | void | |
476 | sighandler(int s) /* I - Signal number */ | |
477 | { | |
478 | /* | |
479 | * Remove the temporary file we're using to print from stdin... | |
480 | */ | |
481 | ||
482 | unlink(tempfile); | |
483 | ||
484 | /* | |
485 | * Exit... | |
486 | */ | |
487 | ||
488 | exit(s); | |
489 | } | |
490 | #endif /* !WIN32 */ | |
491 | ||
492 | ||
493 | /* | |
494 | * End of "$Id: lpr.c 4906 2006-01-10 20:53:28Z mike $". | |
495 | */ |