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