]> git.ipfire.org Git - thirdparty/cups.git/blob - systemv/lp.c
Merge changes from CUPS 1.5svn-r9049 (private header support)
[thirdparty/cups.git] / systemv / lp.c
1 /*
2 * "$Id: lp.c 7170 2008-01-04 02:21:30Z mike $"
3 *
4 * "lp" command for CUPS.
5 *
6 * Copyright 2007-2010 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 <cups/cups-private.h>
27
28
29 /*
30 * Local functions.
31 */
32
33 int restart_job(const char *command, int job_id);
34 int set_job_attrs(const char *command, int job_id, int num_options,
35 cups_option_t *options);
36
37
38 /*
39 * 'main()' - Parse options and send files for printing.
40 */
41
42 int
43 main(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 */
56 cups_dest_t *dest; /* Selected destination */
57 int num_options; /* Number of options */
58 cups_option_t *options; /* Options */
59 int end_options; /* No more options? */
60 int silent; /* Silent or verbose output? */
61 char buffer[8192]; /* Copy buffer */
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
82 _cupsSetLocale(argv);
83
84 silent = 0;
85 printer = NULL;
86 dest = NULL;
87 num_options = 0;
88 options = NULL;
89 num_files = 0;
90 title = NULL;
91 job_id = 0;
92 end_options = 0;
93
94 for (i = 1; i < argc; i ++)
95 if (argv[i][0] == '-' && argv[i][1] && !end_options)
96 switch (argv[i][1])
97 {
98 case 'E' : /* Encrypt */
99 #ifdef HAVE_SSL
100 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
101 #else
102 _cupsLangPrintf(stderr,
103 _("%s: Sorry, no encryption support compiled in\n"),
104 argv[0]);
105 #endif /* HAVE_SSL */
106 break;
107
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 "
118 "\'-U\' option\n"),
119 argv[0]);
120 return (1);
121 }
122
123 cupsSetUser(argv[i]);
124 }
125 break;
126
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 {
139 _cupsLangPrintf(stderr,
140 _("%s: Error - expected destination after "
141 "\'-d\' option\n"),
142 argv[0]);
143 return (1);
144 }
145
146 printer = argv[i];
147 }
148
149 if ((instance = strrchr(printer, '/')) != NULL)
150 *instance++ = '\0';
151
152 if ((dest = cupsGetNamedDest(NULL, printer, instance)) != NULL)
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 {
169 _cupsLangPrintf(stderr,
170 _("%s: Error - expected form after \'-f\' "
171 "option\n"),
172 argv[0]);
173 return (1);
174 }
175 }
176
177 _cupsLangPrintf(stderr, _("%s: Warning - form option ignored\n"),
178 argv[0]);
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 {
190 _cupsLangPrintf(stderr,
191 _("%s: Error - expected hostname after "
192 "\'-h\' option\n"),
193 argv[0]);
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 {
210 _cupsLangPrintf(stderr,
211 _("%s: Expected job ID after \'-i\' option\n"),
212 argv[0]);
213 return (1);
214 }
215
216 val = argv[i];
217 }
218
219 if (num_files > 0)
220 {
221 _cupsLangPrintf(stderr,
222 _("%s: Error - cannot print files and alter "
223 "jobs simultaneously\n"),
224 argv[0]);
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 {
235 _cupsLangPrintf(stderr, _("%s: Error - bad job ID\n"), argv[0]);
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 */
245 {
246 char email[1024]; /* EMail address */
247
248
249 snprintf(email, sizeof(email), "mailto:%s@%s", cupsUser(),
250 httpGetHostname(NULL, buffer, sizeof(buffer)));
251 num_options = cupsAddOption("notify-recipient-uri", email,
252 num_options, &options);
253 }
254
255 silent = 1;
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 {
267 _cupsLangPrintf(stderr,
268 _("%s: Error - expected copies after "
269 "\'-n\' option\n"),
270 argv[0]);
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 {
290 _cupsLangPrintf(stderr,
291 _("%s: Error - expected option string after "
292 "\'-o\' option\n"),
293 argv[0]);
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 {
311 _cupsLangPrintf(stderr,
312 _("%s: Error - expected priority after "
313 "\'-%c\' option\n"),
314 argv[0], argv[i][1]);
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 {
334 _cupsLangPrintf(stderr,
335 _("%s: Error - priority must be between 1 and "
336 "100.\n"),
337 argv[0]);
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 {
358 _cupsLangPrintf(stderr,
359 _("%s: Error - expected title after "
360 "\'-t\' option\n"),
361 argv[0]);
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 {
376 _cupsLangPrintf(stderr,
377 _("%s: Error - expected mode list after "
378 "\'-y\' option\n"),
379 argv[0]);
380 return (1);
381 }
382 }
383
384 _cupsLangPrintf(stderr,
385 _("%s: Warning - mode option ignored\n"),
386 argv[0]);
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 {
398 _cupsLangPrintf(stderr,
399 _("%s: Error - expected hold name after "
400 "\'-H\' option\n"),
401 argv[0]);
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"))
416 {
417 num_options = cupsAddOption("job-hold-until", "no-hold",
418 num_options, &options);
419 num_options = cupsAddOption("job-priority", "100",
420 num_options, &options);
421 }
422 else if (!strcmp(val, "restart"))
423 {
424 if (job_id < 1)
425 {
426 _cupsLangPrintf(stderr,
427 _("%s: Need job ID (\'-i jobid\') before "
428 "\'-H restart\'\n"),
429 argv[0]);
430 return (1);
431 }
432
433 if (restart_job(argv[0], job_id))
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 {
450 _cupsLangPrintf(stderr,
451 _("%s: Error - expected page list after "
452 "\'-P\' option\n"),
453 argv[0]);
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 {
471 _cupsLangPrintf(stderr,
472 _("%s: Error - expected character set after "
473 "\'-S\' option\n"),
474 argv[0]);
475 return (1);
476 }
477 }
478
479 _cupsLangPrintf(stderr,
480 _("%s: Warning - character set option ignored\n"),
481 argv[0]);
482 break;
483
484 case 'T' : /* Content-Type */
485 if (!argv[i][2])
486 {
487 i ++;
488
489 if (i >= argc)
490 {
491 _cupsLangPrintf(stderr,
492 _("%s: Error - expected content type after "
493 "\'-T\' option\n"),
494 argv[0]);
495 return (1);
496 }
497 }
498
499 _cupsLangPrintf(stderr,
500 _("%s: Warning - content type option ignored\n"),
501 argv[0]);
502 break;
503
504 case '-' : /* Stop processing options */
505 end_options = 1;
506 break;
507
508 default :
509 _cupsLangPrintf(stderr, _("%s: Error - unknown option \'%c\'\n"),
510 argv[0], argv[i][1]);
511 return (1);
512 }
513 else if (!strcmp(argv[i], "-"))
514 {
515 if (num_files || job_id)
516 {
517 _cupsLangPrintf(stderr,
518 _("%s: Error - cannot print from stdin if files or a "
519 "job ID are provided\n"),
520 argv[0]);
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 {
534 _cupsLangPrintf(stderr, _("%s: Error - unable to access \"%s\" - %s\n"),
535 argv[0], argv[i], strerror(errno));
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
551 _cupsLangPrintf(stderr, _("%s: Error - too many files - \"%s\"\n"),
552 argv[0], argv[i]);
553
554 /*
555 * See if we are altering an existing job...
556 */
557
558 if (job_id)
559 return (set_job_attrs(argv[0], job_id, num_options, options));
560
561 /*
562 * See if we have any files to print; if not, print from stdin...
563 */
564
565 if (printer == NULL)
566 {
567 if ((dest = cupsGetNamedDest(NULL, NULL, NULL)) != NULL)
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
596 if (printer && !cupsGetNamedDest(NULL, printer, NULL))
597 _cupsLangPrintf(stderr,
598 _("%s: Error - %s environment variable names "
599 "non-existent destination \"%s\"\n"),
600 argv[0], val, printer);
601 else if (cupsLastError() == IPP_NOT_FOUND)
602 _cupsLangPrintf(stderr,
603 _("%s: Error - no default destination available.\n"),
604 argv[0]);
605 else
606 _cupsLangPrintf(stderr,
607 _("%s: Error - scheduler not responding\n"),
608 argv[0]);
609
610 return (1);
611 }
612
613 if (num_files > 0)
614 job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
615 else if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, printer,
616 title ? title : "(stdin)",
617 num_options, options)) > 0)
618 {
619 http_status_t status; /* Write status */
620 const char *format; /* Document format */
621 ssize_t bytes; /* Bytes read */
622
623
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);
632
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)
638 {
639 _cupsLangPrintf(stderr,
640 _("%s: Error - unable to queue from stdin - %s\n"),
641 argv[0], httpStatus(status));
642 return (1);
643 }
644
645 if (cupsFinishDocument(CUPS_HTTP_DEFAULT, printer) != IPP_OK)
646 job_id = 0;
647 }
648
649 if (job_id < 1)
650 {
651 _cupsLangPrintf(stderr, "%s: %s\n", argv[0], cupsLastErrorString());
652 return (1);
653 }
654 else if (!silent)
655 _cupsLangPrintf(stdout, _("request id is %s-%d (%d file(s))\n"),
656 printer, job_id, num_files);
657
658 return (0);
659 }
660
661
662 /*
663 * 'restart_job()' - Restart a job.
664 */
665
666 int /* O - Exit status */
667 restart_job(const char *command, /* I - Command name */
668 int job_id) /* I - Job ID */
669 {
670 ipp_t *request; /* IPP request */
671 char uri[HTTP_MAX_URI]; /* URI for job */
672
673
674 request = ippNewRequest(IPP_RESTART_JOB);
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
684 ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/jobs"));
685
686 if (cupsLastError() > IPP_OK_CONFLICT)
687 {
688 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
689 return (1);
690 }
691
692 return (0);
693 }
694
695
696 /*
697 * 'set_job_attrs()' - Set job attributes.
698 */
699
700 int /* O - Exit status */
701 set_job_attrs(const char *command, /* I - Command name */
702 int job_id, /* I - Job ID */
703 int num_options,/* I - Number of options */
704 cups_option_t *options) /* I - Options */
705 {
706 ipp_t *request; /* IPP request */
707 char uri[HTTP_MAX_URI]; /* URI for job */
708
709
710 if (num_options == 0)
711 return (0);
712
713 request = ippNewRequest(IPP_SET_JOB_ATTRIBUTES);
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
725 ippDelete(cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/jobs"));
726
727 if (cupsLastError() > IPP_OK_CONFLICT)
728 {
729 _cupsLangPrintf(stderr, "%s: %s\n", command, cupsLastErrorString());
730 return (1);
731 }
732
733 return (0);
734 }
735
736
737 /*
738 * End of "$Id: lp.c 7170 2008-01-04 02:21:30Z mike $".
739 */