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