Load cups into easysw/current.
[thirdparty/cups.git] / berkeley / lpr.c
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  */