]>
git.ipfire.org Git - thirdparty/cups.git/blob - systemv/lp.c
2 * "$Id: lp.c 4974 2006-01-25 07:04:33Z mike $"
4 * "lp" command for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
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...
33 * Include necessary headers...
39 #include <cups/string.h>
40 #include <cups/cups.h>
41 #include <cups/i18n.h>
55 int restart_job(const char *command
, int job_id
);
56 int set_job_attrs(const char *command
, int job_id
, int num_options
,
57 cups_option_t
*options
);
64 char tempfile
[1024]; /* Temporary file for printing from stdin */
68 * 'main()' - Parse options and send files for printing.
72 main(int argc
, /* I - Number of command-line arguments */
73 char *argv
[]) /* I - Command-line arguments */
75 int i
, j
; /* Looping vars */
76 int job_id
; /* Job ID */
77 char *printer
, /* Printer name */
78 *instance
, /* Instance name */
79 *val
, /* Option value */
80 *title
; /* Job title */
81 int priority
; /* Job priority (1-100) */
82 int num_copies
; /* Number of copies per file */
83 int num_files
; /* Number of files to print */
84 const char *files
[1000]; /* Files to print */
85 int num_dests
; /* Number of destinations */
86 cups_dest_t
*dests
, /* Destinations */
87 *dest
; /* Selected destination */
88 int num_options
; /* Number of options */
89 cups_option_t
*options
; /* Options */
90 int end_options
; /* No more options? */
91 int silent
; /* Silent or verbose output? */
92 char buffer
[8192]; /* Copy buffer */
93 ssize_t bytes
; /* Bytes copied */
94 off_t filesize
; /* Size of temp file */
95 int temp
; /* Temporary file descriptor */
96 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
97 struct sigaction action
; /* Signal action */
98 struct sigaction oldaction
; /* Old signal action */
99 #endif /* HAVE_SIGACTION && !HAVE_SIGSET*/
104 * Solaris does some rather strange things to re-queue remote print
105 * jobs. On bootup, the "lp" command is run as "printd" to re-spool
106 * any remote jobs in /var/spool/print. Since CUPS doesn't need this
107 * nonsense, we just need to add the necessary check here to prevent
108 * lp from causing boot problems...
111 if ((val
= strrchr(argv
[0], '/')) != NULL
)
116 if (!strcmp(val
, "printd"))
131 for (i
= 1; i
< argc
; i
++)
132 if (argv
[i
][0] == '-' && argv
[i
][1] && !end_options
)
135 case 'E' : /* Encrypt */
137 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED
);
139 _cupsLangPrintf(stderr
,
140 _("%s: Sorry, no encryption support compiled in!\n"),
142 #endif /* HAVE_SSL */
145 case 'U' : /* Username */
146 if (argv
[i
][2] != '\0')
147 cupsSetUser(argv
[i
] + 2);
153 _cupsLangPrintf(stderr
,
154 _("%s: Error - expected username after "
160 cupsSetUser(argv
[i
]);
164 case 'c' : /* Copy to spool dir (always enabled) */
167 case 'd' : /* Destination printer or class */
168 if (argv
[i
][2] != '\0')
169 printer
= argv
[i
] + 2;
176 _cupsLangPrintf(stderr
,
177 _("%s: Error - expected destination after "
186 if ((instance
= strrchr(printer
, '/')) != NULL
)
190 num_dests
= cupsGetDests(&dests
);
192 if ((dest
= cupsGetDest(printer
, instance
, num_dests
, dests
)) != NULL
)
194 for (j
= 0; j
< dest
->num_options
; j
++)
195 if (cupsGetOption(dest
->options
[j
].name
, num_options
, options
) == NULL
)
196 num_options
= cupsAddOption(dest
->options
[j
].name
,
197 dest
->options
[j
].value
,
198 num_options
, &options
);
202 case 'f' : /* Form */
209 _cupsLangPrintf(stderr
,
210 _("%s: Error - expected form after \'-f\' "
217 _cupsLangPrintf(stderr
, _("%s: Warning - form option ignored!\n"),
221 case 'h' : /* Destination host */
222 if (argv
[i
][2] != '\0')
223 cupsSetServer(argv
[i
] + 2);
230 _cupsLangPrintf(stderr
,
231 _("%s: Error - expected hostname after "
237 cupsSetServer(argv
[i
]);
241 case 'i' : /* Change job */
250 _cupsLangPrintf(stderr
,
251 _("%s: Expected job ID after \'-i\' option!\n"),
261 _cupsLangPrintf(stderr
,
262 _("%s: Error - cannot print files and alter "
263 "jobs simultaneously!\n"),
268 if (strrchr(val
, '-') != NULL
)
269 job_id
= atoi(strrchr(val
, '-') + 1);
275 _cupsLangPrintf(stderr
, _("%s: Error - bad job ID!\n"), argv
[0]);
280 case 'm' : /* Send email when job is done */
282 case 'p' : /* Notify on completion */
284 case 'w' : /* Write to console or email */
286 char email
[1024]; /* EMail address */
289 snprintf(email
, sizeof(email
), "mailto:%s@%s", cupsUser(),
290 httpGetHostname(buffer
, sizeof(buffer
)));
291 num_options
= cupsAddOption("notify-recipient", email
,
292 num_options
, &options
);
298 case 'n' : /* Number of copies */
299 if (argv
[i
][2] != '\0')
300 num_copies
= atoi(argv
[i
] + 2);
307 _cupsLangPrintf(stderr
,
308 _("%s: Error - expected copies after "
314 num_copies
= atoi(argv
[i
]);
317 sprintf(buffer
, "%d", num_copies
);
318 num_options
= cupsAddOption("copies", buffer
, num_options
, &options
);
321 case 'o' : /* Option */
322 if (argv
[i
][2] != '\0')
323 num_options
= cupsParseOptions(argv
[i
] + 2, num_options
, &options
);
330 _cupsLangPrintf(stderr
,
331 _("%s: Error - expected option string after "
337 num_options
= cupsParseOptions(argv
[i
], num_options
, &options
);
342 case 'p' : /* Queue priority */
344 case 'q' : /* Queue priority */
345 if (argv
[i
][2] != '\0')
346 priority
= atoi(argv
[i
] + 2);
351 _cupsLangPrintf(stderr
,
352 _("%s: Error - expected priority after "
353 "\'-%c\' option!\n"),
354 argv
[0], argv
[i
][1]);
360 priority
= atoi(argv
[i
]);
364 * For 100% Solaris compatibility, need to add:
366 * priority = 99 * (39 - priority) / 39 + 1;
368 * However, to keep CUPS lp the same across all platforms
369 * we will break compatibility this far...
372 if (priority
< 1 || priority
> 100)
374 _cupsLangPrintf(stderr
,
375 _("%s: Error - priority must be between 1 and "
381 sprintf(buffer
, "%d", priority
);
382 num_options
= cupsAddOption("job-priority", buffer
, num_options
, &options
);
385 case 's' : /* Silent */
389 case 't' : /* Title */
390 if (argv
[i
][2] != '\0')
398 _cupsLangPrintf(stderr
,
399 _("%s: Error - expected title after "
409 case 'y' : /* mode-list */
416 _cupsLangPrintf(stderr
,
417 _("%s: Error - expected mode list after "
424 _cupsLangPrintf(stderr
,
425 _("%s: Warning - mode option ignored!\n"),
429 case 'H' : /* Hold job */
438 _cupsLangPrintf(stderr
,
439 _("%s: Error - expected hold name after "
448 if (!strcmp(val
, "hold"))
449 num_options
= cupsAddOption("job-hold-until", "indefinite",
450 num_options
, &options
);
451 else if (!strcmp(val
, "resume") ||
452 !strcmp(val
, "release"))
453 num_options
= cupsAddOption("job-hold-until", "no-hold",
454 num_options
, &options
);
455 else if (!strcmp(val
, "immediate"))
456 num_options
= cupsAddOption("job-priority", "100",
457 num_options
, &options
);
458 else if (!strcmp(val
, "restart"))
462 _cupsLangPrintf(stderr
,
463 _("%s: Need job ID (\'-i jobid\') before "
464 "\'-H restart\'!\n"),
469 if (restart_job(argv
[0], job_id
))
473 num_options
= cupsAddOption("job-hold-until", val
,
474 num_options
, &options
);
477 case 'P' : /* Page list */
486 _cupsLangPrintf(stderr
,
487 _("%s: Error - expected page list after "
496 num_options
= cupsAddOption("page-ranges", val
, num_options
,
500 case 'S' : /* character set */
507 _cupsLangPrintf(stderr
,
508 _("%s: Error - expected character set after "
515 _cupsLangPrintf(stderr
,
516 _("%s: Warning - character set option ignored!\n"),
520 case 'T' : /* Content-Type */
527 _cupsLangPrintf(stderr
,
528 _("%s: Error - expected content type after "
535 _cupsLangPrintf(stderr
,
536 _("%s: Warning - content type option ignored!\n"),
540 case '-' : /* Stop processing options */
545 _cupsLangPrintf(stderr
, _("%s: Error - unknown option \'%c\'!\n"),
546 argv
[0], argv
[i
][1]);
549 else if (!strcmp(argv
[i
], "-"))
551 if (num_files
|| job_id
)
553 _cupsLangPrintf(stderr
,
554 _("%s: Error - cannot print from stdin if files or a "
555 "job ID are provided!\n"),
562 else if (num_files
< 1000 && job_id
== 0)
568 if (access(argv
[i
], R_OK
) != 0)
570 _cupsLangPrintf(stderr
, _("%s: Error - unable to access \"%s\" - %s\n"),
571 argv
[0], argv
[i
], strerror(errno
));
575 files
[num_files
] = argv
[i
];
580 if ((title
= strrchr(argv
[i
], '/')) != NULL
)
587 _cupsLangPrintf(stderr
, _("%s: Error - too many files - \"%s\"\n"),
591 * See if we are altering an existing job...
595 return (set_job_attrs(argv
[0], job_id
, num_options
, options
));
598 * See if we have any files to print; if not, print from stdin...
604 num_dests
= cupsGetDests(&dests
);
606 if ((dest
= cupsGetDest(NULL
, NULL
, num_dests
, dests
)) != NULL
)
608 printer
= dest
->name
;
610 for (j
= 0; j
< dest
->num_options
; j
++)
611 if (cupsGetOption(dest
->options
[j
].name
, num_options
, options
) == NULL
)
612 num_options
= cupsAddOption(dest
->options
[j
].name
,
613 dest
->options
[j
].value
,
614 num_options
, &options
);
622 if ((printer
= getenv("LPDEST")) == NULL
)
624 if ((printer
= getenv("PRINTER")) != NULL
)
626 if (!strcmp(printer
, "lp"))
635 if (printer
&& !cupsGetDest(printer
, NULL
, num_dests
, dests
))
636 _cupsLangPrintf(stderr
,
637 _("%s: Error - %s environment variable names "
638 "non-existent destination \"%s\"!\n"),
639 argv
[0], val
, printer
);
640 else if (cupsLastError() == IPP_NOT_FOUND
)
641 _cupsLangPrintf(stderr
,
642 _("%s: Error - no default destination available.\n"),
645 _cupsLangPrintf(stderr
,
646 _("%s: Error - scheduler not responding!\n"),
653 job_id
= cupsPrintFiles(printer
, num_files
, files
, title
, num_options
, options
);
659 # if defined(HAVE_SIGSET)
660 sigset(SIGHUP
, sighandler
);
661 if (sigset(SIGINT
, sighandler
) == SIG_IGN
)
662 sigset(SIGINT
, SIG_IGN
);
663 sigset(SIGTERM
, sighandler
);
664 # elif defined(HAVE_SIGACTION)
665 memset(&action
, 0, sizeof(action
));
666 action
.sa_handler
= sighandler
;
668 sigaction(SIGHUP
, &action
, NULL
);
669 sigaction(SIGINT
, NULL
, &oldaction
);
670 if (oldaction
.sa_handler
!= SIG_IGN
)
671 sigaction(SIGINT
, &action
, NULL
);
672 sigaction(SIGTERM
, &action
, NULL
);
674 signal(SIGHUP
, sighandler
);
675 if (signal(SIGINT
, sighandler
) == SIG_IGN
)
676 signal(SIGINT
, SIG_IGN
);
677 signal(SIGTERM
, sighandler
);
681 temp
= cupsTempFd(tempfile
, sizeof(tempfile
));
685 _cupsLangPrintf(stderr
,
686 _("%s: Error - unable to create temporary file \"%s\" - %s\n"),
687 argv
[0], tempfile
, strerror(errno
));
691 while ((bytes
= read(0, buffer
, sizeof(buffer
))) > 0)
692 if (write(temp
, buffer
, bytes
) < 0)
694 _cupsLangPrintf(stderr
,
695 _("%s: Error - unable to write to temporary file "
697 argv
[0], tempfile
, strerror(errno
));
703 filesize
= lseek(temp
, 0, SEEK_CUR
);
708 _cupsLangPrintf(stderr
,
709 _("%s: Error - stdin is empty, so no job has been sent.\n"),
716 job_id
= cupsPrintFile(printer
, tempfile
, title
, num_options
, options
);
718 job_id
= cupsPrintFile(printer
, tempfile
, "(stdin)", num_options
, options
);
725 _cupsLangPrintf(stderr
, "%s: %s\n", argv
[0], cupsLastErrorString());
729 _cupsLangPrintf(stdout
, _("request id is %s-%d (%d file(s))\n"),
730 printer
, job_id
, num_files
);
737 * 'restart_job()' - Restart a job.
740 int /* O - Exit status */
741 restart_job(const char *command
, /* I - Command name */
742 int job_id
) /* I - Job ID */
744 http_t
*http
; /* HTTP connection to server */
745 ipp_t
*request
; /* IPP request */
746 char uri
[HTTP_MAX_URI
]; /* URI for job */
749 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
751 request
= ippNewRequest(IPP_RESTART_JOB
);
753 sprintf(uri
, "ipp://localhost/jobs/%d", job_id
);
755 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
756 "job-uri", NULL
, uri
);
758 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
759 "requesting-user-name", NULL
, cupsUser());
761 ippDelete(cupsDoRequest(http
, request
, "/jobs"));
763 if (cupsLastError() > IPP_OK_CONFLICT
)
765 _cupsLangPrintf(stderr
, "%s: %s\n", command
, cupsLastErrorString());
774 * 'set_job_attrs()' - Set job attributes.
777 int /* O - Exit status */
778 set_job_attrs(const char *command
, /* I - Command name */
779 int job_id
, /* I - Job ID */
780 int num_options
,/* I - Number of options */
781 cups_option_t
*options
) /* I - Options */
783 http_t
*http
; /* HTTP connection to server */
784 ipp_t
*request
; /* IPP request */
785 char uri
[HTTP_MAX_URI
]; /* URI for job */
788 if (num_options
== 0)
791 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
793 request
= ippNewRequest(IPP_SET_JOB_ATTRIBUTES
);
795 sprintf(uri
, "ipp://localhost/jobs/%d", job_id
);
797 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
798 "job-uri", NULL
, uri
);
800 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
801 "requesting-user-name", NULL
, cupsUser());
803 cupsEncodeOptions(request
, num_options
, options
);
805 ippDelete(cupsDoRequest(http
, request
, "/jobs"));
807 if (cupsLastError() > IPP_OK_CONFLICT
)
809 _cupsLangPrintf(stderr
, "%s: %s\n", command
, cupsLastErrorString());
819 * 'sighandler()' - Signal catcher for when we print from stdin...
823 sighandler(int s
) /* I - Signal number */
826 * Remove the temporary file we're using to print from stdin...
841 * End of "$Id: lp.c 4974 2006-01-25 07:04:33Z mike $".