• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * "lp" command for CUPS.
3  *
4  * Copyright © 2020-2024 by OpenPrinting.
5  * Copyright © 2007-2021 by Apple Inc.
6  * Copyright © 1997-2007 by Easy Software Products.
7  *
8  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
9  * information.
10  */
11 
12 /*
13  * Include necessary headers...
14  */
15 
16 #include <cups/cups-private.h>
17 
18 
19 /*
20  * Local functions.
21  */
22 
23 static int	restart_job(const char *command, int job_id, const char *job_hold_until);
24 static int	set_job_attrs(const char *command, int job_id, int num_options, cups_option_t *options);
25 static void	usage(void) _CUPS_NORETURN;
26 
27 
28 /*
29  * 'main()' - Parse options and send files for printing.
30  */
31 
32 int
main(int argc,char * argv[])33 main(int  argc,				/* I - Number of command-line arguments */
34      char *argv[])			/* I - Command-line arguments */
35 {
36   int		i, j;			/* Looping vars */
37   int		job_id;			/* Job ID */
38   char		*printer,		/* Printer name */
39 		*instance,		/* Instance name */
40 		*opt,			/* Option pointer */
41 		*val,			/* Option value */
42 		*title;			/* Job title */
43   int		priority;		/* Job priority (1-100) */
44   int		num_copies;		/* Number of copies per file */
45   int		num_files;		/* Number of files to print */
46   const char	*files[1000];		/* Files to print */
47   cups_dest_t	*dest;			/* Selected destination */
48   int		num_options;		/* Number of options */
49   cups_option_t	*options;		/* Options */
50   int		end_options;		/* No more options? */
51   int		silent;			/* Silent or verbose output? */
52   char		buffer[8192];		/* Copy buffer */
53 
54 
55 #ifdef __sun
56  /*
57   * Solaris does some rather strange things to re-queue remote print
58   * jobs.  On bootup, the "lp" command is run as "printd" to re-spool
59   * any remote jobs in /var/spool/print.  Since CUPS doesn't need this
60   * nonsense, we just need to add the necessary check here to prevent
61   * lp from causing boot problems...
62   */
63 
64   if ((val = strrchr(argv[0], '/')) != NULL)
65     val ++;
66   else
67     val = argv[0];
68 
69   if (!strcmp(val, "printd"))
70     return (0);
71 #endif /* __sun */
72 
73   _cupsSetLocale(argv);
74 
75   silent      = 0;
76   printer     = NULL;
77   dest        = NULL;
78   num_options = 0;
79   options     = NULL;
80   num_files   = 0;
81   title       = NULL;
82   job_id      = 0;
83   end_options = 0;
84 
85   for (i = 1; i < argc; i ++)
86   {
87     if (!strcmp(argv[i], "--help"))
88       usage();
89     else if (argv[i][0] == '-' && argv[i][1] && !end_options)
90     {
91       for (opt = argv[i] + 1; *opt; opt ++)
92       {
93         switch (*opt)
94 	{
95 	  case 'E' : /* Encrypt */
96 #ifdef HAVE_TLS
97 	      cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
98 #else
99 	      _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
100 #endif /* HAVE_TLS */
101 	      break;
102 
103 	  case 'U' : /* Username */
104 	      if (opt[1] != '\0')
105 	      {
106 		cupsSetUser(opt + 1);
107 		opt += strlen(opt) - 1;
108 	      }
109 	      else
110 	      {
111 		i ++;
112 		if (i >= argc)
113 		{
114 		  _cupsLangPrintf(stderr, _("%s: Error - expected username after \"-U\" option."), argv[0]);
115 		  usage();
116 		}
117 
118 		cupsSetUser(argv[i]);
119 	      }
120 	      break;
121 
122 	  case 'c' : /* Copy to spool dir (always enabled) */
123 	      break;
124 
125 	  case 'd' : /* Destination printer or class */
126 	      if (opt[1] != '\0')
127 	      {
128 		printer = opt + 1;
129 		opt += strlen(opt) - 1;
130 	      }
131 	      else
132 	      {
133 		i ++;
134 
135 		if (i >= argc)
136 		{
137 		  _cupsLangPrintf(stderr, _("%s: Error - expected destination after \"-d\" option."), argv[0]);
138 		  usage();
139 		}
140 
141 		printer = argv[i];
142 	      }
143 
144 	      if ((instance = strrchr(printer, '/')) != NULL)
145 		*instance++ = '\0';
146 
147 	      if ((dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, printer,
148 					   instance)) != NULL)
149 	      {
150 		for (j = 0; j < dest->num_options; j ++)
151 		  if (cupsGetOption(dest->options[j].name, num_options,
152 				    options) == NULL)
153 		    num_options = cupsAddOption(dest->options[j].name,
154 						dest->options[j].value,
155 						num_options, &options);
156 	      }
157 	      else if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
158 		       cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
159 	      {
160 		_cupsLangPrintf(stderr,
161 				_("%s: Error - add '/version=1.1' to server "
162 				  "name."), argv[0]);
163 		return (1);
164 	      }
165 	      else if (cupsLastError() == IPP_STATUS_ERROR_NOT_FOUND)
166 	      {
167 		_cupsLangPrintf(stderr,
168 				_("%s: Error - The printer or class does not exist."), argv[0]);
169 		return (1);
170 	      }
171 	      break;
172 
173 	  case 'f' : /* Form */
174 	      if (opt[1] != '\0')
175 	      {
176 	        opt += strlen(opt) - 1;
177 	      }
178 	      else
179 	      {
180 		i ++;
181 
182 		if (i >= argc)
183 		{
184 		  _cupsLangPrintf(stderr, _("%s: Error - expected form after \"-f\" option."), argv[0]);
185 		  usage();
186 		}
187 	      }
188 
189 	      _cupsLangPrintf(stderr, _("%s: Warning - form option ignored."), argv[0]);
190 	      break;
191 
192 	  case 'h' : /* Destination host */
193 	      if (opt[1] != '\0')
194 	      {
195 		cupsSetServer(opt + 1);
196 	        opt += strlen(opt) - 1;
197 	      }
198 	      else
199 	      {
200 		i ++;
201 
202 		if (i >= argc)
203 		{
204 		  _cupsLangPrintf(stderr, _("%s: Error - expected hostname after \"-h\" option."), argv[0]);
205 		  usage();
206 		}
207 
208 		cupsSetServer(argv[i]);
209 	      }
210 	      break;
211 
212 	  case 'i' : /* Change job */
213 	      if (opt[1] != '\0')
214 	      {
215 		val = opt + 1;
216 		opt += strlen(opt) - 1;
217 	      }
218 	      else
219 	      {
220 		i ++;
221 
222 		if (i >= argc)
223 		{
224 		  _cupsLangPrintf(stderr, _("%s: Expected job ID after \"-i\" option."), argv[0]);
225 		  usage();
226 		}
227 
228 		val = argv[i];
229 	      }
230 
231 	      if (num_files > 0)
232 	      {
233 		_cupsLangPrintf(stderr, _("%s: Error - cannot print files and alter jobs simultaneously."), argv[0]);
234 		return (1);
235 	      }
236 
237 	      if (strrchr(val, '-') != NULL)
238 		job_id = atoi(strrchr(val, '-') + 1);
239 	      else
240 		job_id = atoi(val);
241 
242 	      if (job_id < 0)
243 	      {
244 		_cupsLangPrintf(stderr, _("%s: Error - bad job ID."), argv[0]);
245 		break;
246 	      }
247 	      break;
248 
249 	  case 'm' : /* Send email when job is done */
250 #ifdef __sun
251 	  case 'p' : /* Notify on completion */
252 #endif /* __sun */
253 	  case 'w' : /* Write to console or email */
254 	      {
255 		char	email[1024];	/* EMail address */
256 
257 
258 		snprintf(email, sizeof(email), "mailto:%s@%s", cupsUser(), httpGetHostname(NULL, buffer, sizeof(buffer)));
259 		num_options = cupsAddOption("notify-recipient-uri", email, num_options, &options);
260 	      }
261 
262 	      silent = 1;
263 	      break;
264 
265 	  case 'n' : /* Number of copies */
266 	      if (opt[1] != '\0')
267 	      {
268 		num_copies = atoi(opt + 1);
269 		opt += strlen(opt) - 1;
270 	      }
271 	      else
272 	      {
273 		i ++;
274 
275 		if (i >= argc)
276 		{
277 		  _cupsLangPrintf(stderr, _("%s: Error - expected copies after \"-n\" option."), argv[0]);
278 		  usage();
279 		}
280 
281 		num_copies = atoi(argv[i]);
282 	      }
283 
284 	      if (num_copies < 1)
285 	      {
286 		_cupsLangPrintf(stderr, _("%s: Error - copies must be 1 or more."), argv[0]);
287 		return (1);
288 	      }
289 
290 	      num_options = cupsAddIntegerOption("copies", num_copies, num_options, &options);
291 	      break;
292 
293 	  case 'o' : /* Option */
294 	      if (opt[1] != '\0')
295 	      {
296 		num_options = cupsParseOptions(opt + 1, num_options, &options);
297 		opt += strlen(opt) - 1;
298 	      }
299 	      else
300 	      {
301 		i ++;
302 
303 		if (i >= argc)
304 		{
305 		  _cupsLangPrintf(stderr, _("%s: Error - expected option=value after \"-o\" option."), argv[0]);
306 		  usage();
307 		}
308 
309 		num_options = cupsParseOptions(argv[i], num_options, &options);
310 	      }
311 	      break;
312 
313 #ifndef __sun
314 	  case 'p' : /* Queue priority */
315 #endif /* !__sun */
316 	  case 'q' : /* Queue priority */
317 	      if (opt[1] != '\0')
318 	      {
319 		priority = atoi(opt + 1);
320 		opt += strlen(opt) - 1;
321 	      }
322 	      else
323 	      {
324 		if ((i + 1) >= argc)
325 		{
326 		  _cupsLangPrintf(stderr, _("%s: Error - expected priority after \"-%c\" option."), argv[0], *opt);
327 		  usage();
328 		}
329 
330 		i ++;
331 
332 		priority = atoi(argv[i]);
333 	      }
334 
335 	     /*
336 	      * For 100% Solaris compatibility, need to add:
337 	      *
338 	      *   priority = 99 * (39 - priority) / 39 + 1;
339 	      *
340 	      * However, to keep CUPS lp the same across all platforms
341 	      * we will break compatibility this far...
342 	      */
343 
344 	      if (priority < 1 || priority > 100)
345 	      {
346 		_cupsLangPrintf(stderr, _("%s: Error - priority must be between 1 and 100."), argv[0]);
347 		return (1);
348 	      }
349 
350 	      num_options = cupsAddIntegerOption("job-priority", priority, num_options, &options);
351 	      break;
352 
353 	  case 's' : /* Silent */
354 	      silent = 1;
355 	      break;
356 
357 	  case 't' : /* Title */
358 	      if (opt[1] != '\0')
359 	      {
360 		title = opt + 1;
361 		opt += strlen(opt) - 1;
362 	      }
363 	      else
364 	      {
365 		i ++;
366 
367 		if (i >= argc)
368 		{
369 		  _cupsLangPrintf(stderr, _("%s: Error - expected title after \"-t\" option."), argv[0]);
370 		  usage();
371 		}
372 
373 		title = argv[i];
374 	      }
375 	      break;
376 
377 	  case 'y' : /* mode-list */
378 	      if (opt[1] != '\0')
379 	      {
380 		opt += strlen(opt) - 1;
381 	      }
382 	      else
383 	      {
384 		i ++;
385 
386 		if (i >= argc)
387 		{
388 		  _cupsLangPrintf(stderr, _("%s: Error - expected mode list after \"-y\" option."), argv[0]);
389 		  usage();
390 		}
391 	      }
392 
393 	      _cupsLangPrintf(stderr, _("%s: Warning - mode option ignored."), argv[0]);
394 	      break;
395 
396 	  case 'H' : /* Hold job */
397 	      if (opt[1] != '\0')
398 	      {
399 		val = opt + 1;
400 		opt += strlen(opt) - 1;
401 	      }
402 	      else
403 	      {
404 		i ++;
405 
406 		if (i >= argc)
407 		{
408 		  _cupsLangPrintf(stderr, _("%s: Error - expected hold name after \"-H\" option."), argv[0]);
409 		  usage();
410 		}
411 
412 		val = argv[i];
413 	      }
414 
415 	      if (!strcmp(val, "hold"))
416 		num_options = cupsAddOption("job-hold-until", "indefinite", num_options, &options);
417 	      else if (!strcmp(val, "resume") || !strcmp(val, "release"))
418 		num_options = cupsAddOption("job-hold-until", "no-hold", num_options, &options);
419 	      else if (!strcmp(val, "immediate"))
420 	      {
421 		num_options = cupsAddOption("job-hold-until", "no-hold", num_options, &options);
422 		num_options = cupsAddOption("job-priority", "100", num_options, &options);
423 	      }
424 	      else if (!strcmp(val, "restart"))
425 	      {
426 		if (job_id < 1)
427 		{
428 		  _cupsLangPrintf(stderr, _("%s: Need job ID (\"-i jobid\") before \"-H restart\"."), argv[0]);
429 		  return (1);
430 		}
431 
432 		if (restart_job(argv[0], job_id, cupsGetOption("job-hold-until", num_options, options)))
433 		  return (1);
434 	      }
435 	      else
436 		num_options = cupsAddOption("job-hold-until", val, num_options, &options);
437 	      break;
438 
439 	  case 'P' : /* Page list */
440 	      if (opt[1] != '\0')
441 	      {
442 		val = opt + 1;
443 		opt += strlen(opt) - 1;
444 	      }
445 	      else
446 	      {
447 		i ++;
448 
449 		if (i >= argc)
450 		{
451 		  _cupsLangPrintf(stderr, _("%s: Error - expected page list after \"-P\" option."), argv[0]);
452 		  usage();
453 		}
454 
455 		val = argv[i];
456 	      }
457 
458 	      num_options = cupsAddOption("page-ranges", val, num_options, &options);
459 	      break;
460 
461 	  case 'S' : /* character set */
462 	      if (opt[1] != '\0')
463 	      {
464 		opt += strlen(opt) - 1;
465 	      }
466 	      else
467 	      {
468 		i ++;
469 
470 		if (i >= argc)
471 		{
472 		  _cupsLangPrintf(stderr, _("%s: Error - expected character set after \"-S\" option."), argv[0]);
473 		  usage();
474 		}
475 	      }
476 
477 	      _cupsLangPrintf(stderr, _("%s: Warning - character set option ignored."), argv[0]);
478 	      break;
479 
480 	  case 'T' : /* Content-Type */
481 	      if (opt[1] != '\0')
482 	      {
483 		opt += strlen(opt) - 1;
484 	      }
485 	      else
486 	      {
487 		i ++;
488 
489 		if (i >= argc)
490 		{
491 		  _cupsLangPrintf(stderr, _("%s: Error - expected content type after \"-T\" option."), argv[0]);
492 		  usage();
493 		}
494 	      }
495 
496 	      _cupsLangPrintf(stderr, _("%s: Warning - content type option ignored."), argv[0]);
497 	      break;
498 
499 	  case '-' : /* Stop processing options */
500 	      if (opt[1] != '\0')
501 	      {
502 		_cupsLangPrintf(stderr, _("%s: Error - unknown option \"%s\"."), argv[0], argv[i]);
503 		usage();
504 	      }
505 
506 	      end_options = 1;
507 	      break;
508 
509 	  default :
510 	      _cupsLangPrintf(stderr, _("%s: Error - unknown option \"%c\"."), argv[0], *opt);
511 	      usage();
512 	}
513       }
514     }
515     else if (!strcmp(argv[i], "-"))
516     {
517       if (num_files || job_id)
518       {
519         _cupsLangPrintf(stderr,
520 			_("%s: Error - cannot print from stdin if files or a "
521 		          "job ID are provided."), argv[0]);
522 	return (1);
523       }
524 
525       break;
526     }
527     else if (num_files < 1000 && job_id == 0)
528     {
529      /*
530       * Print a file...
531       */
532 
533       if (access(argv[i], R_OK) != 0)
534       {
535         _cupsLangPrintf(stderr, _("%s: Error - unable to access \"%s\" - %s"), argv[0], argv[i], strerror(errno));
536         return (1);
537       }
538 
539       files[num_files] = argv[i];
540       num_files ++;
541 
542       if (title == NULL)
543       {
544         if ((title = strrchr(argv[i], '/')) != NULL)
545 	  title ++;
546 	else
547           title = argv[i];
548       }
549     }
550     else
551     {
552       _cupsLangPrintf(stderr, _("%s: Error - too many files - \"%s\"."), argv[0], argv[i]);
553     }
554   }
555 
556  /*
557   * See if we are altering an existing job...
558   */
559 
560   if (job_id)
561     return (set_job_attrs(argv[0], job_id, num_options, options));
562 
563  /*
564   * See if we have any files to print; if not, print from stdin...
565   */
566 
567   if (printer == NULL)
568   {
569     if ((dest = cupsGetNamedDest(NULL, NULL, NULL)) != NULL)
570     {
571       printer = dest->name;
572 
573       for (j = 0; j < dest->num_options; j ++)
574 	if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
575 	  num_options = cupsAddOption(dest->options[j].name,
576 		                      dest->options[j].value,
577 				      num_options, &options);
578     }
579     else if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
580 	     cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
581     {
582       _cupsLangPrintf(stderr,
583 		      _("%s: Error - add '/version=1.1' to server "
584 			"name."), argv[0]);
585       return (1);
586     }
587   }
588 
589   if (printer == NULL)
590   {
591     if (!cupsGetNamedDest(NULL, NULL, NULL) && cupsLastError() == IPP_STATUS_ERROR_NOT_FOUND)
592       _cupsLangPrintf(stderr, _("%s: Error - %s"), argv[0], cupsLastErrorString());
593     else
594       _cupsLangPrintf(stderr, _("%s: Error - scheduler not responding."), argv[0]);
595 
596     return (1);
597   }
598 
599   if (num_files > 0)
600     job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
601   else if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, printer,
602                                    title ? title : "(stdin)",
603                                    num_options, options)) > 0)
604   {
605     http_status_t	status;		/* Write status */
606     const char		*format;	/* Document format */
607     ssize_t		bytes;		/* Bytes read */
608 
609     if (cupsGetOption("raw", num_options, options))
610       format = CUPS_FORMAT_RAW;
611     else if ((format = cupsGetOption("document-format", num_options,
612                                      options)) == NULL)
613       format = CUPS_FORMAT_AUTO;
614 
615     status = cupsStartDocument(CUPS_HTTP_DEFAULT, printer, job_id, NULL,
616                                format, 1);
617 
618     while (status == HTTP_CONTINUE &&
619            (bytes = read(0, buffer, sizeof(buffer))) > 0)
620       status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, (size_t)bytes);
621 
622     if (status != HTTP_CONTINUE)
623     {
624       _cupsLangPrintf(stderr, _("%s: Error - unable to queue from stdin - %s."),
625 		      argv[0], httpStatus(status));
626       cupsFinishDocument(CUPS_HTTP_DEFAULT, printer);
627       cupsCancelJob2(CUPS_HTTP_DEFAULT, printer, job_id, 0);
628       return (1);
629     }
630 
631     if (cupsFinishDocument(CUPS_HTTP_DEFAULT, printer) != IPP_OK)
632     {
633       _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
634       cupsCancelJob2(CUPS_HTTP_DEFAULT, printer, job_id, 0);
635       return (1);
636     }
637   }
638 
639   if (job_id < 1)
640   {
641     _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
642     return (1);
643   }
644   else if (!silent)
645     _cupsLangPrintf(stdout, _("request id is %s-%d (%d file(s))"),
646 		    printer, job_id, num_files);
647 
648   return (0);
649 }
650 
651 
652 /*
653  * 'restart_job()' - Restart a job.
654  */
655 
656 static int				/* O - Exit status */
restart_job(const char * command,int job_id,const char * job_hold_until)657 restart_job(const char *command,	/* I - Command name */
658             int        job_id,		/* I - Job ID */
659             const char *job_hold_until)	/* I - "job-hold-until" value, if any */
660 {
661   ipp_t		*request;		/* IPP request */
662   char		uri[HTTP_MAX_URI];	/* URI for job */
663 
664 
665   request = ippNewRequest(IPP_RESTART_JOB);
666 
667   snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
668 
669   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
670                "job-uri", NULL, uri);
671 
672   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
673                "requesting-user-name", NULL, cupsUser());
674 
675   if (job_hold_until)
676     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "job-hold-until", NULL, job_hold_until);
677 
678   ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/jobs"));
679 
680   if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
681       cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
682   {
683     _cupsLangPrintf(stderr,
684 		    _("%s: Error - add '/version=1.1' to server "
685 		      "name."), command);
686     return (1);
687   }
688   else if (cupsLastError() > IPP_OK_CONFLICT)
689   {
690     _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
691     return (1);
692   }
693 
694   return (0);
695 }
696 
697 
698 /*
699  * 'set_job_attrs()' - Set job attributes.
700  */
701 
702 static int				/* O - Exit status */
set_job_attrs(const char * command,int job_id,int num_options,cups_option_t * options)703 set_job_attrs(
704     const char    *command,		/* I - Command name */
705     int           job_id,		/* I - Job ID */
706     int           num_options,		/* I - Number of options */
707     cups_option_t *options)		/* I - Options */
708 {
709   ipp_t		*request;		/* IPP request */
710   char		uri[HTTP_MAX_URI];	/* URI for job */
711 
712 
713   if (num_options == 0)
714     return (0);
715 
716   request = ippNewRequest(IPP_SET_JOB_ATTRIBUTES);
717 
718   snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
719 
720   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
721                "job-uri", NULL, uri);
722 
723   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
724                "requesting-user-name", NULL, cupsUser());
725 
726   cupsEncodeOptions(request, num_options, options);
727 
728   ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/jobs"));
729 
730   if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
731       cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
732   {
733     _cupsLangPrintf(stderr,
734 		    _("%s: Error - add '/version=1.1' to server "
735 		      "name."), command);
736     return (1);
737   }
738   else if (cupsLastError() > IPP_OK_CONFLICT)
739   {
740     _cupsLangPrintf(stderr, "%s: %s", command, cupsLastErrorString());
741     return (1);
742   }
743 
744   return (0);
745 }
746 
747 
748 /*
749  * 'usage()' - Show program usage and exit.
750  */
751 
752 static void
usage(void)753 usage(void)
754 {
755   _cupsLangPuts(stdout, _("Usage: lp [options] [--] [file(s)]\n"
756                           "       lp [options] -i id"));
757   _cupsLangPuts(stdout, _("Options:"));
758   _cupsLangPuts(stdout, _("-c                      Make a copy of the print file(s)"));
759   _cupsLangPuts(stdout, _("-d destination          Specify the destination"));
760   _cupsLangPuts(stdout, _("-E                      Encrypt the connection to the server"));
761   _cupsLangPuts(stdout, _("-h server[:port]        Connect to the named server and port"));
762   _cupsLangPuts(stdout, _("-H HH:MM                Hold the job until the specified UTC time"));
763   _cupsLangPuts(stdout, _("-H hold                 Hold the job until released/resumed"));
764   _cupsLangPuts(stdout, _("-H immediate            Print the job as soon as possible"));
765   _cupsLangPuts(stdout, _("-H restart              Reprint the job"));
766   _cupsLangPuts(stdout, _("-H resume               Resume a held job"));
767   _cupsLangPuts(stdout, _("-i id                   Specify an existing job ID to modify"));
768   _cupsLangPuts(stdout, _("-m                      Send an email notification when the job completes"));
769   _cupsLangPuts(stdout, _("-n num-copies           Specify the number of copies to print"));
770   _cupsLangPuts(stdout, _("-o option[=value]       Specify a printer-specific option"));
771   _cupsLangPuts(stdout, _("-o job-sheets=standard  Print a banner page with the job"));
772   _cupsLangPuts(stdout, _("-o media=size           Specify the media size to use"));
773   _cupsLangPuts(stdout, _("-o number-up=N          Specify that input pages should be printed N-up (1, 2, 4, 6, 9, and 16 are supported)"));
774   _cupsLangPuts(stdout, _("-o orientation-requested=N\n"
775                           "                        Specify portrait (3) or landscape (4) orientation"));
776   _cupsLangPuts(stdout, _("-o print-quality=N      Specify the print quality - draft (3), normal (4), or best (5)"));
777   _cupsLangPuts(stdout, _("-o sides=one-sided      Specify 1-sided printing"));
778   _cupsLangPuts(stdout, _("-o sides=two-sided-long-edge\n"
779                           "                        Specify 2-sided portrait printing"));
780   _cupsLangPuts(stdout, _("-o sides=two-sided-short-edge\n"
781                           "                        Specify 2-sided landscape printing"));
782   _cupsLangPuts(stdout, _("-P page-list            Specify a list of pages to print"));
783   _cupsLangPuts(stdout, _("-q priority             Specify the priority from low (1) to high (100)"));
784   _cupsLangPuts(stdout, _("-s                      Be silent"));
785   _cupsLangPuts(stdout, _("-t title                Specify the job title"));
786   _cupsLangPuts(stdout, _("-U username             Specify the username to use for authentication"));
787 
788 
789   exit(1);
790 }
791