]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/lp.c
To prepare to load cups into easysw/current, perform 4 renames.
[thirdparty/cups.git] / systemv / lp.c
CommitLineData
ef416fc2 1/*
2 * "$Id: lp.c 4906 2006-01-10 20:53:28Z mike $"
3 *
4 * "lp" command for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Parse options and send files for printing.
27 * restart_job() - Restart a job.
28 * set_job_attrs() - Set job attributes.
29 * sighandler() - Signal catcher for when we print from stdin...
30 */
31
32/*
33 * Include necessary headers...
34 */
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <errno.h>
39#include <cups/string.h>
40#include <cups/cups.h>
41#include <cups/i18n.h>
42
43
44#ifndef WIN32
45# include <unistd.h>
46# include <signal.h>
47
48
49/*
50 * Local functions.
51 */
52
53void sighandler(int);
54#endif /* !WIN32 */
55int restart_job(int job_id);
56int set_job_attrs(int job_id, int num_options, cups_option_t *options);
57
58
59/*
60 * Globals...
61 */
62
63char tempfile[1024]; /* Temporary file for printing from stdin */
64
65
66/*
67 * 'main()' - Parse options and send files for printing.
68 */
69
70int
71main(int argc, /* I - Number of command-line arguments */
72 char *argv[]) /* I - Command-line arguments */
73{
74 int i, j; /* Looping vars */
75 int job_id; /* Job ID */
76 char *printer, /* Printer name */
77 *instance, /* Instance name */
78 *val, /* Option value */
79 *title; /* Job title */
80 int priority; /* Job priority (1-100) */
81 int num_copies; /* Number of copies per file */
82 int num_files; /* Number of files to print */
83 const char *files[1000]; /* Files to print */
84 int num_dests; /* Number of destinations */
85 cups_dest_t *dests, /* Destinations */
86 *dest; /* Selected destination */
87 int num_options; /* Number of options */
88 cups_option_t *options; /* Options */
89 int silent; /* Silent or verbose output? */
90 char buffer[8192]; /* Copy buffer */
91 int temp; /* Temporary file descriptor */
92#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
93 struct sigaction action; /* Signal action */
94 struct sigaction oldaction; /* Old signal action */
95#endif /* HAVE_SIGACTION && !HAVE_SIGSET*/
96
97
98#ifdef __sun
99 /*
100 * Solaris does some rather strange things to re-queue remote print
101 * jobs. On bootup, the "lp" command is run as "printd" to re-spool
102 * any remote jobs in /var/spool/print. Since CUPS doesn't need this
103 * nonsense, we just need to add the necessary check here to prevent
104 * lp from causing boot problems...
105 */
106
107 if ((val = strrchr(argv[0], '/')) != NULL)
108 val ++;
109 else
110 val = argv[0];
111
112 if (!strcmp(val, "printd"))
113 return (0);
114#endif /* __sun */
115
116 silent = 0;
117 printer = NULL;
118 num_dests = 0;
119 dests = NULL;
120 num_options = 0;
121 options = NULL;
122 num_files = 0;
123 title = NULL;
124 job_id = 0;
125
126 for (i = 1; i < argc; i ++)
127 if (argv[i][0] == '-' && argv[i][1])
128 switch (argv[i][1])
129 {
130 case 'E' : /* Encrypt */
131#ifdef HAVE_SSL
132 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
133#else
134 _cupsLangPrintf(stderr, NULL,
135 _("%s: Sorry, no encryption support compiled in!\n"),
136 argv[0]);
137#endif /* HAVE_SSL */
138 break;
139
140 case 'c' : /* Copy to spool dir (always enabled) */
141 break;
142
143 case 'd' : /* Destination printer or class */
144 if (argv[i][2] != '\0')
145 printer = argv[i] + 2;
146 else
147 {
148 i ++;
149
150 if (i >= argc)
151 {
152 _cupsLangPuts(stderr, NULL,
153 _("lp: Expected destination after -d option!\n"));
154 return (1);
155 }
156
157 printer = argv[i];
158 }
159
160 if ((instance = strrchr(printer, '/')) != NULL)
161 *instance++ = '\0';
162
163 if (num_dests == 0)
164 num_dests = cupsGetDests(&dests);
165
166 if ((dest = cupsGetDest(printer, instance, num_dests, dests)) != NULL)
167 {
168 for (j = 0; j < dest->num_options; j ++)
169 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
170 num_options = cupsAddOption(dest->options[j].name,
171 dest->options[j].value,
172 num_options, &options);
173 }
174 break;
175
176 case 'f' : /* Form */
177 if (!argv[i][2])
178 {
179 i ++;
180
181 if (i >= argc)
182 {
183 _cupsLangPuts(stderr, NULL,
184 _("lp: Expected form after -f option!\n"));
185 return (1);
186 }
187 }
188
189 fputs("lp: Warning - form option ignored!\n", stderr);
190 break;
191
192 case 'h' : /* Destination host */
193 if (argv[i][2] != '\0')
194 cupsSetServer(argv[i] + 2);
195 else
196 {
197 i ++;
198
199 if (i >= argc)
200 {
201 _cupsLangPuts(stderr, NULL,
202 _("lp: Expected hostname after -h option!\n"));
203 return (1);
204 }
205
206 cupsSetServer(argv[i]);
207 }
208 break;
209
210 case 'i' : /* Change job */
211 if (argv[i][2])
212 val = argv[i] + 2;
213 else
214 {
215 i ++;
216
217 if (i >= argc)
218 {
219 _cupsLangPuts(stderr, NULL,
220 _("lp: Expected job ID after -i option!\n"));
221 return (1);
222 }
223
224 val = argv[i];
225 }
226
227 if (num_files > 0)
228 {
229 _cupsLangPuts(stderr, NULL,
230 _("lp: Error - cannot print files and alter "
231 "jobs simultaneously!\n"));
232 return (1);
233 }
234
235 if (strrchr(val, '-') != NULL)
236 job_id = atoi(strrchr(val, '-') + 1);
237 else
238 job_id = atoi(val);
239
240 if (job_id < 0)
241 {
242 _cupsLangPuts(stderr, NULL, _("lp: Error - bad job ID!\n"));
243 break;
244 }
245 break;
246
247 case 'm' : /* Send email when job is done */
248#ifdef __sun
249 case 'p' : /* Notify on completion */
250#endif /* __sun */
251 case 'w' : /* Write to console or email */
252 break;
253
254 case 'n' : /* Number of copies */
255 if (argv[i][2] != '\0')
256 num_copies = atoi(argv[i] + 2);
257 else
258 {
259 i ++;
260
261 if (i >= argc)
262 {
263 _cupsLangPuts(stderr, NULL,
264 _("lp: Expected copies after -n option!\n"));
265 return (1);
266 }
267
268 num_copies = atoi(argv[i]);
269 }
270
271 sprintf(buffer, "%d", num_copies);
272 num_options = cupsAddOption("copies", buffer, num_options, &options);
273 break;
274
275 case 'o' : /* Option */
276 if (argv[i][2] != '\0')
277 num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
278 else
279 {
280 i ++;
281
282 if (i >= argc)
283 {
284 _cupsLangPuts(stderr, NULL,
285 _("lp: Expected option string after -o option!\n"));
286 return (1);
287 }
288
289 num_options = cupsParseOptions(argv[i], num_options, &options);
290 }
291 break;
292
293#ifndef __sun
294 case 'p' : /* Queue priority */
295#endif /* !__sun */
296 case 'q' : /* Queue priority */
297 if (argv[i][2] != '\0')
298 priority = atoi(argv[i] + 2);
299 else
300 {
301 if ((i + 1) >= argc)
302 {
303 _cupsLangPrintf(stderr, NULL,
304 _("lp: Expected priority after -%c option!\n"),
305 argv[i][1]);
306 return (1);
307 }
308
309 i ++;
310
311 priority = atoi(argv[i]);
312 }
313
314 /*
315 * For 100% Solaris compatibility, need to add:
316 *
317 * priority = 99 * (39 - priority) / 39 + 1;
318 *
319 * However, to keep CUPS lp the same across all platforms
320 * we will break compatibility this far...
321 */
322
323 if (priority < 1 || priority > 100)
324 {
325 _cupsLangPuts(stderr, NULL,
326 _("lp: Priority must be between 1 and 100.\n"));
327 return (1);
328 }
329
330 sprintf(buffer, "%d", priority);
331 num_options = cupsAddOption("job-priority", buffer, num_options, &options);
332 break;
333
334 case 's' : /* Silent */
335 silent = 1;
336 break;
337
338 case 't' : /* Title */
339 if (argv[i][2] != '\0')
340 title = argv[i] + 2;
341 else
342 {
343 i ++;
344
345 if (i >= argc)
346 {
347 _cupsLangPuts(stderr, NULL,
348 _("lp: Expected title after -t option!\n"));
349 return (1);
350 }
351
352 title = argv[i];
353 }
354 break;
355
356 case 'y' : /* mode-list */
357 if (!argv[i][2])
358 {
359 i ++;
360
361 if (i >= argc)
362 {
363 _cupsLangPuts(stderr, NULL,
364 _("lp: Expected mode list after -y option!\n"));
365 return (1);
366 }
367 }
368
369 _cupsLangPuts(stderr, NULL,
370 _("lp: Warning - mode option ignored!\n"));
371 break;
372
373 case 'H' : /* Hold job */
374 if (argv[i][2])
375 val = argv[i] + 2;
376 else
377 {
378 i ++;
379
380 if (i >= argc)
381 {
382 _cupsLangPuts(stderr, NULL,
383 _("lp: Expected hold name after -H option!\n"));
384 return (1);
385 }
386
387 val = argv[i];
388 }
389
390 if (!strcmp(val, "hold"))
391 num_options = cupsAddOption("job-hold-until", "indefinite",
392 num_options, &options);
393 else if (!strcmp(val, "resume") ||
394 !strcmp(val, "release"))
395 num_options = cupsAddOption("job-hold-until", "no-hold",
396 num_options, &options);
397 else if (!strcmp(val, "immediate"))
398 num_options = cupsAddOption("job-priority", "100",
399 num_options, &options);
400 else if (!strcmp(val, "restart"))
401 {
402 if (job_id < 1)
403 {
404 _cupsLangPuts(stderr, NULL,
405 _("lp: Need job ID (-i) before \"-H restart\"!\n"));
406 return (1);
407 }
408
409 if (restart_job(job_id))
410 return (1);
411 }
412 else
413 num_options = cupsAddOption("job-hold-until", val,
414 num_options, &options);
415 break;
416
417 case 'P' : /* Page list */
418 if (argv[i][2])
419 val = argv[i] + 2;
420 else
421 {
422 i ++;
423
424 if (i >= argc)
425 {
426 _cupsLangPuts(stderr, NULL,
427 _("lp: Expected page list after -P option!\n"));
428 return (1);
429 }
430
431 val = argv[i];
432 }
433
434 num_options = cupsAddOption("page-ranges", val, num_options,
435 &options);
436 break;
437
438 case 'S' : /* character set */
439 if (!argv[i][2])
440 {
441 i ++;
442
443 if (i >= argc)
444 {
445 _cupsLangPuts(stderr, NULL,
446 _("lp: Expected character set after -S option!\n"));
447 return (1);
448 }
449 }
450
451 _cupsLangPuts(stderr, NULL,
452 _("lp: Warning - character set option ignored!\n"));
453 break;
454
455 case 'T' : /* Content-Type */
456 if (!argv[i][2])
457 {
458 i ++;
459
460 if (i >= argc)
461 {
462 _cupsLangPuts(stderr, NULL,
463 _("lp: Expected content type after -T option!\n"));
464 return (1);
465 }
466 }
467
468 _cupsLangPuts(stderr, NULL,
469 _("lp: Warning - content type option ignored!\n"));
470 break;
471
472 default :
473 _cupsLangPrintf(stderr, NULL, _("lp: Unknown option \'%c\'!\n"),
474 argv[i][1]);
475 return (1);
476 }
477 else if (!strcmp(argv[i], "-"))
478 {
479 if (num_files || job_id)
480 {
481 _cupsLangPuts(stderr, NULL,
482 _("lp: Error - cannot print from stdin if files or a "
483 "job ID are provided!\n"));
484 return (1);
485 }
486
487 break;
488 }
489 else if (num_files < 1000 && job_id == 0)
490 {
491 /*
492 * Print a file...
493 */
494
495 if (access(argv[i], R_OK) != 0)
496 {
497 _cupsLangPrintf(stderr, NULL, _("lp: Unable to access \"%s\" - %s\n"),
498 argv[i], strerror(errno));
499 return (1);
500 }
501
502 files[num_files] = argv[i];
503 num_files ++;
504
505 if (title == NULL)
506 {
507 if ((title = strrchr(argv[i], '/')) != NULL)
508 title ++;
509 else
510 title = argv[i];
511 }
512 }
513 else
514 _cupsLangPrintf(stderr, NULL, _("lp: Too many files - \"%s\"\n"),
515 argv[i]);
516
517 /*
518 * See if we are altering an existing job...
519 */
520
521 if (job_id)
522 return (set_job_attrs(job_id, num_options, options));
523
524 /*
525 * See if we have any files to print; if not, print from stdin...
526 */
527
528 if (printer == NULL)
529 {
530 if (num_dests == 0)
531 num_dests = cupsGetDests(&dests);
532
533 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL)
534 {
535 printer = dest->name;
536
537 for (j = 0; j < dest->num_options; j ++)
538 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
539 num_options = cupsAddOption(dest->options[j].name,
540 dest->options[j].value,
541 num_options, &options);
542 }
543 }
544
545 if (printer == NULL)
546 {
547 val = NULL;
548
549 if ((printer = getenv("LPDEST")) == NULL)
550 {
551 if ((printer = getenv("PRINTER")) != NULL)
552 {
553 if (!strcmp(printer, "lp"))
554 printer = NULL;
555 else
556 val = "PRINTER";
557 }
558 }
559 else
560 val = "LPDEST";
561
562 if (printer && !cupsGetDest(printer, NULL, num_dests, dests))
563 _cupsLangPrintf(stderr, NULL,
564 _("lp: error - %s environment variable names "
565 "non-existent destination \"%s\"!\n"),
566 val, printer);
567 else if (cupsLastError() == IPP_NOT_FOUND)
568 _cupsLangPuts(stderr, NULL,
569 _("lp: error - no default destination available.\n"));
570 else
571 _cupsLangPuts(stderr, NULL,
572 _("lp: error - scheduler not responding!\n"));
573
574 return (1);
575 }
576
577 if (num_files > 0)
578 job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
579 else
580 {
581 num_files = 1;
582
583#ifndef WIN32
584# if defined(HAVE_SIGSET)
585 sigset(SIGHUP, sighandler);
586 if (sigset(SIGINT, sighandler) == SIG_IGN)
587 sigset(SIGINT, SIG_IGN);
588 sigset(SIGTERM, sighandler);
589# elif defined(HAVE_SIGACTION)
590 memset(&action, 0, sizeof(action));
591 action.sa_handler = sighandler;
592
593 sigaction(SIGHUP, &action, NULL);
594 sigaction(SIGINT, NULL, &oldaction);
595 if (oldaction.sa_handler != SIG_IGN)
596 sigaction(SIGINT, &action, NULL);
597 sigaction(SIGTERM, &action, NULL);
598# else
599 signal(SIGHUP, sighandler);
600 if (signal(SIGINT, sighandler) == SIG_IGN)
601 signal(SIGINT, SIG_IGN);
602 signal(SIGTERM, sighandler);
603# endif
604#endif /* !WIN32 */
605
606 temp = cupsTempFd(tempfile, sizeof(tempfile));
607
608 if (temp < 0)
609 {
610 _cupsLangPrintf(stderr, NULL,
611 _("lp: unable to create temporary file \"%s\" - %s\n"),
612 tempfile, strerror(errno));
613 return (1);
614 }
615
616 while ((i = read(0, buffer, sizeof(buffer))) > 0)
617 if (write(temp, buffer, i) < 0)
618 {
619 _cupsLangPrintf(stderr, NULL,
620 _("lp: error - unable to write to temporary file "
621 "\"%s\" - %s\n"),
622 tempfile, strerror(errno));
623 close(temp);
624 unlink(tempfile);
625 return (1);
626 }
627
628 i = lseek(temp, 0, SEEK_CUR);
629 close(temp);
630
631 if (i == 0)
632 {
633 _cupsLangPuts(stderr, NULL,
634 _("lp: stdin is empty, so no job has been sent.\n"));
635 unlink(tempfile);
636 return (1);
637 }
638
639 if (title)
640 job_id = cupsPrintFile(printer, tempfile, title, num_options, options);
641 else
642 job_id = cupsPrintFile(printer, tempfile, "(stdin)", num_options, options);
643
644 unlink(tempfile);
645 }
646
647 if (job_id < 1)
648 {
649 _cupsLangPrintf(stderr, NULL,
650 _("lp: unable to print file: %s\n"),
651 ippErrorString(cupsLastError()));
652 return (1);
653 }
654 else if (!silent)
655 _cupsLangPrintf(stdout, NULL,
656 _("request id is %s-%d (%d file(s))\n"),
657 printer, job_id, num_files);
658
659 return (0);
660}
661
662
663/*
664 * 'restart_job()' - Restart a job.
665 */
666
667int /* O - Exit status */
668restart_job(int job_id) /* I - Job ID */
669{
670 http_t *http; /* HTTP connection to server */
671 ipp_t *request, /* IPP request */
672 *response; /* IPP response */
673 cups_lang_t *language; /* Language for request */
674 char uri[HTTP_MAX_URI]; /* URI for job */
675
676
677 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
678
679 language = cupsLangDefault();
680
681 request = ippNew();
682 request->request.op.operation_id = IPP_RESTART_JOB;
683 request->request.op.request_id = 1;
684
685 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
686 "attributes-charset", NULL, cupsLangEncoding(language));
687
688 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
689 "attributes-natural-language", NULL, language->language);
690
691 sprintf(uri, "ipp://localhost/jobs/%d", job_id);
692
693 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
694 "job-uri", NULL, uri);
695
696 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
697 "requesting-user-name", NULL, cupsUser());
698
699 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL)
700 {
701 if (response->request.status.status_code > IPP_OK_CONFLICT)
702 {
703 _cupsLangPrintf(stderr, NULL, _("lp: restart-job failed: %s\n"),
704 ippErrorString(response->request.status.status_code));
705 ippDelete(response);
706 return (1);
707 }
708
709 ippDelete(response);
710 }
711 else
712 {
713 _cupsLangPrintf(stderr, NULL, _("lp: restart-job failed: %s\n"),
714 ippErrorString(cupsLastError()));
715 return (1);
716 }
717
718 return (0);
719}
720
721
722/*
723 * 'set_job_attrs()' - Set job attributes.
724 */
725
726int /* O - Exit status */
727set_job_attrs(int job_id, /* I - Job ID */
728 int num_options,/* I - Number of options */
729 cups_option_t *options) /* I - Options */
730{
731 http_t *http; /* HTTP connection to server */
732 ipp_t *request, /* IPP request */
733 *response; /* IPP response */
734 cups_lang_t *language; /* Language for request */
735 char uri[HTTP_MAX_URI]; /* URI for job */
736
737
738 if (num_options == 0)
739 return (0);
740
741 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
742
743 language = cupsLangDefault();
744
745 request = ippNew();
746 request->request.op.operation_id = IPP_SET_JOB_ATTRIBUTES;
747 request->request.op.request_id = 1;
748
749 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
750 "attributes-charset", NULL, cupsLangEncoding(language));
751
752 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
753 "attributes-natural-language", NULL, language->language);
754
755 sprintf(uri, "ipp://localhost/jobs/%d", job_id);
756
757 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
758 "job-uri", NULL, uri);
759
760 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
761 "requesting-user-name", NULL, cupsUser());
762
763 cupsEncodeOptions(request, num_options, options);
764
765 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL)
766 {
767 if (response->request.status.status_code > IPP_OK_CONFLICT)
768 {
769 _cupsLangPrintf(stderr, NULL, _("lp: set-job-attributes failed: %s\n"),
770 ippErrorString(response->request.status.status_code));
771 ippDelete(response);
772 return (1);
773 }
774
775 ippDelete(response);
776 }
777 else
778 {
779 _cupsLangPrintf(stderr, NULL, _("lp: set-job-attributes failed: %s\n"),
780 ippErrorString(cupsLastError()));
781 return (1);
782 }
783
784 return (0);
785}
786
787
788#ifndef WIN32
789/*
790 * 'sighandler()' - Signal catcher for when we print from stdin...
791 */
792
793void
794sighandler(int s) /* I - Signal number */
795{
796 /*
797 * Remove the temporary file we're using to print from stdin...
798 */
799
800 unlink(tempfile);
801
802 /*
803 * Exit...
804 */
805
806 exit(s);
807}
808#endif /* !WIN32 */
809
810
811/*
812 * End of "$Id: lp.c 4906 2006-01-10 20:53:28Z mike $".
813 */