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