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