]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/lp.c
Add httpConnectEncrypt() and fix all code that uses the
[thirdparty/cups.git] / systemv / lp.c
CommitLineData
7b4a1417 1/*
a1793153 2 * "$Id: lp.c,v 1.30 2001/05/06 00:11:26 mike Exp $"
7b4a1417 3 *
4 * "lp" command for the Common UNIX Printing System (CUPS).
5 *
d2935a0f 6 * Copyright 1997-2001 by Easy Software Products.
7b4a1417 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
146949f8 17 * 44141 Airport View Drive, Suite 204
7b4a1417 18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
8dbf3e6a 26 * main() - Parse options and send files for printing.
27 * sighandler() - Signal catcher for when we print from stdin...
7b4a1417 28 */
29
30/*
31 * Include necessary headers...
32 */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <cups/cups.h>
0b340d2d 37#include <cups/string.h>
effdc824 38#include <cups/language.h>
7b4a1417 39
40
8dbf3e6a 41#ifndef WIN32
42# include <signal.h>
43
44
45/*
46 * Local functions.
47 */
48
977acbd3 49void sighandler(int);
8dbf3e6a 50#endif /* !WIN32 */
d37c31b8 51int set_job_attrs(int job_id, int num_options, cups_option_t *options);
8dbf3e6a 52
53
54/*
55 * Globals...
56 */
57
58char tempfile[1024]; /* Temporary file for printing from stdin */
59
60
7b4a1417 61/*
62 * 'main()' - Parse options and send files for printing.
63 */
64
65int
66main(int argc, /* I - Number of command-line arguments */
67 char *argv[]) /* I - Command-line arguments */
68{
3d06d12f 69 int i, j; /* Looping vars */
7b4a1417 70 int job_id; /* Job ID */
3d06d12f 71 char *printer, /* Printer name */
d37c31b8 72 *instance, /* Instance name */
73 *val, /* Option value */
74 *title; /* Job title */
7b4a1417 75 int priority; /* Job priority (1-100) */
76 int num_copies; /* Number of copies per file */
fb577685 77 int num_files; /* Number of files to print */
78 const char *files[1000]; /* Files to print */
dd0f599a 79 int num_dests; /* Number of destinations */
80 cups_dest_t *dests, /* Destinations */
3d06d12f 81 *dest; /* Selected destination */
7b4a1417 82 int num_options; /* Number of options */
83 cups_option_t *options; /* Options */
84 int silent; /* Silent or verbose output? */
7b4a1417 85 char buffer[8192]; /* Copy buffer */
1b5bf964 86 int temp; /* Temporary file descriptor */
8a2c2126 87#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
977acbd3 88 struct sigaction action; /* Signal action */
8a2c2126 89#endif /* HAVE_SIGACTION && !HAVE_SIGSET*/
7b4a1417 90
91
df7507f5 92#ifdef __sun
93 /*
94 * Solaris does some rather strange things to re-queue remote print
95 * jobs. On bootup, the "lp" command is run as "printd" to re-spool
96 * any remote jobs in /var/spool/print. Since CUPS doesn't need this
97 * nonsense, we just need to add the necessary check here to prevent
98 * lp from causing boot problems...
99 */
100
101 if ((val = strrchr(argv[0], '/')) != NULL)
102 val ++;
103 else
104 val = argv[0];
105
106 if (strcmp(val, "printd") == 0)
107 return (0);
108#endif /* __sun */
109
7b4a1417 110 silent = 0;
3d06d12f 111 printer = NULL;
112 num_dests = 0;
113 dests = NULL;
7b4a1417 114 num_options = 0;
115 options = NULL;
116 num_files = 0;
b310a06a 117 title = NULL;
d37c31b8 118 job_id = 0;
7b4a1417 119
120 for (i = 1; i < argc; i ++)
121 if (argv[i][0] == '-')
122 switch (argv[i][1])
123 {
1c9e0181 124 case 'E' : /* Encrypt */
125#ifdef HAVE_LIBSSL
126 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
127#else
128 fprintf(stderr, "%s: Sorry, no encryption support compiled in!\n",
129 argv[0]);
130#endif /* HAVE_LIBSSL */
131 break;
132
7b4a1417 133 case 'c' : /* Copy to spool dir (always enabled) */
134 break;
135
136 case 'd' : /* Destination printer or class */
137 if (argv[i][2] != '\0')
3d06d12f 138 printer = argv[i] + 2;
7b4a1417 139 else
140 {
141 i ++;
d37c31b8 142
143 if (i >= argc)
144 {
145 fputs("lp: Expected destination after -d option!\n", stderr);
146 return (1);
147 }
148
3d06d12f 149 printer = argv[i];
150 }
151
152 if ((instance = strrchr(printer, '/')) != NULL)
153 *instance++ = '\0';
154
155 if (num_dests == 0)
156 num_dests = cupsGetDests(&dests);
157
158 if ((dest = cupsGetDest(printer, instance, num_dests, dests)) != NULL)
159 {
160 for (j = 0; j < dest->num_options; j ++)
e8973392 161 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
162 num_options = cupsAddOption(dest->options[j].name,
163 dest->options[j].value,
164 num_options, &options);
7b4a1417 165 }
166 break;
167
d37c31b8 168 case 'f' : /* Form */
169 if (!argv[i][2])
170 {
171 i ++;
172
173 if (i >= argc)
174 {
175 fputs("lp: Expected form after -f option!\n", stderr);
176 return (1);
177 }
178 }
179
180 fputs("lp: Warning - form option ignored!\n", stderr);
181 break;
182
0b340d2d 183 case 'h' : /* Destination host */
184 if (argv[i][2] != '\0')
d37c31b8 185 cupsSetServer(argv[i] + 2);
0b340d2d 186 else
187 {
188 i ++;
d37c31b8 189
190 if (i >= argc)
191 {
192 fputs("lp: Expected hostname after -h option!\n", stderr);
193 return (1);
194 }
195
196 cupsSetServer(argv[i]);
197 }
198 break;
199
200 case 'i' : /* Change job */
201 if (argv[i][2])
202 val = argv[i] + 2;
203 else
204 {
205 i ++;
206
207 if (i >= argc)
208 {
209 fputs("lp: Expected job ID after -i option!\n", stderr);
210 return (1);
211 }
212
213 val = argv[i];
214 }
215
216 if (num_files > 0)
217 {
218 fputs("lp: Error - cannot print files and alter jobs simultaneously!\n", stderr);
219 return (1);
220 }
221
222 if (strrchr(val, '-') != NULL)
223 job_id = atoi(strrchr(val, '-') + 1);
224 else
225 job_id = atoi(val);
226
227 if (job_id < 0)
228 {
229 fputs("lp: Error - bad job ID!\n", stderr);
230 break;
0b340d2d 231 }
0b340d2d 232 break;
233
7b4a1417 234 case 'm' : /* Send email when job is done */
d37c31b8 235#ifdef __sun
236 case 'p' : /* Notify on completion */
237#endif /* __sun */
7b4a1417 238 case 'w' : /* Write to console or email */
239 break;
240
241 case 'n' : /* Number of copies */
242 if (argv[i][2] != '\0')
243 num_copies = atoi(argv[i] + 2);
244 else
245 {
246 i ++;
d37c31b8 247
248 if (i >= argc)
249 {
250 fputs("lp: Expected copies after -n option!\n", stderr);
251 return (1);
252 }
253
7b4a1417 254 num_copies = atoi(argv[i]);
255 }
256
257 if (num_copies < 1 || num_copies > 100)
258 {
259 fputs("lp: Number copies must be between 1 and 100.\n", stderr);
260 return (1);
261 }
8f70d036 262
263 sprintf(buffer, "%d", num_copies);
264 num_options = cupsAddOption("copies", buffer, num_options, &options);
7b4a1417 265 break;
266
267 case 'o' : /* Option */
268 if (argv[i][2] != '\0')
269 num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
270 else
271 {
272 i ++;
d37c31b8 273
274 if (i >= argc)
275 {
276 fputs("lp: Expected option string after -o option!\n", stderr);
277 return (1);
278 }
279
7b4a1417 280 num_options = cupsParseOptions(argv[i], num_options, &options);
281 }
282 break;
283
d37c31b8 284#ifndef __sun
1738443a 285 case 'p' : /* Queue priority */
d37c31b8 286#endif /* !__sun */
7b4a1417 287 case 'q' : /* Queue priority */
288 if (argv[i][2] != '\0')
289 priority = atoi(argv[i] + 2);
290 else
291 {
292 i ++;
d37c31b8 293
294 if (i >= argc)
295 {
296 fprintf(stderr, "lp: Expected priority after -%c option!\n",
297 argv[i][1]);
298 return (1);
299 }
300
7b4a1417 301 priority = atoi(argv[i]);
302 }
303
d37c31b8 304 /*
305 * For 100% Solaris compatibility, need to add:
306 *
307 * priority = 99 * (39 - priority) / 39 + 1;
308 *
309 * However, to keep CUPS lp the same across all platforms
310 * we will break compatibility this far...
311 */
312
7b4a1417 313 if (priority < 1 || priority > 100)
314 {
315 fputs("lp: Priority must be between 1 and 100.\n", stderr);
316 return (1);
317 }
8f70d036 318
319 sprintf(buffer, "%d", priority);
320 num_options = cupsAddOption("job-priority", buffer, num_options, &options);
7b4a1417 321 break;
322
323 case 's' : /* Silent */
324 silent = 1;
325 break;
326
327 case 't' : /* Title */
328 if (argv[i][2] != '\0')
329 title = argv[i] + 2;
330 else
331 {
332 i ++;
d37c31b8 333
334 if (i >= argc)
335 {
336 fputs("lp: Expected title after -t option!\n", stderr);
337 return (1);
338 }
339
7b4a1417 340 title = argv[i];
341 }
342 break;
343
d37c31b8 344 case 'y' : /* mode-list */
345 if (!argv[i][2])
346 {
347 i ++;
348
349 if (i >= argc)
350 {
351 fputs("lp: Expected mode list after -y option!\n", stderr);
352 return (1);
353 }
354 }
355
356 fputs("lp: Warning - mode option ignored!\n", stderr);
357 break;
358
359 case 'H' : /* Hold job */
360 if (argv[i][2])
361 val = argv[i] + 2;
362 else
363 {
364 i ++;
365
366 if (i >= argc)
367 {
368 fputs("lp: Expected hold name after -H option!\n", stderr);
369 return (1);
370 }
371
372 val = argv[i];
373 }
374
375 if (strcmp(val, "hold") == 0)
376 num_options = cupsAddOption("job-hold-until", "indefinite",
377 num_options, &options);
378 if (strcmp(val, "resume") == 0)
379 num_options = cupsAddOption("job-hold-until", "none",
380 num_options, &options);
381 else if (strcmp(val, "immediate") == 0)
382 num_options = cupsAddOption("job-priority", "100",
383 num_options, &options);
384 else
385 num_options = cupsAddOption("job-hold-until", val,
386 num_options, &options);
387 break;
388
389 case 'P' : /* Page list */
390 if (argv[i][2])
391 val = argv[i] + 2;
392 else
393 {
394 i ++;
395
396 if (i >= argc)
397 {
398 fputs("lp: Expected page list after -P option!\n", stderr);
399 return (1);
400 }
401
402 val = argv[i];
403 }
404
405 num_options = cupsAddOption("page-ranges", val, num_options,
406 &options);
407 break;
408
409 case 'S' : /* character set */
410 if (!argv[i][2])
411 {
412 i ++;
413
414 if (i >= argc)
415 {
416 fputs("lp: Expected character set after -S option!\n", stderr);
417 return (1);
418 }
419 }
420
421 fputs("lp: Warning - character set option ignored!\n", stderr);
422 break;
423
424 case 'T' : /* Content-Type */
425 if (!argv[i][2])
426 {
427 i ++;
428
429 if (i >= argc)
430 {
431 fputs("lp: Expected content type after -T option!\n", stderr);
432 return (1);
433 }
434 }
435
436 fputs("lp: Warning - content type option ignored!\n", stderr);
437 break;
438
7b4a1417 439 default :
440 fprintf(stderr, "lp: Unknown option \'%c\'!\n", argv[i][1]);
441 return (1);
442 }
d37c31b8 443 else if (num_files < 1000 && job_id == 0)
7b4a1417 444 {
b310a06a 445 /*
446 * Print a file...
447 */
7b4a1417 448
fb577685 449 files[num_files] = argv[i];
b310a06a 450 num_files ++;
146949f8 451
fb577685 452 if (title == NULL)
b310a06a 453 {
fb577685 454 if ((title = strrchr(argv[i], '/')) != NULL)
455 title ++;
456 else
457 title = argv[i];
b310a06a 458 }
7b4a1417 459 }
fb577685 460 else
461 fprintf(stderr, "lp: Too many files - \"%s\"\n", argv[i]);
7b4a1417 462
d37c31b8 463 /*
464 * See if we are altering an existing job...
465 */
466
467 if (job_id)
468 return (set_job_attrs(job_id, num_options, options));
469
7b4a1417 470 /*
fb577685 471 * See if we have any files to print; if not, print from stdin...
7b4a1417 472 */
473
fb577685 474 if (printer == NULL)
7b4a1417 475 {
fb577685 476 if (num_dests == 0)
477 num_dests = cupsGetDests(&dests);
0b340d2d 478
fb577685 479 for (j = 0, dest = dests; j < num_dests; j ++, dest ++)
480 if (dest->is_default)
481 {
482 printer = dests[j].name;
483
484 for (j = 0; j < dest->num_options; j ++)
e8973392 485 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
486 num_options = cupsAddOption(dest->options[j].name,
487 dest->options[j].value,
488 num_options, &options);
fb577685 489 break;
490 }
491 }
492
493 if (printer == NULL)
494 {
495 fputs("lp: error - no default destination available.\n", stderr);
496 return (1);
497 }
498
499 if (num_files > 0)
500 job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options);
501 else
502 {
503 num_files = 1;
7b4a1417 504
8dbf3e6a 505#ifndef WIN32
977acbd3 506# if defined(HAVE_SIGSET)
507 sigset(SIGHUP, sighandler);
508 sigset(SIGINT, sighandler);
509 sigset(SIGTERM, sighandler);
510# elif defined(HAVE_SIGACTION)
511 memset(&action, 0, sizeof(action));
512 action.sa_handler = sighandler;
513
514 sigaction(SIGHUP, &action, NULL);
515 sigaction(SIGINT, &action, NULL);
516 sigaction(SIGTERM, &action, NULL);
517# else
518 signal(SIGHUP, sighandler);
519 signal(SIGINT, sighandler);
8dbf3e6a 520 signal(SIGTERM, sighandler);
977acbd3 521# endif
8dbf3e6a 522#endif /* !WIN32 */
523
1b5bf964 524 temp = cupsTempFd(tempfile, sizeof(tempfile));
7b4a1417 525
1b5bf964 526 if (temp < 0)
7b4a1417 527 {
528 fputs("lp: unable to create temporary file.\n", stderr);
529 return (1);
530 }
531
532 while ((i = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
1b5bf964 533 write(temp, buffer, i);
7b4a1417 534
1b5bf964 535 i = lseek(temp, 0, SEEK_CUR);
536 close(temp);
7b4a1417 537
538 if (i == 0)
539 {
540 fputs("lp: stdin is empty, so no job has been sent.\n", stderr);
541 return (1);
542 }
543
b310a06a 544 if (title)
3d06d12f 545 job_id = cupsPrintFile(printer, tempfile, title, num_options, options);
b310a06a 546 else
3d06d12f 547 job_id = cupsPrintFile(printer, tempfile, "(stdin)", num_options, options);
7b4a1417 548
004c20f7 549 unlink(tempfile);
fb577685 550 }
004c20f7 551
fb577685 552 if (job_id < 1)
553 {
554 fprintf(stderr, "lp: unable to print file: %s\n",
555 ippErrorString(cupsLastError()));
556 return (1);
7b4a1417 557 }
fb577685 558 else if (!silent)
559 fprintf(stderr, "request id is %s-%d (%d file(s))\n", printer, job_id,
560 num_files);
7b4a1417 561
562 return (0);
563}
564
565
d37c31b8 566/*
567 * 'set_job_attrs()' - Set job attributes.
568 */
569
570int /* O - Exit status */
571set_job_attrs(int job_id, /* I - Job ID */
572 int num_options,/* I - Number of options */
573 cups_option_t *options) /* I - Options */
574{
575 http_t *http; /* HTTP connection to server */
576 ipp_t *request, /* IPP request */
577 *response; /* IPP response */
578 cups_lang_t *language; /* Language for request */
579 char uri[HTTP_MAX_URI]; /* URI for job */
580
581
a1793153 582 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
d37c31b8 583
effdc824 584 language = cupsLangDefault();
585
586 request = ippNew();
587 request->request.op.operation_id = IPP_SET_JOB_ATTRIBUTES;
588 request->request.op.request_id = 1;
589
590 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
591 "attributes-charset", NULL, cupsLangEncoding(language));
592
593 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
594 "attributes-natural-language", NULL, language->language);
595
596 sprintf(uri, "ipp://localhost/jobs/%d", job_id);
597
598 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
599 "job-uri", NULL, uri);
600
07f4bbbf 601 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
602 "requesting-user-name", NULL, cupsUser());
603
effdc824 604 cupsEncodeOptions(request, num_options, options);
605
606 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL)
607 {
608 if (response->request.status.status_code > IPP_OK_CONFLICT)
609 {
610 fprintf(stderr, "lp: set-job-attributes failed: %s\n",
611 ippErrorString(response->request.status.status_code));
612 ippDelete(response);
613 return (1);
614 }
615
616 ippDelete(response);
617 }
618 else
619 {
620 fprintf(stderr, "lp: set-job-attributes failed: %s\n",
621 ippErrorString(cupsLastError()));
622 return (1);
623 }
624
625 return (0);
d37c31b8 626}
627
628
8dbf3e6a 629#ifndef WIN32
630/*
631 * 'sighandler()' - Signal catcher for when we print from stdin...
632 */
633
634void
977acbd3 635sighandler(int s) /* I - Signal number */
8dbf3e6a 636{
637 /*
638 * Remove the temporary file we're using to print from stdin...
639 */
640
641 unlink(tempfile);
977acbd3 642
643 /*
644 * Exit...
645 */
646
647 exit(s);
8dbf3e6a 648}
649#endif /* !WIN32 */
650
651
7b4a1417 652/*
a1793153 653 * End of "$Id: lp.c,v 1.30 2001/05/06 00:11:26 mike Exp $".
7b4a1417 654 */