2 * "lp" command for CUPS.
4 * Copyright 2007-2016 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products.
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * missing or damaged, see the license at "http://www.cups.org/".
15 * Include necessary headers...
18 #include <cups/cups-private.h>
25 int restart_job(const char *command
, int job_id
);
26 int set_job_attrs(const char *command
, int job_id
, int num_options
,
27 cups_option_t
*options
);
31 * 'main()' - Parse options and send files for printing.
35 main(int argc
, /* I - Number of command-line arguments */
36 char *argv
[]) /* I - Command-line arguments */
38 int i
, j
; /* Looping vars */
39 int job_id
; /* Job ID */
40 char *printer
, /* Printer name */
41 *instance
, /* Instance name */
42 *opt
, /* Option pointer */
43 *val
, /* Option value */
44 *title
; /* Job title */
45 int priority
; /* Job priority (1-100) */
46 int num_copies
; /* Number of copies per file */
47 int num_files
; /* Number of files to print */
48 const char *files
[1000]; /* Files to print */
49 cups_dest_t
*dest
; /* Selected destination */
50 int num_options
; /* Number of options */
51 cups_option_t
*options
; /* Options */
52 int end_options
; /* No more options? */
53 int silent
; /* Silent or verbose output? */
54 char buffer
[8192]; /* Copy buffer */
59 * Solaris does some rather strange things to re-queue remote print
60 * jobs. On bootup, the "lp" command is run as "printd" to re-spool
61 * any remote jobs in /var/spool/print. Since CUPS doesn't need this
62 * nonsense, we just need to add the necessary check here to prevent
63 * lp from causing boot problems...
66 if ((val
= strrchr(argv
[0], '/')) != NULL
)
71 if (!strcmp(val
, "printd"))
87 for (i
= 1; i
< argc
; i
++)
89 if (argv
[i
][0] == '-' && argv
[i
][1] && !end_options
)
91 for (opt
= argv
[i
] + 1; *opt
; opt
++)
95 case 'E' : /* Encrypt */
97 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED
);
99 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."), argv
[0]);
100 #endif /* HAVE_SSL */
103 case 'U' : /* Username */
106 cupsSetUser(opt
+ 1);
107 opt
+= strlen(opt
) - 1;
114 _cupsLangPrintf(stderr
, _("%s: Error - expected username after \"-U\" option."), argv
[0]);
118 cupsSetUser(argv
[i
]);
122 case 'c' : /* Copy to spool dir (always enabled) */
125 case 'd' : /* Destination printer or class */
129 opt
+= strlen(opt
) - 1;
137 _cupsLangPrintf(stderr
, _("%s: Error - expected destination after \"-d\" option."), argv
[0]);
144 if ((instance
= strrchr(printer
, '/')) != NULL
)
147 if ((dest
= cupsGetNamedDest(CUPS_HTTP_DEFAULT
, printer
,
150 for (j
= 0; j
< dest
->num_options
; j
++)
151 if (cupsGetOption(dest
->options
[j
].name
, num_options
,
153 num_options
= cupsAddOption(dest
->options
[j
].name
,
154 dest
->options
[j
].value
,
155 num_options
, &options
);
157 else if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST
||
158 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED
)
160 _cupsLangPrintf(stderr
,
161 _("%s: Error - add '/version=1.1' to server "
167 case 'f' : /* Form */
170 opt
+= strlen(opt
) - 1;
178 _cupsLangPrintf(stderr
, _("%s: Error - expected form after \"-f\" option."), argv
[0]);
183 _cupsLangPrintf(stderr
, _("%s: Warning - form option ignored."), argv
[0]);
186 case 'h' : /* Destination host */
189 cupsSetServer(opt
+ 1);
190 opt
+= strlen(opt
) - 1;
198 _cupsLangPrintf(stderr
, _("%s: Error - expected hostname after \"-h\" option."), argv
[0]);
202 cupsSetServer(argv
[i
]);
206 case 'i' : /* Change job */
210 opt
+= strlen(opt
) - 1;
218 _cupsLangPrintf(stderr
, _("%s: Expected job ID after \"-i\" option."), argv
[0]);
227 _cupsLangPrintf(stderr
, _("%s: Error - cannot print files and alter jobs simultaneously."), argv
[0]);
231 if (strrchr(val
, '-') != NULL
)
232 job_id
= atoi(strrchr(val
, '-') + 1);
238 _cupsLangPrintf(stderr
, _("%s: Error - bad job ID."), argv
[0]);
243 case 'm' : /* Send email when job is done */
245 case 'p' : /* Notify on completion */
247 case 'w' : /* Write to console or email */
249 char email
[1024]; /* EMail address */
252 snprintf(email
, sizeof(email
), "mailto:%s@%s", cupsUser(), httpGetHostname(NULL
, buffer
, sizeof(buffer
)));
253 num_options
= cupsAddOption("notify-recipient-uri", email
, num_options
, &options
);
259 case 'n' : /* Number of copies */
262 num_copies
= atoi(opt
+ 1);
263 opt
+= strlen(opt
) - 1;
271 _cupsLangPrintf(stderr
, _("%s: Error - expected copies after \"-n\" option."), argv
[0]);
275 num_copies
= atoi(argv
[i
]);
280 _cupsLangPrintf(stderr
, _("%s: Error - copies must be 1 or more."), argv
[0]);
284 sprintf(buffer
, "%d", num_copies
);
285 num_options
= cupsAddOption("copies", buffer
, num_options
,
289 case 'o' : /* Option */
292 num_options
= cupsParseOptions(opt
+ 1, num_options
, &options
);
293 opt
+= strlen(opt
) - 1;
301 _cupsLangPrintf(stderr
, _("%s: Error - expected option=value after \"-o\" option."), argv
[0]);
305 num_options
= cupsParseOptions(argv
[i
], num_options
, &options
);
310 case 'p' : /* Queue priority */
312 case 'q' : /* Queue priority */
315 priority
= atoi(opt
+ 1);
316 opt
+= strlen(opt
) - 1;
322 _cupsLangPrintf(stderr
, _("%s: Error - expected priority after \"-%c\" option."), argv
[0], *opt
);
328 priority
= atoi(argv
[i
]);
332 * For 100% Solaris compatibility, need to add:
334 * priority = 99 * (39 - priority) / 39 + 1;
336 * However, to keep CUPS lp the same across all platforms
337 * we will break compatibility this far...
340 if (priority
< 1 || priority
> 100)
342 _cupsLangPrintf(stderr
, _("%s: Error - priority must be between 1 and 100."), argv
[0]);
346 sprintf(buffer
, "%d", priority
);
347 num_options
= cupsAddOption("job-priority", buffer
, num_options
,
351 case 's' : /* Silent */
355 case 't' : /* Title */
359 opt
+= strlen(opt
) - 1;
367 _cupsLangPrintf(stderr
, _("%s: Error - expected title after \"-t\" option."), argv
[0]);
375 case 'y' : /* mode-list */
378 opt
+= strlen(opt
) - 1;
386 _cupsLangPrintf(stderr
, _("%s: Error - expected mode list after \"-y\" option."), argv
[0]);
391 _cupsLangPrintf(stderr
, _("%s: Warning - mode option ignored."), argv
[0]);
394 case 'H' : /* Hold job */
398 opt
+= strlen(opt
) - 1;
406 _cupsLangPrintf(stderr
, _("%s: Error - expected hold name after \"-H\" option."), argv
[0]);
413 if (!strcmp(val
, "hold"))
414 num_options
= cupsAddOption("job-hold-until", "indefinite", num_options
, &options
);
415 else if (!strcmp(val
, "resume") || !strcmp(val
, "release"))
416 num_options
= cupsAddOption("job-hold-until", "no-hold", num_options
, &options
);
417 else if (!strcmp(val
, "immediate"))
419 num_options
= cupsAddOption("job-hold-until", "no-hold", num_options
, &options
);
420 num_options
= cupsAddOption("job-priority", "100", num_options
, &options
);
422 else if (!strcmp(val
, "restart"))
426 _cupsLangPrintf(stderr
, _("%s: Need job ID (\"-i jobid\") before \"-H restart\"."), argv
[0]);
430 if (restart_job(argv
[0], job_id
))
434 num_options
= cupsAddOption("job-hold-until", val
, num_options
, &options
);
437 case 'P' : /* Page list */
441 opt
+= strlen(opt
) - 1;
449 _cupsLangPrintf(stderr
, _("%s: Error - expected page list after \"-P\" option."), argv
[0]);
456 num_options
= cupsAddOption("page-ranges", val
, num_options
, &options
);
459 case 'S' : /* character set */
462 opt
+= strlen(opt
) - 1;
470 _cupsLangPrintf(stderr
, _("%s: Error - expected character set after \"-S\" option."), argv
[0]);
475 _cupsLangPrintf(stderr
, _("%s: Warning - character set option ignored."), argv
[0]);
478 case 'T' : /* Content-Type */
481 opt
+= strlen(opt
) - 1;
489 _cupsLangPrintf(stderr
, _("%s: Error - expected content type after \"-T\" option."), argv
[0]);
494 _cupsLangPrintf(stderr
, _("%s: Warning - content type option ignored."), argv
[0]);
497 case '-' : /* Stop processing options */
500 _cupsLangPrintf(stderr
, _("%s: Error - unknown option \"%s\"."), argv
[0], argv
[i
]);
508 _cupsLangPrintf(stderr
, _("%s: Error - unknown option \"%c\"."), argv
[0], *opt
);
513 else if (!strcmp(argv
[i
], "-"))
515 if (num_files
|| job_id
)
517 _cupsLangPrintf(stderr
,
518 _("%s: Error - cannot print from stdin if files or a "
519 "job ID are provided."), argv
[0]);
525 else if (num_files
< 1000 && job_id
== 0)
531 if (access(argv
[i
], R_OK
) != 0)
533 _cupsLangPrintf(stderr
, _("%s: Error - unable to access \"%s\" - %s"), argv
[0], argv
[i
], strerror(errno
));
537 files
[num_files
] = argv
[i
];
542 if ((title
= strrchr(argv
[i
], '/')) != NULL
)
550 _cupsLangPrintf(stderr
, _("%s: Error - too many files - \"%s\"."), argv
[0], argv
[i
]);
555 * See if we are altering an existing job...
559 return (set_job_attrs(argv
[0], job_id
, num_options
, options
));
562 * See if we have any files to print; if not, print from stdin...
567 if ((dest
= cupsGetNamedDest(NULL
, NULL
, NULL
)) != NULL
)
569 printer
= dest
->name
;
571 for (j
= 0; j
< dest
->num_options
; j
++)
572 if (cupsGetOption(dest
->options
[j
].name
, num_options
, options
) == NULL
)
573 num_options
= cupsAddOption(dest
->options
[j
].name
,
574 dest
->options
[j
].value
,
575 num_options
, &options
);
577 else if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST
||
578 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED
)
580 _cupsLangPrintf(stderr
,
581 _("%s: Error - add '/version=1.1' to server "
591 if ((printer
= getenv("LPDEST")) == NULL
)
593 if ((printer
= getenv("PRINTER")) != NULL
)
595 if (!strcmp(printer
, "lp"))
604 if (printer
&& !cupsGetNamedDest(NULL
, printer
, NULL
))
605 _cupsLangPrintf(stderr
,
606 _("%s: Error - %s environment variable names "
607 "non-existent destination \"%s\"."), argv
[0], val
,
609 else if (cupsLastError() == IPP_NOT_FOUND
)
610 _cupsLangPrintf(stderr
,
611 _("%s: Error - no default destination available."),
614 _cupsLangPrintf(stderr
, _("%s: Error - scheduler not responding."),
621 job_id
= cupsPrintFiles(printer
, num_files
, files
, title
, num_options
, options
);
622 else if ((job_id
= cupsCreateJob(CUPS_HTTP_DEFAULT
, printer
,
623 title
? title
: "(stdin)",
624 num_options
, options
)) > 0)
626 http_status_t status
; /* Write status */
627 const char *format
; /* Document format */
628 ssize_t bytes
; /* Bytes read */
630 if (cupsGetOption("raw", num_options
, options
))
631 format
= CUPS_FORMAT_RAW
;
632 else if ((format
= cupsGetOption("document-format", num_options
,
634 format
= CUPS_FORMAT_AUTO
;
636 status
= cupsStartDocument(CUPS_HTTP_DEFAULT
, printer
, job_id
, NULL
,
639 while (status
== HTTP_CONTINUE
&&
640 (bytes
= read(0, buffer
, sizeof(buffer
))) > 0)
641 status
= cupsWriteRequestData(CUPS_HTTP_DEFAULT
, buffer
, (size_t)bytes
);
643 if (status
!= HTTP_CONTINUE
)
645 _cupsLangPrintf(stderr
, _("%s: Error - unable to queue from stdin - %s."),
646 argv
[0], httpStatus(status
));
647 cupsFinishDocument(CUPS_HTTP_DEFAULT
, printer
);
648 cupsCancelJob2(CUPS_HTTP_DEFAULT
, printer
, job_id
, 0);
652 if (cupsFinishDocument(CUPS_HTTP_DEFAULT
, printer
) != IPP_OK
)
654 _cupsLangPrintf(stderr
, "%s: %s", argv
[0], cupsLastErrorString());
655 cupsCancelJob2(CUPS_HTTP_DEFAULT
, printer
, job_id
, 0);
662 _cupsLangPrintf(stderr
, "%s: %s", argv
[0], cupsLastErrorString());
666 _cupsLangPrintf(stdout
, _("request id is %s-%d (%d file(s))"),
667 printer
, job_id
, num_files
);
674 * 'restart_job()' - Restart a job.
677 int /* O - Exit status */
678 restart_job(const char *command
, /* I - Command name */
679 int job_id
) /* I - Job ID */
681 ipp_t
*request
; /* IPP request */
682 char uri
[HTTP_MAX_URI
]; /* URI for job */
685 request
= ippNewRequest(IPP_RESTART_JOB
);
687 sprintf(uri
, "ipp://localhost/jobs/%d", job_id
);
689 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
690 "job-uri", NULL
, uri
);
692 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
693 "requesting-user-name", NULL
, cupsUser());
695 ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT
, request
, "/jobs"));
697 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST
||
698 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED
)
700 _cupsLangPrintf(stderr
,
701 _("%s: Error - add '/version=1.1' to server "
705 else if (cupsLastError() > IPP_OK_CONFLICT
)
707 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());
716 * 'set_job_attrs()' - Set job attributes.
719 int /* O - Exit status */
720 set_job_attrs(const char *command
, /* I - Command name */
721 int job_id
, /* I - Job ID */
722 int num_options
,/* I - Number of options */
723 cups_option_t
*options
) /* I - Options */
725 ipp_t
*request
; /* IPP request */
726 char uri
[HTTP_MAX_URI
]; /* URI for job */
729 if (num_options
== 0)
732 request
= ippNewRequest(IPP_SET_JOB_ATTRIBUTES
);
734 sprintf(uri
, "ipp://localhost/jobs/%d", job_id
);
736 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
737 "job-uri", NULL
, uri
);
739 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
740 "requesting-user-name", NULL
, cupsUser());
742 cupsEncodeOptions(request
, num_options
, options
);
744 ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT
, request
, "/jobs"));
746 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST
||
747 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED
)
749 _cupsLangPrintf(stderr
,
750 _("%s: Error - add '/version=1.1' to server "
754 else if (cupsLastError() > IPP_OK_CONFLICT
)
756 _cupsLangPrintf(stderr
, "%s: %s", command
, cupsLastErrorString());