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