]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/lp.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / systemv / lp.c
CommitLineData
7b4a1417 1/*
bcf61448 2 * "$Id: lp.c,v 1.29.2.11 2003/01/15 04:25:57 mike Exp $"
7b4a1417 3 *
4 * "lp" command for the Common UNIX Printing System (CUPS).
5 *
1d9595ab 6 * Copyright 1997-2003 by Easy Software Products.
7b4a1417 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
146949f8 17 * 44141 Airport View Drive, Suite 204
7b4a1417 18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
8dbf3e6a 26 * main() - Parse options and send files for printing.
27 * sighandler() - Signal catcher for when we print from stdin...
7b4a1417 28 */
29
30/*
31 * Include necessary headers...
32 */
33
34#include <stdio.h>
35#include <stdlib.h>
3b8ff70f 36#include <errno.h>
7b4a1417 37#include <cups/cups.h>
0b340d2d 38#include <cups/string.h>
effdc824 39#include <cups/language.h>
7b4a1417 40
41
8dbf3e6a 42#ifndef WIN32
3b8ff70f 43# include <unistd.h>
8dbf3e6a 44# include <signal.h>
45
46
47/*
48 * Local functions.
49 */
50
977acbd3 51void sighandler(int);
8dbf3e6a 52#endif /* !WIN32 */
d37c31b8 53int set_job_attrs(int job_id, int num_options, cups_option_t *options);
8dbf3e6a 54
55
56/*
57 * Globals...
58 */
59
60char tempfile[1024]; /* Temporary file for printing from stdin */
61
62
7b4a1417 63/*
64 * 'main()' - Parse options and send files for printing.
65 */
66
67int
68main(int argc, /* I - Number of command-line arguments */
69 char *argv[]) /* I - Command-line arguments */
70{
3d06d12f 71 int i, j; /* Looping vars */
7b4a1417 72 int job_id; /* Job ID */
3d06d12f 73 char *printer, /* Printer name */
d37c31b8 74 *instance, /* Instance name */
75 *val, /* Option value */
76 *title; /* Job title */
7b4a1417 77 int priority; /* Job priority (1-100) */
78 int num_copies; /* Number of copies per file */
fb577685 79 int num_files; /* Number of files to print */
80 const char *files[1000]; /* Files to print */
dd0f599a 81 int num_dests; /* Number of destinations */
82 cups_dest_t *dests, /* Destinations */
3d06d12f 83 *dest; /* Selected destination */
7b4a1417 84 int num_options; /* Number of options */
85 cups_option_t *options; /* Options */
86 int silent; /* Silent or verbose output? */
7b4a1417 87 char buffer[8192]; /* Copy buffer */
1b5bf964 88 int temp; /* Temporary file descriptor */
8a2c2126 89#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
977acbd3 90 struct sigaction action; /* Signal action */
576b82ca 91 struct sigaction oldaction; /* Old signal action */
8a2c2126 92#endif /* HAVE_SIGACTION && !HAVE_SIGSET*/
7b4a1417 93
94
df7507f5 95#ifdef __sun
96 /*
97 * Solaris does some rather strange things to re-queue remote print
98 * jobs. On bootup, the "lp" command is run as "printd" to re-spool
99 * any remote jobs in /var/spool/print. Since CUPS doesn't need this
100 * nonsense, we just need to add the necessary check here to prevent
101 * lp from causing boot problems...
102 */
103
104 if ((val = strrchr(argv[0], '/')) != NULL)
105 val ++;
106 else
107 val = argv[0];
108
109 if (strcmp(val, "printd") == 0)
110 return (0);
111#endif /* __sun */
112
7b4a1417 113 silent = 0;
3d06d12f 114 printer = NULL;
115 num_dests = 0;
116 dests = NULL;
7b4a1417 117 num_options = 0;
118 options = NULL;
119 num_files = 0;
b310a06a 120 title = NULL;
d37c31b8 121 job_id = 0;
7b4a1417 122
123 for (i = 1; i < argc; i ++)
124 if (argv[i][0] == '-')
125 switch (argv[i][1])
126 {
1c9e0181 127 case 'E' : /* Encrypt */
bcf61448 128#ifdef HAVE_SSL
1c9e0181 129 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
130#else
131 fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
132 argv[0]);
bcf61448 133#endif /* HAVE_SSL */
1c9e0181 134 break;
135
7b4a1417 136 case 'c' : /* Copy to spool dir (always enabled) */
137 break;
138
139 case 'd' : /* Destination printer or class */
140 if (argv[i][2] != '\0')
3d06d12f 141 printer = argv[i] + 2;
7b4a1417 142 else
143 {
144 i ++;
d37c31b8 145
146 if (i >= argc)
147 {
148 fputs("lp: Expected destination after -d option!\n", stderr);
149 return (1);
150 }
151
3d06d12f 152 printer = argv[i];
153 }
154
155 if ((instance = strrchr(printer, '/')) != NULL)
156 *instance++ = '\0';
157
158 if (num_dests == 0)
159 num_dests = cupsGetDests(&dests);
160
161 if ((dest = cupsGetDest(printer, instance, num_dests, dests)) != NULL)
162 {
163 for (j = 0; j < dest->num_options; j ++)
e8973392 164 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
165 num_options = cupsAddOption(dest->options[j].name,
166 dest->options[j].value,
167 num_options, &options);
7b4a1417 168 }
169 break;
170
d37c31b8 171 case 'f' : /* Form */
172 if (!argv[i][2])
173 {
174 i ++;
175
176 if (i >= argc)
177 {
178 fputs("lp: Expected form after -f option!\n", stderr);
179 return (1);
180 }
181 }
182
183 fputs("lp: Warning - form option ignored!\n", stderr);
184 break;
185
0b340d2d 186 case 'h' : /* Destination host */
187 if (argv[i][2] != '\0')
d37c31b8 188 cupsSetServer(argv[i] + 2);
0b340d2d 189 else
190 {
191 i ++;
d37c31b8 192
193 if (i >= argc)
194 {
195 fputs("lp: Expected hostname after -h option!\n", stderr);
196 return (1);
197 }
198
199 cupsSetServer(argv[i]);
200 }
201 break;
202
203 case 'i' : /* Change job */
204 if (argv[i][2])
205 val = argv[i] + 2;
206 else
207 {
208 i ++;
209
210 if (i >= argc)
211 {
212 fputs("lp: Expected job ID after -i option!\n", stderr);
213 return (1);
214 }
215
216 val = argv[i];
217 }
218
219 if (num_files > 0)
220 {
221 fputs("lp: Error - cannot print files and alter jobs simultaneously!\n", stderr);
222 return (1);
223 }
224
225 if (strrchr(val, '-') != NULL)
226 job_id = atoi(strrchr(val, '-') + 1);
227 else
228 job_id = atoi(val);
229
230 if (job_id < 0)
231 {
232 fputs("lp: Error - bad job ID!\n", stderr);
233 break;
0b340d2d 234 }
0b340d2d 235 break;
236
7b4a1417 237 case 'm' : /* Send email when job is done */
d37c31b8 238#ifdef __sun
239 case 'p' : /* Notify on completion */
240#endif /* __sun */
7b4a1417 241 case 'w' : /* Write to console or email */
242 break;
243
244 case 'n' : /* Number of copies */
245 if (argv[i][2] != '\0')
246 num_copies = atoi(argv[i] + 2);
247 else
248 {
249 i ++;
d37c31b8 250
251 if (i >= argc)
252 {
253 fputs("lp: Expected copies after -n option!\n", stderr);
254 return (1);
255 }
256
7b4a1417 257 num_copies = atoi(argv[i]);
258 }
259
8f70d036 260 sprintf(buffer, "%d", num_copies);
261 num_options = cupsAddOption("copies", buffer, num_options, &options);
7b4a1417 262 break;
263
264 case 'o' : /* Option */
265 if (argv[i][2] != '\0')
266 num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
267 else
268 {
269 i ++;
d37c31b8 270
271 if (i >= argc)
272 {
273 fputs("lp: Expected option string after -o option!\n", stderr);
274 return (1);
275 }
276
7b4a1417 277 num_options = cupsParseOptions(argv[i], num_options, &options);
278 }
279 break;
280
d37c31b8 281#ifndef __sun
1738443a 282 case 'p' : /* Queue priority */
d37c31b8 283#endif /* !__sun */
7b4a1417 284 case 'q' : /* Queue priority */
285 if (argv[i][2] != '\0')
286 priority = atoi(argv[i] + 2);
287 else
288 {
f2320e2d 289 if ((i + 1) >= argc)
d37c31b8 290 {
291 fprintf(stderr, "lp: Expected priority after -%c option!\n",
292 argv[i][1]);
293 return (1);
294 }
295
f2320e2d 296 i ++;
297
7b4a1417 298 priority = atoi(argv[i]);
299 }
300
d37c31b8 301 /*
302 * For 100% Solaris compatibility, need to add:
303 *
304 * priority = 99 * (39 - priority) / 39 + 1;
305 *
306 * However, to keep CUPS lp the same across all platforms
307 * we will break compatibility this far...
308 */
309
7b4a1417 310 if (priority < 1 || priority > 100)
311 {
312 fputs("lp: Priority must be between 1 and 100.\n", stderr);
313 return (1);
314 }
8f70d036 315
316 sprintf(buffer, "%d", priority);
317 num_options = cupsAddOption("job-priority", buffer, num_options, &options);
7b4a1417 318 break;
319
320 case 's' : /* Silent */
321 silent = 1;
322 break;
323
324 case 't' : /* Title */
325 if (argv[i][2] != '\0')
326 title = argv[i] + 2;
327 else
328 {
329 i ++;
d37c31b8 330
331 if (i >= argc)
332 {
333 fputs("lp: Expected title after -t option!\n", stderr);
334 return (1);
335 }
336
7b4a1417 337 title = argv[i];
338 }
339 break;
340
d37c31b8 341 case 'y' : /* mode-list */
342 if (!argv[i][2])
343 {
344 i ++;
345
346 if (i >= argc)
347 {
348 fputs("lp: Expected mode list after -y option!\n", stderr);
349 return (1);
350 }
351 }
352
353 fputs("lp: Warning - mode option ignored!\n", stderr);
354 break;
355
356 case 'H' : /* Hold job */
357 if (argv[i][2])
358 val = argv[i] + 2;
359 else
360 {
361 i ++;
362
363 if (i >= argc)
364 {
365 fputs("lp: Expected hold name after -H option!\n", stderr);
366 return (1);
367 }
368
369 val = argv[i];
370 }
371
372 if (strcmp(val, "hold") == 0)
373 num_options = cupsAddOption("job-hold-until", "indefinite",
374 num_options, &options);
753453e4 375 else if (strcmp(val, "resume") == 0 ||
376 strcmp(val, "release") == 0)
377 num_options = cupsAddOption("job-hold-until", "no-hold",
d37c31b8 378 num_options, &options);
379 else if (strcmp(val, "immediate") == 0)
380 num_options = cupsAddOption("job-priority", "100",
381 num_options, &options);
382 else
383 num_options = cupsAddOption("job-hold-until", val,
384 num_options, &options);
385 break;
386
387 case 'P' : /* Page list */
388 if (argv[i][2])
389 val = argv[i] + 2;
390 else
391 {
392 i ++;
393
394 if (i >= argc)
395 {
396 fputs("lp: Expected page list after -P option!\n", stderr);
397 return (1);
398 }
399
400 val = argv[i];
401 }
402
403 num_options = cupsAddOption("page-ranges", val, num_options,
404 &options);
405 break;
406
407 case 'S' : /* character set */
408 if (!argv[i][2])
409 {
410 i ++;
411
412 if (i >= argc)
413 {
414 fputs("lp: Expected character set after -S option!\n", stderr);
415 return (1);
416 }
417 }
418
419 fputs("lp: Warning - character set option ignored!\n", stderr);
420 break;
421
422 case 'T' : /* Content-Type */
423 if (!argv[i][2])
424 {
425 i ++;
426
427 if (i >= argc)
428 {
429 fputs("lp: Expected content type after -T option!\n", stderr);
430 return (1);
431 }
432 }
433
434 fputs("lp: Warning - content type option ignored!\n", stderr);
435 break;
436
7b4a1417 437 default :
438 fprintf(stderr, "lp: Unknown option \'%c\'!\n", argv[i][1]);
439 return (1);
440 }
d37c31b8 441 else if (num_files < 1000 && job_id == 0)
7b4a1417 442 {
b310a06a 443 /*
444 * Print a file...
445 */
7b4a1417 446
3b8ff70f 447 if (access(argv[i], R_OK) != 0)
448 {
449 fprintf(stderr, "lp: Unable to access \"%s\" - %s\n", argv[i],
450 strerror(errno));
451 return (1);
452 }
453
fb577685 454 files[num_files] = argv[i];
b310a06a 455 num_files ++;
146949f8 456
fb577685 457 if (title == NULL)
b310a06a 458 {
fb577685 459 if ((title = strrchr(argv[i], '/')) != NULL)
460 title ++;
461 else
462 title = argv[i];
b310a06a 463 }
7b4a1417 464 }
fb577685 465 else
466 fprintf(stderr, "lp: Too many files - \"%s\"\n", argv[i]);
7b4a1417 467
d37c31b8 468 /*
469 * See if we are altering an existing job...
470 */
471
472 if (job_id)
473 return (set_job_attrs(job_id, num_options, options));
474
7b4a1417 475 /*
fb577685 476 * See if we have any files to print; if not, print from stdin...
7b4a1417 477 */
478
fb577685 479 if (printer == NULL)
7b4a1417 480 {
fb577685 481 if (num_dests == 0)
482 num_dests = cupsGetDests(&dests);
0b340d2d 483
fb577685 484 for (j = 0, dest = dests; j < num_dests; j ++, dest ++)
485 if (dest->is_default)
486 {
487 printer = dests[j].name;
488
489 for (j = 0; j < dest->num_options; j ++)
e8973392 490 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
491 num_options = cupsAddOption(dest->options[j].name,
492 dest->options[j].value,
493 num_options, &options);
fb577685 494 break;
495 }
496 }
497
498 if (printer == NULL)
499 {
500 fputs("lp: error - no default destination available.\n", stderr);
501 return (1);
502 }
503
504 if (num_files > 0)
505 job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
506 else
507 {
508 num_files = 1;
7b4a1417 509
8dbf3e6a 510#ifndef WIN32
977acbd3 511# if defined(HAVE_SIGSET)
512 sigset(SIGHUP, sighandler);
576b82ca 513 if (sigset(SIGINT, sighandler) == SIG_IGN)
514 sigset(SIGINT, SIG_IGN);
977acbd3 515 sigset(SIGTERM, sighandler);
516# elif defined(HAVE_SIGACTION)
517 memset(&action, 0, sizeof(action));
518 action.sa_handler = sighandler;
519
520 sigaction(SIGHUP, &action, NULL);
576b82ca 521 sigaction(SIGINT, NULL, &oldaction);
522 if (oldaction.sa_handler != SIG_IGN)
523 sigaction(SIGINT, &action, NULL);
977acbd3 524 sigaction(SIGTERM, &action, NULL);
525# else
526 signal(SIGHUP, sighandler);
576b82ca 527 if (signal(SIGINT, sighandler) == SIG_IGN)
528 signal(SIGINT, SIG_IGN);
8dbf3e6a 529 signal(SIGTERM, sighandler);
977acbd3 530# endif
8dbf3e6a 531#endif /* !WIN32 */
532
1b5bf964 533 temp = cupsTempFd(tempfile, sizeof(tempfile));
7b4a1417 534
1b5bf964 535 if (temp < 0)
7b4a1417 536 {
537 fputs("lp: unable to create temporary file.\n", stderr);
538 return (1);
539 }
540
753453e4 541 while ((i = read(0, buffer, sizeof(buffer))) > 0)
1b5bf964 542 write(temp, buffer, i);
7b4a1417 543
1b5bf964 544 i = lseek(temp, 0, SEEK_CUR);
545 close(temp);
7b4a1417 546
547 if (i == 0)
548 {
549 fputs("lp: stdin is empty, so no job has been sent.\n", stderr);
550 return (1);
551 }
552
b310a06a 553 if (title)
3d06d12f 554 job_id = cupsPrintFile(printer, tempfile, title, num_options, options);
b310a06a 555 else
3d06d12f 556 job_id = cupsPrintFile(printer, tempfile, "(stdin)", num_options, options);
7b4a1417 557
004c20f7 558 unlink(tempfile);
fb577685 559 }
004c20f7 560
fb577685 561 if (job_id < 1)
562 {
563 fprintf(stderr, "lp: unable to print file: %s\n",
564 ippErrorString(cupsLastError()));
565 return (1);
7b4a1417 566 }
fb577685 567 else if (!silent)
753453e4 568 printf("request id is %s-%d (%d file(s))\n", printer, job_id, num_files);
7b4a1417 569
570 return (0);
571}
572
573
d37c31b8 574/*
575 * 'set_job_attrs()' - Set job attributes.
576 */
577
578int /* O - Exit status */
579set_job_attrs(int job_id, /* I - Job ID */
580 int num_options,/* I - Number of options */
581 cups_option_t *options) /* I - Options */
582{
583 http_t *http; /* HTTP connection to server */
584 ipp_t *request, /* IPP request */
585 *response; /* IPP response */
586 cups_lang_t *language; /* Language for request */
587 char uri[HTTP_MAX_URI]; /* URI for job */
588
589
b5cb0608 590 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
d37c31b8 591
effdc824 592 language = cupsLangDefault();
593
594 request = ippNew();
0a3ac972 595 request->request.op.operation_id = IPP_SET_JOB_ATTRIBUTES;
596 request->request.op.request_id = 1;
effdc824 597
598 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
599 "attributes-charset", NULL, cupsLangEncoding(language));
600
601 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
602 "attributes-natural-language", NULL, language->language);
603
604 sprintf(uri, "ipp://localhost/jobs/%d", job_id);
605
606 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
607 "job-uri", NULL, uri);
608
07f4bbbf 609 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
610 "requesting-user-name", NULL, cupsUser());
611
effdc824 612 cupsEncodeOptions(request, num_options, options);
613
614 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL)
615 {
0a3ac972 616 if (response->request.status.status_code > IPP_OK_CONFLICT)
effdc824 617 {
618 fprintf(stderr, "lp: set-job-attributes failed: %s\n",
0a3ac972 619 ippErrorString(response->request.status.status_code));
effdc824 620 ippDelete(response);
621 return (1);
622 }
623
624 ippDelete(response);
625 }
626 else
627 {
628 fprintf(stderr, "lp: set-job-attributes failed: %s\n",
629 ippErrorString(cupsLastError()));
630 return (1);
631 }
632
633 return (0);
d37c31b8 634}
635
636
8dbf3e6a 637#ifndef WIN32
638/*
639 * 'sighandler()' - Signal catcher for when we print from stdin...
640 */
641
642void
977acbd3 643sighandler(int s) /* I - Signal number */
8dbf3e6a 644{
645 /*
646 * Remove the temporary file we're using to print from stdin...
647 */
648
649 unlink(tempfile);
977acbd3 650
651 /*
652 * Exit...
653 */
654
655 exit(s);
8dbf3e6a 656}
657#endif /* !WIN32 */
658
659
7b4a1417 660/*
bcf61448 661 * End of "$Id: lp.c,v 1.29.2.11 2003/01/15 04:25:57 mike Exp $".
7b4a1417 662 */