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