]>
git.ipfire.org Git - thirdparty/cups.git/blob - systemv/lp.c
2 * "$Id: lp.c 5926 2006-09-05 20:45:47Z 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"))
120 _cupsSetLocale(argv
);
133 for (i
= 1; i
< argc
; i
++)
134 if (argv
[i
][0] == '-' && argv
[i
][1] && !end_options
)
137 case 'E' : /* Encrypt */
139 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED
);
141 _cupsLangPrintf(stderr
,
142 _("%s: Sorry, no encryption support compiled in!\n"),
144 #endif /* HAVE_SSL */
147 case 'U' : /* Username */
148 if (argv
[i
][2] != '\0')
149 cupsSetUser(argv
[i
] + 2);
155 _cupsLangPrintf(stderr
,
156 _("%s: Error - expected username after "
162 cupsSetUser(argv
[i
]);
166 case 'c' : /* Copy to spool dir (always enabled) */
169 case 'd' : /* Destination printer or class */
170 if (argv
[i
][2] != '\0')
171 printer
= argv
[i
] + 2;
178 _cupsLangPrintf(stderr
,
179 _("%s: Error - expected destination after "
188 if ((instance
= strrchr(printer
, '/')) != NULL
)
192 num_dests
= cupsGetDests(&dests
);
194 if ((dest
= cupsGetDest(printer
, instance
, num_dests
, dests
)) != NULL
)
196 for (j
= 0; j
< dest
->num_options
; j
++)
197 if (cupsGetOption(dest
->options
[j
].name
, num_options
, options
) == NULL
)
198 num_options
= cupsAddOption(dest
->options
[j
].name
,
199 dest
->options
[j
].value
,
200 num_options
, &options
);
204 case 'f' : /* Form */
211 _cupsLangPrintf(stderr
,
212 _("%s: Error - expected form after \'-f\' "
219 _cupsLangPrintf(stderr
, _("%s: Warning - form option ignored!\n"),
223 case 'h' : /* Destination host */
224 if (argv
[i
][2] != '\0')
225 cupsSetServer(argv
[i
] + 2);
232 _cupsLangPrintf(stderr
,
233 _("%s: Error - expected hostname after "
239 cupsSetServer(argv
[i
]);
243 case 'i' : /* Change job */
252 _cupsLangPrintf(stderr
,
253 _("%s: Expected job ID after \'-i\' option!\n"),
263 _cupsLangPrintf(stderr
,
264 _("%s: Error - cannot print files and alter "
265 "jobs simultaneously!\n"),
270 if (strrchr(val
, '-') != NULL
)
271 job_id
= atoi(strrchr(val
, '-') + 1);
277 _cupsLangPrintf(stderr
, _("%s: Error - bad job ID!\n"), argv
[0]);
282 case 'm' : /* Send email when job is done */
284 case 'p' : /* Notify on completion */
286 case 'w' : /* Write to console or email */
288 char email
[1024]; /* EMail address */
291 snprintf(email
, sizeof(email
), "mailto:%s@%s", cupsUser(),
292 httpGetHostname(NULL
, buffer
, sizeof(buffer
)));
293 num_options
= cupsAddOption("notify-recipient", email
,
294 num_options
, &options
);
300 case 'n' : /* Number of copies */
301 if (argv
[i
][2] != '\0')
302 num_copies
= atoi(argv
[i
] + 2);
309 _cupsLangPrintf(stderr
,
310 _("%s: Error - expected copies after "
316 num_copies
= atoi(argv
[i
]);
319 sprintf(buffer
, "%d", num_copies
);
320 num_options
= cupsAddOption("copies", buffer
, num_options
, &options
);
323 case 'o' : /* Option */
324 if (argv
[i
][2] != '\0')
325 num_options
= cupsParseOptions(argv
[i
] + 2, num_options
, &options
);
332 _cupsLangPrintf(stderr
,
333 _("%s: Error - expected option string after "
339 num_options
= cupsParseOptions(argv
[i
], num_options
, &options
);
344 case 'p' : /* Queue priority */
346 case 'q' : /* Queue priority */
347 if (argv
[i
][2] != '\0')
348 priority
= atoi(argv
[i
] + 2);
353 _cupsLangPrintf(stderr
,
354 _("%s: Error - expected priority after "
355 "\'-%c\' option!\n"),
356 argv
[0], argv
[i
][1]);
362 priority
= atoi(argv
[i
]);
366 * For 100% Solaris compatibility, need to add:
368 * priority = 99 * (39 - priority) / 39 + 1;
370 * However, to keep CUPS lp the same across all platforms
371 * we will break compatibility this far...
374 if (priority
< 1 || priority
> 100)
376 _cupsLangPrintf(stderr
,
377 _("%s: Error - priority must be between 1 and "
383 sprintf(buffer
, "%d", priority
);
384 num_options
= cupsAddOption("job-priority", buffer
, num_options
, &options
);
387 case 's' : /* Silent */
391 case 't' : /* Title */
392 if (argv
[i
][2] != '\0')
400 _cupsLangPrintf(stderr
,
401 _("%s: Error - expected title after "
411 case 'y' : /* mode-list */
418 _cupsLangPrintf(stderr
,
419 _("%s: Error - expected mode list after "
426 _cupsLangPrintf(stderr
,
427 _("%s: Warning - mode option ignored!\n"),
431 case 'H' : /* Hold job */
440 _cupsLangPrintf(stderr
,
441 _("%s: Error - expected hold name after "
450 if (!strcmp(val
, "hold"))
451 num_options
= cupsAddOption("job-hold-until", "indefinite",
452 num_options
, &options
);
453 else if (!strcmp(val
, "resume") ||
454 !strcmp(val
, "release"))
455 num_options
= cupsAddOption("job-hold-until", "no-hold",
456 num_options
, &options
);
457 else if (!strcmp(val
, "immediate"))
458 num_options
= cupsAddOption("job-priority", "100",
459 num_options
, &options
);
460 else if (!strcmp(val
, "restart"))
464 _cupsLangPrintf(stderr
,
465 _("%s: Need job ID (\'-i jobid\') before "
466 "\'-H restart\'!\n"),
471 if (restart_job(argv
[0], job_id
))
475 num_options
= cupsAddOption("job-hold-until", val
,
476 num_options
, &options
);
479 case 'P' : /* Page list */
488 _cupsLangPrintf(stderr
,
489 _("%s: Error - expected page list after "
498 num_options
= cupsAddOption("page-ranges", val
, num_options
,
502 case 'S' : /* character set */
509 _cupsLangPrintf(stderr
,
510 _("%s: Error - expected character set after "
517 _cupsLangPrintf(stderr
,
518 _("%s: Warning - character set option ignored!\n"),
522 case 'T' : /* Content-Type */
529 _cupsLangPrintf(stderr
,
530 _("%s: Error - expected content type after "
537 _cupsLangPrintf(stderr
,
538 _("%s: Warning - content type option ignored!\n"),
542 case '-' : /* Stop processing options */
547 _cupsLangPrintf(stderr
, _("%s: Error - unknown option \'%c\'!\n"),
548 argv
[0], argv
[i
][1]);
551 else if (!strcmp(argv
[i
], "-"))
553 if (num_files
|| job_id
)
555 _cupsLangPrintf(stderr
,
556 _("%s: Error - cannot print from stdin if files or a "
557 "job ID are provided!\n"),
564 else if (num_files
< 1000 && job_id
== 0)
570 if (access(argv
[i
], R_OK
) != 0)
572 _cupsLangPrintf(stderr
, _("%s: Error - unable to access \"%s\" - %s\n"),
573 argv
[0], argv
[i
], strerror(errno
));
577 files
[num_files
] = argv
[i
];
582 if ((title
= strrchr(argv
[i
], '/')) != NULL
)
589 _cupsLangPrintf(stderr
, _("%s: Error - too many files - \"%s\"\n"),
593 * See if we are altering an existing job...
597 return (set_job_attrs(argv
[0], job_id
, num_options
, options
));
600 * See if we have any files to print; if not, print from stdin...
606 num_dests
= cupsGetDests(&dests
);
608 if ((dest
= cupsGetDest(NULL
, NULL
, num_dests
, dests
)) != NULL
)
610 printer
= dest
->name
;
612 for (j
= 0; j
< dest
->num_options
; j
++)
613 if (cupsGetOption(dest
->options
[j
].name
, num_options
, options
) == NULL
)
614 num_options
= cupsAddOption(dest
->options
[j
].name
,
615 dest
->options
[j
].value
,
616 num_options
, &options
);
624 if ((printer
= getenv("LPDEST")) == NULL
)
626 if ((printer
= getenv("PRINTER")) != NULL
)
628 if (!strcmp(printer
, "lp"))
637 if (printer
&& !cupsGetDest(printer
, NULL
, num_dests
, dests
))
638 _cupsLangPrintf(stderr
,
639 _("%s: Error - %s environment variable names "
640 "non-existent destination \"%s\"!\n"),
641 argv
[0], val
, printer
);
642 else if (cupsLastError() == IPP_NOT_FOUND
)
643 _cupsLangPrintf(stderr
,
644 _("%s: Error - no default destination available.\n"),
647 _cupsLangPrintf(stderr
,
648 _("%s: Error - scheduler not responding!\n"),
655 job_id
= cupsPrintFiles(printer
, num_files
, files
, title
, num_options
, options
);
661 # if defined(HAVE_SIGSET)
662 sigset(SIGHUP
, sighandler
);
663 if (sigset(SIGINT
, sighandler
) == SIG_IGN
)
664 sigset(SIGINT
, SIG_IGN
);
665 sigset(SIGTERM
, sighandler
);
666 # elif defined(HAVE_SIGACTION)
667 memset(&action
, 0, sizeof(action
));
668 action
.sa_handler
= sighandler
;
670 sigaction(SIGHUP
, &action
, NULL
);
671 sigaction(SIGINT
, NULL
, &oldaction
);
672 if (oldaction
.sa_handler
!= SIG_IGN
)
673 sigaction(SIGINT
, &action
, NULL
);
674 sigaction(SIGTERM
, &action
, NULL
);
676 signal(SIGHUP
, sighandler
);
677 if (signal(SIGINT
, sighandler
) == SIG_IGN
)
678 signal(SIGINT
, SIG_IGN
);
679 signal(SIGTERM
, sighandler
);
683 temp
= cupsTempFd(tempfile
, sizeof(tempfile
));
687 _cupsLangPrintf(stderr
,
688 _("%s: Error - unable to create temporary file \"%s\" - %s\n"),
689 argv
[0], tempfile
, strerror(errno
));
693 while ((bytes
= read(0, buffer
, sizeof(buffer
))) > 0)
694 if (write(temp
, buffer
, bytes
) < 0)
696 _cupsLangPrintf(stderr
,
697 _("%s: Error - unable to write to temporary file "
699 argv
[0], tempfile
, strerror(errno
));
705 filesize
= lseek(temp
, 0, SEEK_CUR
);
710 _cupsLangPrintf(stderr
,
711 _("%s: Error - stdin is empty, so no job has been sent.\n"),
718 job_id
= cupsPrintFile(printer
, tempfile
, title
, num_options
, options
);
720 job_id
= cupsPrintFile(printer
, tempfile
, "(stdin)", num_options
, options
);
727 _cupsLangPrintf(stderr
, "%s: %s\n", argv
[0], cupsLastErrorString());
731 _cupsLangPrintf(stdout
, _("request id is %s-%d (%d file(s))\n"),
732 printer
, job_id
, num_files
);
739 * 'restart_job()' - Restart a job.
742 int /* O - Exit status */
743 restart_job(const char *command
, /* I - Command name */
744 int job_id
) /* I - Job ID */
746 http_t
*http
; /* HTTP connection to server */
747 ipp_t
*request
; /* IPP request */
748 char uri
[HTTP_MAX_URI
]; /* URI for job */
751 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
753 request
= ippNewRequest(IPP_RESTART_JOB
);
755 sprintf(uri
, "ipp://localhost/jobs/%d", job_id
);
757 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
758 "job-uri", NULL
, uri
);
760 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
761 "requesting-user-name", NULL
, cupsUser());
763 ippDelete(cupsDoRequest(http
, request
, "/jobs"));
765 if (cupsLastError() > IPP_OK_CONFLICT
)
767 _cupsLangPrintf(stderr
, "%s: %s\n", command
, cupsLastErrorString());
776 * 'set_job_attrs()' - Set job attributes.
779 int /* O - Exit status */
780 set_job_attrs(const char *command
, /* I - Command name */
781 int job_id
, /* I - Job ID */
782 int num_options
,/* I - Number of options */
783 cups_option_t
*options
) /* I - Options */
785 http_t
*http
; /* HTTP connection to server */
786 ipp_t
*request
; /* IPP request */
787 char uri
[HTTP_MAX_URI
]; /* URI for job */
790 if (num_options
== 0)
793 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
795 request
= ippNewRequest(IPP_SET_JOB_ATTRIBUTES
);
797 sprintf(uri
, "ipp://localhost/jobs/%d", job_id
);
799 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
800 "job-uri", NULL
, uri
);
802 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
803 "requesting-user-name", NULL
, cupsUser());
805 cupsEncodeOptions(request
, num_options
, options
);
807 ippDelete(cupsDoRequest(http
, request
, "/jobs"));
809 if (cupsLastError() > IPP_OK_CONFLICT
)
811 _cupsLangPrintf(stderr
, "%s: %s\n", command
, cupsLastErrorString());
821 * 'sighandler()' - Signal catcher for when we print from stdin...
825 sighandler(int s
) /* I - Signal number */
828 * Remove the temporary file we're using to print from stdin...
843 * End of "$Id: lp.c 5926 2006-09-05 20:45:47Z mike $".