]> git.ipfire.org Git - thirdparty/cups.git/blob - systemv/lp.c
Merge changes from CUPS 1.4svn-r7961.
[thirdparty/cups.git] / systemv / lp.c
1 /*
2 * "$Id: lp.c 7170 2008-01-04 02:21:30Z mike $"
3 *
4 * "lp" command for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
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/".
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.
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
34 /*
35 * Local functions.
36 */
37
38 int restart_job(const char *command, int job_id);
39 int set_job_attrs(const char *command, int job_id, int num_options,
40 cups_option_t *options);
41
42
43 /*
44 * 'main()' - Parse options and send files for printing.
45 */
46
47 int
48 main(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 */
61 cups_dest_t *dest; /* Selected destination */
62 int num_options; /* Number of options */
63 cups_option_t *options; /* Options */
64 int end_options; /* No more options? */
65 int silent; /* Silent or verbose output? */
66 char buffer[8192]; /* Copy buffer */
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
87 _cupsSetLocale(argv);
88
89 silent = 0;
90 printer = NULL;
91 dest = NULL;
92 num_options = 0;
93 options = NULL;
94 num_files = 0;
95 title = NULL;
96 job_id = 0;
97 end_options = 0;
98
99 for (i = 1; i < argc; i ++)
100 if (argv[i][0] == '-' && argv[i][1] && !end_options)
101 switch (argv[i][1])
102 {
103 case 'E' : /* Encrypt */
104 #ifdef HAVE_SSL
105 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
106 #else
107 _cupsLangPrintf(stderr,
108 _("%s: Sorry, no encryption support compiled in!\n"),
109 argv[0]);
110 #endif /* HAVE_SSL */
111 break;
112
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 "
123 "\'-U\' option!\n"),
124 argv[0]);
125 return (1);
126 }
127
128 cupsSetUser(argv[i]);
129 }
130 break;
131
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 {
144 _cupsLangPrintf(stderr,
145 _("%s: Error - expected destination after "
146 "\'-d\' option!\n"),
147 argv[0]);
148 return (1);
149 }
150
151 printer = argv[i];
152 }
153
154 if ((instance = strrchr(printer, '/')) != NULL)
155 *instance++ = '\0';
156
157 if ((dest = cupsGetNamedDest(NULL, printer, instance)) != NULL)
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 {
174 _cupsLangPrintf(stderr,
175 _("%s: Error - expected form after \'-f\' "
176 "option!\n"),
177 argv[0]);
178 return (1);
179 }
180 }
181
182 _cupsLangPrintf(stderr, _("%s: Warning - form option ignored!\n"),
183 argv[0]);
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 {
195 _cupsLangPrintf(stderr,
196 _("%s: Error - expected hostname after "
197 "\'-h\' option!\n"),
198 argv[0]);
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 {
215 _cupsLangPrintf(stderr,
216 _("%s: Expected job ID after \'-i\' option!\n"),
217 argv[0]);
218 return (1);
219 }
220
221 val = argv[i];
222 }
223
224 if (num_files > 0)
225 {
226 _cupsLangPrintf(stderr,
227 _("%s: Error - cannot print files and alter "
228 "jobs simultaneously!\n"),
229 argv[0]);
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 {
240 _cupsLangPrintf(stderr, _("%s: Error - bad job ID!\n"), argv[0]);
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 */
250 {
251 char email[1024]; /* EMail address */
252
253
254 snprintf(email, sizeof(email), "mailto:%s@%s", cupsUser(),
255 httpGetHostname(NULL, buffer, sizeof(buffer)));
256 num_options = cupsAddOption("notify-recipient-uri", email,
257 num_options, &options);
258 }
259
260 silent = 1;
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 {
272 _cupsLangPrintf(stderr,
273 _("%s: Error - expected copies after "
274 "\'-n\' option!\n"),
275 argv[0]);
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 {
295 _cupsLangPrintf(stderr,
296 _("%s: Error - expected option string after "
297 "\'-o\' option!\n"),
298 argv[0]);
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 {
316 _cupsLangPrintf(stderr,
317 _("%s: Error - expected priority after "
318 "\'-%c\' option!\n"),
319 argv[0], argv[i][1]);
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 {
339 _cupsLangPrintf(stderr,
340 _("%s: Error - priority must be between 1 and "
341 "100.\n"),
342 argv[0]);
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 {
363 _cupsLangPrintf(stderr,
364 _("%s: Error - expected title after "
365 "\'-t\' option!\n"),
366 argv[0]);
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 {
381 _cupsLangPrintf(stderr,
382 _("%s: Error - expected mode list after "
383 "\'-y\' option!\n"),
384 argv[0]);
385 return (1);
386 }
387 }
388
389 _cupsLangPrintf(stderr,
390 _("%s: Warning - mode option ignored!\n"),
391 argv[0]);
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 {
403 _cupsLangPrintf(stderr,
404 _("%s: Error - expected hold name after "
405 "\'-H\' option!\n"),
406 argv[0]);
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"))
421 num_options = cupsAddOption("job-priority", "100",
422 num_options, &options);
423 else if (!strcmp(val, "restart"))
424 {
425 if (job_id < 1)
426 {
427 _cupsLangPrintf(stderr,
428 _("%s: Need job ID (\'-i jobid\') before "
429 "\'-H restart\'!\n"),
430 argv[0]);
431 return (1);
432 }
433
434 if (restart_job(argv[0], job_id))
435 return (1);
436 }
437 else
438 num_options = cupsAddOption("job-hold-until", val,
439 num_options, &options);
440 break;
441
442 case 'P' : /* Page list */
443 if (argv[i][2])
444 val = argv[i] + 2;
445 else
446 {
447 i ++;
448
449 if (i >= argc)
450 {
451 _cupsLangPrintf(stderr,
452 _("%s: Error - expected page list after "
453 "\'-P\' option!\n"),
454 argv[0]);
455 return (1);
456 }
457
458 val = argv[i];
459 }
460
461 num_options = cupsAddOption("page-ranges", val, num_options,
462 &options);
463 break;
464
465 case 'S' : /* character set */
466 if (!argv[i][2])
467 {
468 i ++;
469
470 if (i >= argc)
471 {
472 _cupsLangPrintf(stderr,
473 _("%s: Error - expected character set after "
474 "\'-S\' option!\n"),
475 argv[0]);
476 return (1);
477 }
478 }
479
480 _cupsLangPrintf(stderr,
481 _("%s: Warning - character set option ignored!\n"),
482 argv[0]);
483 break;
484
485 case 'T' : /* Content-Type */
486 if (!argv[i][2])
487 {
488 i ++;
489
490 if (i >= argc)
491 {
492 _cupsLangPrintf(stderr,
493 _("%s: Error - expected content type after "
494 "\'-T\' option!\n"),
495 argv[0]);
496 return (1);
497 }
498 }
499
500 _cupsLangPrintf(stderr,
501 _("%s: Warning - content type option ignored!\n"),
502 argv[0]);
503 break;
504
505 case '-' : /* Stop processing options */
506 end_options = 1;
507 break;
508
509 default :
510 _cupsLangPrintf(stderr, _("%s: Error - unknown option \'%c\'!\n"),
511 argv[0], argv[i][1]);
512 return (1);
513 }
514 else if (!strcmp(argv[i], "-"))
515 {
516 if (num_files || job_id)
517 {
518 _cupsLangPrintf(stderr,
519 _("%s: Error - cannot print from stdin if files or a "
520 "job ID are provided!\n"),
521 argv[0]);
522 return (1);
523 }
524
525 break;
526 }
527 else if (num_files < 1000 && job_id == 0)
528 {
529 /*
530 * Print a file...
531 */
532
533 if (access(argv[i], R_OK) != 0)
534 {
535 _cupsLangPrintf(stderr, _("%s: Error - unable to access \"%s\" - %s\n"),
536 argv[0], argv[i], strerror(errno));
537 return (1);
538 }
539
540 files[num_files] = argv[i];
541 num_files ++;
542
543 if (title == NULL)
544 {
545 if ((title = strrchr(argv[i], '/')) != NULL)
546 title ++;
547 else
548 title = argv[i];
549 }
550 }
551 else
552 _cupsLangPrintf(stderr, _("%s: Error - too many files - \"%s\"\n"),
553 argv[0], argv[i]);
554
555 /*
556 * See if we are altering an existing job...
557 */
558
559 if (job_id)
560 return (set_job_attrs(argv[0], job_id, num_options, options));
561
562 /*
563 * See if we have any files to print; if not, print from stdin...
564 */
565
566 if (printer == NULL)
567 {
568 if ((dest = cupsGetNamedDest(NULL, NULL, NULL)) != NULL)
569 {
570 printer = dest->name;
571
572 for (j = 0; j < dest->num_options; j ++)
573 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
574 num_options = cupsAddOption(dest->options[j].name,
575 dest->options[j].value,
576 num_options, &options);
577 }
578 }
579
580 if (printer == NULL)
581 {
582 val = NULL;
583
584 if ((printer = getenv("LPDEST")) == NULL)
585 {
586 if ((printer = getenv("PRINTER")) != NULL)
587 {
588 if (!strcmp(printer, "lp"))
589 printer = NULL;
590 else
591 val = "PRINTER";
592 }
593 }
594 else
595 val = "LPDEST";
596
597 if (printer && !cupsGetNamedDest(NULL, printer, NULL))
598 _cupsLangPrintf(stderr,
599 _("%s: Error - %s environment variable names "
600 "non-existent destination \"%s\"!\n"),
601 argv[0], val, printer);
602 else if (cupsLastError() == IPP_NOT_FOUND)
603 _cupsLangPrintf(stderr,
604 _("%s: Error - no default destination available.\n"),
605 argv[0]);
606 else
607 _cupsLangPrintf(stderr,
608 _("%s: Error - scheduler not responding!\n"),
609 argv[0]);
610
611 return (1);
612 }
613
614 if (num_files > 0)
615 job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
616 else if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, printer,
617 title ? title : "(stdin)",
618 num_options, options)) > 0)
619 {
620 http_status_t status; /* Write status */
621 const char *format; /* Document format */
622 ssize_t bytes; /* Bytes read */
623
624
625 if (cupsGetOption("raw", num_options, options))
626 format = CUPS_FORMAT_RAW;
627 else if ((format = cupsGetOption("document-format", num_options,
628 options)) == NULL)
629 format = CUPS_FORMAT_AUTO;
630
631 status = cupsStartDocument(CUPS_HTTP_DEFAULT, printer, job_id, NULL,
632 format, 1);
633
634 while (status == HTTP_CONTINUE &&
635 (bytes = read(0, buffer, sizeof(buffer))) > 0)
636 status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, bytes);
637
638 if (status != HTTP_CONTINUE)
639 {
640 _cupsLangPrintf(stderr,
641 _("%s: Error - unable to queue from stdin - %s\n"),
642 argv[0], httpStatus(status));
643 return (1);
644 }
645
646 if (cupsFinishDocument(CUPS_HTTP_DEFAULT, printer) != IPP_OK)
647 job_id = 0;
648 }
649
650 if (job_id < 1)
651 {
652 _cupsLangPrintf(stderr, "%s: %s\n", argv[0], cupsLastErrorString());
653 return (1);
654 }
655 else if (!silent)
656 _cupsLangPrintf(stdout, _("request id is %s-%d (%d file(s))\n"),
657 printer, job_id, num_files);
658
659 return (0);
660 }
661
662
663 /*
664 * 'restart_job()' - Restart a job.
665 */
666
667 int /* O - Exit status */
668 restart_job(const char *command, /* I - Command name */
669 int job_id) /* I - Job ID */
670 {
671 ipp_t *request; /* IPP request */
672 char uri[HTTP_MAX_URI]; /* URI for job */
673
674
675 request = ippNewRequest(IPP_RESTART_JOB);
676
677 sprintf(uri, "ipp://localhost/jobs/%d", job_id);
678
679 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
680 "job-uri", NULL, uri);
681
682 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
683 "requesting-user-name", NULL, cupsUser());
684
685 ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/jobs"));
686
687 if (cupsLastError() > IPP_OK_CONFLICT)
688 {
689 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
690 return (1);
691 }
692
693 return (0);
694 }
695
696
697 /*
698 * 'set_job_attrs()' - Set job attributes.
699 */
700
701 int /* O - Exit status */
702 set_job_attrs(const char *command, /* I - Command name */
703 int job_id, /* I - Job ID */
704 int num_options,/* I - Number of options */
705 cups_option_t *options) /* I - Options */
706 {
707 ipp_t *request; /* IPP request */
708 char uri[HTTP_MAX_URI]; /* URI for job */
709
710
711 if (num_options == 0)
712 return (0);
713
714 request = ippNewRequest(IPP_SET_JOB_ATTRIBUTES);
715
716 sprintf(uri, "ipp://localhost/jobs/%d", job_id);
717
718 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
719 "job-uri", NULL, uri);
720
721 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
722 "requesting-user-name", NULL, cupsUser());
723
724 cupsEncodeOptions(request, num_options, options);
725
726 ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/jobs"));
727
728 if (cupsLastError() > IPP_OK_CONFLICT)
729 {
730 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
731 return (1);
732 }
733
734 return (0);
735 }
736
737
738 /*
739 * End of "$Id: lp.c 7170 2008-01-04 02:21:30Z mike $".
740 */