1/*
2 * "$Id: lpr.c 11560 2014-02-06 20:10:19Z msweet $"
3 *
4 * "lpr" command for CUPS.
5 *
6 * Copyright 2007-2014 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
16/*
17 * Include necessary headers...
18 */
19
20#include <cups/cups-private.h>
21
22
23/*
24 * 'main()' - Parse options and send files for printing.
25 */
26
27int
28main(int  argc,				/* I - Number of command-line arguments */
29     char *argv[])			/* I - Command-line arguments */
30{
31  int		i, j;			/* Looping var */
32  int		job_id;			/* Job ID */
33  char		ch;			/* Option character */
34  char		*printer,		/* Destination printer or class */
35		*instance;		/* Instance */
36  const char	*title,			/* Job title */
37		*val;			/* Environment variable name */
38  int		num_copies;		/* Number of copies per file */
39  int		num_files;		/* Number of files to print */
40  const char	*files[1000];		/* Files to print */
41  cups_dest_t	*dest;			/* Selected destination */
42  int		num_options;		/* Number of options */
43  cups_option_t	*options;		/* Options */
44  int		deletefile;		/* Delete file after print? */
45  char		buffer[8192];		/* Copy buffer */
46
47
48  _cupsSetLocale(argv);
49
50  deletefile  = 0;
51  printer     = NULL;
52  dest        = NULL;
53  num_options = 0;
54  options     = NULL;
55  num_files   = 0;
56  title       = NULL;
57
58  for (i = 1; i < argc; i ++)
59    if (argv[i][0] == '-')
60    {
61      switch (ch = argv[i][1])
62      {
63        case 'E' : /* Encrypt */
64#ifdef HAVE_SSL
65	    cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
66#else
67            _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
68	                    argv[0]);
69#endif /* HAVE_SSL */
70	    break;
71
72        case 'U' : /* Username */
73	    if (argv[i][2] != '\0')
74	      cupsSetUser(argv[i] + 2);
75	    else
76	    {
77	      i ++;
78	      if (i >= argc)
79	      {
80	        _cupsLangPrintf(stderr,
81		                _("%s: Error - expected username after "
82				  "\"-U\" option."), argv[0]);
83	        return (1);
84	      }
85
86              cupsSetUser(argv[i]);
87	    }
88	    break;
89
90        case 'H' : /* Connect to host */
91	    if (argv[i][2] != '\0')
92              cupsSetServer(argv[i] + 2);
93	    else
94	    {
95	      i ++;
96
97	      if (i >= argc)
98	      {
99	        _cupsLangPrintf(stderr,
100		        	_("%s: Error - expected hostname after "
101			          "\"-H\" option."), argv[0]);
102		return (1);
103              }
104	      else
105                cupsSetServer(argv[i]);
106	    }
107	    break;
108
109	case '1' : /* TROFF font set 1 */
110	case '2' : /* TROFF font set 2 */
111	case '3' : /* TROFF font set 3 */
112	case '4' : /* TROFF font set 4 */
113	case 'i' : /* indent */
114	case 'w' : /* width */
115	    if (argv[i][2] == '\0')
116	    {
117	      i ++;
118
119	      if (i >= argc)
120	      {
121		_cupsLangPrintf(stderr,
122		                _("%s: Error - expected value after \"-%c\" "
123				  "option."), argv[0], ch);
124		return (1);
125	      }
126	    }
127
128        case 'c' : /* CIFPLOT */
129	case 'd' : /* DVI */
130	case 'f' : /* FORTRAN */
131	case 'g' : /* plot */
132	case 'n' : /* Ditroff */
133	case 't' : /* Troff */
134	case 'v' : /* Raster image */
135	    _cupsLangPrintf(stderr,
136	                    _("%s: Warning - \"%c\" format modifier not "
137			      "supported - output may not be correct."),
138			    argv[0], ch);
139	    break;
140
141	case 'o' : /* Option */
142	    if (argv[i][2] != '\0')
143	      num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
144	    else
145	    {
146	      i ++;
147	      if (i >= argc)
148	      {
149	        _cupsLangPrintf(stderr,
150		                _("%s: Error - expected option=value after "
151			          "\"-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,
165	                                &options);
166	    break;
167
168	case 'h' : /* Suppress burst page */
169            num_options = cupsAddOption("job-sheets", "none", num_options,
170	                                &options);
171	    break;
172
173	case 's' : /* Don't use symlinks */
174	    break;
175
176	case 'm' : /* Mail on completion */
177	    {
178	      char	email[1024];	/* EMail address */
179
180
181	      snprintf(email, sizeof(email), "mailto:%s@%s", cupsUser(),
182	               httpGetHostname(NULL, buffer, sizeof(buffer)));
183	      num_options = cupsAddOption("notify-recipient-uri", email,
184	                                  num_options, &options);
185	    }
186	    break;
187
188	case 'q' : /* Queue file but don't print */
189            num_options = cupsAddOption("job-hold-until", "indefinite",
190	                                num_options, &options);
191	    break;
192
193	case 'r' : /* Remove file after printing */
194	    deletefile = 1;
195	    break;
196
197        case 'P' : /* Destination printer or class */
198	    if (argv[i][2] != '\0')
199	      printer = argv[i] + 2;
200	    else
201	    {
202	      i ++;
203	      if (i >= argc)
204	      {
205	        _cupsLangPrintf(stderr,
206		        	_("%s: Error - expected destination after "
207			          "\"-P\" option."), argv[0]);
208		return (1);
209	      }
210
211	      printer = argv[i];
212	    }
213
214            if ((instance = strrchr(printer, '/')) != NULL)
215	      *instance++ = '\0';
216
217            if ((dest = cupsGetNamedDest(NULL, printer, instance)) != NULL)
218	    {
219	      for (j = 0; j < dest->num_options; j ++)
220	        if (cupsGetOption(dest->options[j].name, num_options,
221		                  options) == NULL)
222	          num_options = cupsAddOption(dest->options[j].name,
223		                              dest->options[j].value,
224					      num_options, &options);
225	    }
226	    else if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
227		     cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
228	    {
229	      _cupsLangPrintf(stderr,
230			      _("%s: Error - add '/version=1.1' to server "
231				"name."), argv[0]);
232	      return (1);
233	    }
234	    break;
235
236	case '#' : /* Number of copies */
237	    if (argv[i][2] != '\0')
238	      num_copies = atoi(argv[i] + 2);
239	    else
240	    {
241	      i ++;
242	      if (i >= argc)
243	      {
244	        _cupsLangPrintf(stderr,
245		        	_("%s: Error - expected copies after "
246			          "\"-#\" option."), argv[0]);
247		return (1);
248	      }
249
250	      num_copies = atoi(argv[i]);
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 (argv[i][2] != '\0')
261	      title = argv[i] + 2;
262	    else
263	    {
264	      i ++;
265	      if (i >= argc)
266	      {
267		_cupsLangPrintf(stderr,
268		                _("%s: Error - expected name after \"-%c\" "
269				  "option."), argv[0], ch);
270		return (1);
271	      }
272
273	      title = argv[i];
274	    }
275	    break;
276
277	default :
278	    _cupsLangPrintf(stderr,
279	                    _("%s: Error - unknown option \"%c\"."), argv[0],
280			    argv[i][1]);
281	    return (1);
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      _cupsLangPrintf(stderr,
311                      _("%s: Error - too many files - \"%s\"."), argv[0],
312		      argv[i]);
313 /*
314  * See if we have any files to print; if not, print from stdin...
315  */
316
317  if (printer == NULL)
318  {
319    if ((dest = cupsGetNamedDest(NULL, NULL, NULL)) != NULL)
320    {
321      printer = dest->name;
322
323      for (j = 0; j < dest->num_options; j ++)
324	if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
325	  num_options = cupsAddOption(dest->options[j].name,
326		                      dest->options[j].value,
327				      num_options, &options);
328    }
329    else if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
330	     cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
331    {
332      _cupsLangPrintf(stderr,
333		      _("%s: Error - add '/version=1.1' to server "
334			"name."), argv[0]);
335      return (1);
336    }
337  }
338
339  if (printer == NULL)
340  {
341    val = NULL;
342
343    if ((printer = getenv("LPDEST")) == NULL)
344    {
345      if ((printer = getenv("PRINTER")) != NULL)
346      {
347        if (!strcmp(printer, "lp"))
348          printer = NULL;
349	else
350	  val = "PRINTER";
351      }
352    }
353    else
354      val = "LPDEST";
355
356    if (printer && !cupsGetNamedDest(NULL, printer, NULL))
357      _cupsLangPrintf(stderr,
358                      _("%s: Error - %s environment variable names "
359		        "non-existent destination \"%s\"."), argv[0], val,
360		      printer);
361    else if (cupsLastError() == IPP_NOT_FOUND)
362      _cupsLangPrintf(stderr,
363                      _("%s: Error - no default destination available."),
364		      argv[0]);
365    else
366      _cupsLangPrintf(stderr, _("%s: Error - scheduler not responding."),
367		      argv[0]);
368
369    return (1);
370  }
371
372  if (num_files > 0)
373  {
374    job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
375
376    if (deletefile && job_id > 0)
377    {
378     /*
379      * Delete print files after printing...
380      */
381
382      for (i = 0; i < num_files; i ++)
383        unlink(files[i]);
384    }
385  }
386  else if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, printer,
387                                   title ? title : "(stdin)",
388                                   num_options, options)) > 0)
389  {
390    http_status_t	status;		/* Write status */
391    const char		*format;	/* Document format */
392    ssize_t		bytes;		/* Bytes read */
393
394    if (cupsGetOption("raw", num_options, options))
395      format = CUPS_FORMAT_RAW;
396    else if ((format = cupsGetOption("document-format", num_options,
397                                     options)) == NULL)
398      format = CUPS_FORMAT_AUTO;
399
400    status = cupsStartDocument(CUPS_HTTP_DEFAULT, printer, job_id, NULL,
401                               format, 1);
402
403    while (status == HTTP_CONTINUE &&
404           (bytes = read(0, buffer, sizeof(buffer))) > 0)
405      status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, (size_t)bytes);
406
407    if (status != HTTP_CONTINUE)
408    {
409      _cupsLangPrintf(stderr, _("%s: Error - unable to queue from stdin - %s."),
410		      argv[0], httpStatus(status));
411      cupsFinishDocument(CUPS_HTTP_DEFAULT, printer);
412      cupsCancelJob2(CUPS_HTTP_DEFAULT, printer, job_id, 0);
413      return (1);
414    }
415
416    if (cupsFinishDocument(CUPS_HTTP_DEFAULT, printer) != IPP_OK)
417    {
418      _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
419      cupsCancelJob2(CUPS_HTTP_DEFAULT, printer, job_id, 0);
420      return (1);
421    }
422  }
423
424  if (job_id < 1)
425  {
426    _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
427    return (1);
428  }
429
430  return (0);
431}
432
433
434/*
435 * End of "$Id: lpr.c 11560 2014-02-06 20:10:19Z msweet $".
436 */
437