]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/ipp.c
Remove svn:keywords since they cause svn_load_dirs.pl to complain about every file.
[thirdparty/cups.git] / backend / ipp.c
CommitLineData
ef416fc2 1/*
c07d5b2d 2 * "$Id: ipp.c 181 2006-06-22 20:01:18Z jlovell $"
ef416fc2 3 *
4 * IPP backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
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" 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
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * main() - Send a file to the printer or server.
b423cd4c 29 * cancel_job() - Cancel a print job.
ef416fc2 30 * check_printer_state() - Check the printer state...
b423cd4c 31 * compress_files() - Compress print files...
ef416fc2 32 * password_cb() - Disable the password prompt for
33 * cupsDoFileRequest().
34 * report_printer_state() - Report the printer state.
35 * run_pictwps_filter() - Convert PICT files to PostScript when printing
36 * remotely.
37 * sigterm_handler() - Handle 'terminate' signals that stop the backend.
38 */
39
40/*
41 * Include necessary headers.
42 */
43
44#include <cups/http-private.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <errno.h>
48#include <sys/types.h>
49#include <sys/stat.h>
50#include <cups/backend.h>
51#include <cups/cups.h>
52#include <cups/language.h>
53#include <cups/string.h>
54#include <signal.h>
55#include <sys/wait.h>
56
57
58/*
59 * Globals...
60 */
61
62static char *password = NULL; /* Password for device URI */
63#ifdef __APPLE__
64static char pstmpname[1024] = ""; /* Temporary PostScript file name */
65#endif /* __APPLE__ */
66static char tmpfilename[1024] = ""; /* Temporary spool file name */
bd7854cb 67static int job_cancelled = 0; /* Job cancelled? */
ef416fc2 68
69
70/*
71 * Local functions...
72 */
73
bd7854cb 74static void cancel_job(http_t *http, const char *uri, int id,
75 const char *resource, const char *user, int version);
76static void check_printer_state(http_t *http, const char *uri,
ef416fc2 77 const char *resource, const char *user,
78 int version);
b423cd4c 79#ifdef HAVE_LIBZ
80static void compress_files(int num_files, char **files);
81#endif /* HAVE_LIBZ */
bd7854cb 82static const char *password_cb(const char *);
83static int report_printer_state(ipp_t *ipp);
ef416fc2 84
85#ifdef __APPLE__
bd7854cb 86static int run_pictwps_filter(char **argv, const char *filename);
ef416fc2 87#endif /* __APPLE__ */
88static void sigterm_handler(int sig);
89
90
91/*
92 * 'main()' - Send a file to the printer or server.
93 *
94 * Usage:
95 *
96 * printer-uri job-id user title copies options [file]
97 */
98
99int /* O - Exit status */
bd7854cb 100main(int argc, /* I - Number of command-line args */
ef416fc2 101 char *argv[]) /* I - Command-line arguments */
102{
103 int i; /* Looping var */
104 int num_options; /* Number of printer options */
105 cups_option_t *options; /* Printer options */
106 char method[255], /* Method in URI */
107 hostname[1024], /* Hostname */
108 username[255], /* Username info */
109 resource[1024], /* Resource info (printer name) */
110 *optptr, /* Pointer to URI options */
111 name[255], /* Name of option */
112 value[255], /* Value of option */
113 *ptr; /* Pointer into name or value */
bd7854cb 114 int num_files; /* Number of files to print */
115 char **files, /* Files to print */
116 *filename; /* Pointer to single filename */
ef416fc2 117 int port; /* Port number (not used) */
118 char uri[HTTP_MAX_URI]; /* Updated URI without user/pass */
119 ipp_status_t ipp_status; /* Status of IPP request */
120 http_t *http; /* HTTP connection */
121 ipp_t *request, /* IPP request */
122 *response, /* IPP response */
123 *supported; /* get-printer-attributes response */
b423cd4c 124 int compression, /* Do compression of the job data? */
125 waitjob, /* Wait for job complete? */
ef416fc2 126 waitprinter; /* Wait for printer ready? */
127 ipp_attribute_t *job_id_attr; /* job-id attribute */
128 int job_id; /* job-id value */
bd7854cb 129 ipp_attribute_t *job_sheets; /* job-media-sheets-completed */
130 ipp_attribute_t *job_state; /* job-state */
131 ipp_attribute_t *copies_sup; /* copies-supported */
132 ipp_attribute_t *format_sup; /* document-format-supported */
ef416fc2 133 ipp_attribute_t *printer_state; /* printer-state attribute */
bd7854cb 134 ipp_attribute_t *printer_accepting; /* printer-is-accepting-jobs */
ef416fc2 135 int copies; /* Number of copies remaining */
136 const char *content_type; /* CONTENT_TYPE environment variable */
137#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
138 struct sigaction action; /* Actions for POSIX signals */
139#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
140 int version; /* IPP version */
bd7854cb 141 int reasons; /* Number of printer-state-reasons */
ef416fc2 142 static const char * const pattrs[] =
143 { /* Printer attributes we want */
144 "copies-supported",
ef416fc2 145 "document-format-supported",
146 "printer-is-accepting-jobs",
147 "printer-state",
148 "printer-state-reasons",
149 };
150 static const char * const jattrs[] =
151 { /* Job attributes we want */
152 "job-media-sheets-completed",
153 "job-state"
154 };
155
156
157 /*
158 * Make sure status messages are not buffered...
159 */
160
161 setbuf(stderr, NULL);
162
163 /*
164 * Ignore SIGPIPE and catch SIGTERM signals...
165 */
166
167#ifdef HAVE_SIGSET
168 sigset(SIGPIPE, SIG_IGN);
169 sigset(SIGTERM, sigterm_handler);
170#elif defined(HAVE_SIGACTION)
171 memset(&action, 0, sizeof(action));
172 action.sa_handler = SIG_IGN;
173 sigaction(SIGPIPE, &action, NULL);
174
175 sigemptyset(&action.sa_mask);
176 sigaddset(&action.sa_mask, SIGTERM);
177 action.sa_handler = sigterm_handler;
178 sigaction(SIGTERM, &action, NULL);
179#else
180 signal(SIGPIPE, SIG_IGN);
181 signal(SIGTERM, sigterm_handler);
182#endif /* HAVE_SIGSET */
183
184 /*
185 * Check command-line...
186 */
187
188 if (argc == 1)
189 {
190 char *s;
191
192 if ((s = strrchr(argv[0], '/')) != NULL)
193 s ++;
194 else
195 s = argv[0];
196
bd7854cb 197 printf("network %s \"Unknown\" \"Internet Printing Protocol (%s)\"\n",
198 s, s);
ef416fc2 199 return (CUPS_BACKEND_OK);
200 }
bd7854cb 201 else if (argc < 6)
ef416fc2 202 {
bd7854cb 203 fprintf(stderr,
204 "Usage: %s job-id user title copies options [file ... fileN]\n",
ef416fc2 205 argv[0]);
206 return (CUPS_BACKEND_STOP);
207 }
208
209 /*
bd7854cb 210 * Get the (final) content type...
ef416fc2 211 */
212
bd7854cb 213 if ((content_type = getenv("FINAL_CONTENT_TYPE")) == NULL)
ed486911 214 if ((content_type = getenv("CONTENT_TYPE")) == NULL)
215 content_type = "application/octet-stream";
ef416fc2 216
217 /*
218 * Extract the hostname and printer name from the URI...
219 */
220
a4d04587 221 if (httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv),
222 method, sizeof(method), username, sizeof(username),
223 hostname, sizeof(hostname), &port,
224 resource, sizeof(resource)) < HTTP_URI_OK)
ef416fc2 225 {
a4d04587 226 fputs("ERROR: Missing device URI on command-line and no DEVICE_URI "
227 "environment variable!\n", stderr);
ef416fc2 228 return (CUPS_BACKEND_STOP);
229 }
230
231 if (!strcmp(method, "https"))
232 cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
233
ef416fc2 234 /*
235 * See if there are any options...
236 */
237
b423cd4c 238 compression = 0;
ef416fc2 239 version = 1;
240 waitjob = 1;
241 waitprinter = 1;
242
243 if ((optptr = strchr(resource, '?')) != NULL)
244 {
245 /*
246 * Yup, terminate the device name string and move to the first
247 * character of the optptr...
248 */
249
250 *optptr++ = '\0';
251
252 /*
253 * Then parse the optptr...
254 */
255
256 while (*optptr)
257 {
258 /*
259 * Get the name...
260 */
261
262 for (ptr = name; *optptr && *optptr != '=';)
263 if (ptr < (name + sizeof(name) - 1))
264 *ptr++ = *optptr++;
265 *ptr = '\0';
266
267 if (*optptr == '=')
268 {
269 /*
270 * Get the value...
271 */
272
273 optptr ++;
274
275 for (ptr = value; *optptr && *optptr != '+' && *optptr != '&';)
276 if (ptr < (value + sizeof(value) - 1))
277 *ptr++ = *optptr++;
278 *ptr = '\0';
279
f301802f 280 if (*optptr == '+' || *optptr == '&')
ef416fc2 281 optptr ++;
282 }
283 else
284 value[0] = '\0';
285
286 /*
287 * Process the option...
288 */
289
290 if (!strcasecmp(name, "waitjob"))
291 {
292 /*
293 * Wait for job completion?
294 */
295
296 waitjob = !strcasecmp(value, "on") ||
297 !strcasecmp(value, "yes") ||
298 !strcasecmp(value, "true");
299 }
300 else if (!strcasecmp(name, "waitprinter"))
301 {
302 /*
303 * Wait for printer idle?
304 */
305
306 waitprinter = !strcasecmp(value, "on") ||
307 !strcasecmp(value, "yes") ||
308 !strcasecmp(value, "true");
309 }
310 else if (!strcasecmp(name, "encryption"))
311 {
312 /*
313 * Enable/disable encryption?
314 */
315
316 if (!strcasecmp(value, "always"))
317 cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
318 else if (!strcasecmp(value, "required"))
319 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
320 else if (!strcasecmp(value, "never"))
321 cupsSetEncryption(HTTP_ENCRYPT_NEVER);
322 else if (!strcasecmp(value, "ifrequested"))
323 cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
324 else
325 {
326 fprintf(stderr, "ERROR: Unknown encryption option value \"%s\"!\n",
327 value);
328 }
329 }
330 else if (!strcasecmp(name, "version"))
331 {
332 if (!strcmp(value, "1.0"))
333 version = 0;
334 else if (!strcmp(value, "1.1"))
335 version = 1;
336 else
337 {
338 fprintf(stderr, "ERROR: Unknown version option value \"%s\"!\n",
339 value);
340 }
341 }
b423cd4c 342#ifdef HAVE_LIBZ
343 else if (!strcasecmp(name, "compression"))
344 {
345 compression = !strcasecmp(value, "true") ||
346 !strcasecmp(value, "yes") ||
347 !strcasecmp(value, "on") ||
348 !strcasecmp(value, "gzip");
349 }
350#endif /* HAVE_LIBZ */
ef416fc2 351 else
352 {
353 /*
354 * Unknown option...
355 */
356
357 fprintf(stderr, "ERROR: Unknown option \"%s\" with value \"%s\"!\n",
358 name, value);
359 }
360 }
361 }
362
b423cd4c 363 /*
364 * If we have 7 arguments, print the file named on the command-line.
365 * Otherwise, copy stdin to a temporary file and print the temporary
366 * file.
367 */
368
369 if (argc == 6)
370 {
371 /*
372 * Copy stdin to a temporary file...
373 */
374
375 int fd; /* File descriptor */
376 cups_file_t *fp; /* Temporary file */
377 char buffer[8192]; /* Buffer for copying */
378 int bytes; /* Number of bytes read */
379
380
381 if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0)
382 {
383 perror("ERROR: unable to create temporary file");
384 return (CUPS_BACKEND_FAILED);
385 }
386
387 if ((fp = cupsFileOpenFd(fd, compression ? "w9" : "w")) == NULL)
388 {
389 perror("ERROR: unable to open temporary file");
390 close(fd);
391 unlink(tmpfilename);
392 return (CUPS_BACKEND_FAILED);
393 }
394
395 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
396 if (cupsFileWrite(fp, buffer, bytes) < bytes)
397 {
398 perror("ERROR: unable to write to temporary file");
399 cupsFileClose(fp);
400 unlink(tmpfilename);
401 return (CUPS_BACKEND_FAILED);
402 }
403
404 cupsFileClose(fp);
405
406 /*
407 * Point to the single file from stdin...
408 */
409
410 filename = tmpfilename;
411 files = &filename;
412 num_files = 1;
413 }
414 else
415 {
416 /*
417 * Point to the files on the command-line...
418 */
419
420 num_files = argc - 6;
421 files = argv + 6;
422
423#ifdef HAVE_LIBZ
424 if (compression)
425 compress_files(num_files, files);
426#endif /* HAVE_LIBZ */
427 }
428
429 fprintf(stderr, "DEBUG: %d files to send in job...\n", num_files);
430
ef416fc2 431 /*
432 * Set the authentication info, if any...
433 */
434
435 cupsSetPasswordCB(password_cb);
436
437 if (username[0])
438 {
439 /*
440 * Use authenticaion information in the device URI...
441 */
442
443 if ((password = strchr(username, ':')) != NULL)
444 *password++ = '\0';
445
446 cupsSetUser(username);
447 }
448 else if (!getuid())
449 {
450 /*
451 * Try loading authentication information from the a##### file.
452 */
453
454 const char *request_root; /* CUPS_REQUESTROOT env var */
455 char afilename[1024], /* a##### filename */
456 aline[1024]; /* Line from file */
457 FILE *fp; /* File pointer */
458
459
460 if ((request_root = getenv("CUPS_REQUESTROOT")) != NULL)
461 {
462 /*
463 * Try opening authentication cache file...
464 */
465
466 snprintf(afilename, sizeof(afilename), "%s/a%05d", request_root,
467 atoi(argv[1]));
468 if ((fp = fopen(afilename, "r")) != NULL)
469 {
470 /*
471 * Read username...
472 */
473
474 if (fgets(aline, sizeof(aline), fp))
475 {
476 /*
477 * Decode username...
478 */
479
480 i = sizeof(username);
481 httpDecode64_2(username, &i, aline);
482
483 /*
484 * Read password...
485 */
486
487 if (fgets(aline, sizeof(aline), fp))
488 {
489 /*
490 * Decode password...
491 */
492
493 i = sizeof(password);
494 httpDecode64_2(password, &i, aline);
495 }
496 }
497
498 /*
499 * Close the file...
500 */
501
502 fclose(fp);
503 }
504 }
505 }
506
507 /*
508 * Try connecting to the remote server...
509 */
510
757d2cad 511 fputs("STATE: +connecting-to-device\n", stderr);
512
ef416fc2 513 do
514 {
515 fprintf(stderr, "INFO: Connecting to %s on port %d...\n", hostname, port);
516
517 if ((http = httpConnectEncrypt(hostname, port, cupsEncryption())) == NULL)
518 {
519 if (getenv("CLASS") != NULL)
520 {
521 /*
522 * If the CLASS environment variable is set, the job was submitted
523 * to a class and not to a specific queue. In this case, we want
524 * to abort immediately so that the job can be requeued on the next
525 * available printer in the class.
526 */
527
bd7854cb 528 fprintf(stderr,
529 "INFO: Unable to connect to %s, queuing on next printer in "
530 "class...\n",
ef416fc2 531 hostname);
532
533 if (argc == 6 || strcmp(filename, argv[6]))
534 unlink(filename);
535
536 /*
537 * Sleep 5 seconds to keep the job from requeuing too rapidly...
538 */
539
540 sleep(5);
541
542 return (CUPS_BACKEND_FAILED);
543 }
544
545 if (errno == ECONNREFUSED || errno == EHOSTDOWN ||
546 errno == EHOSTUNREACH)
547 {
bd7854cb 548 fprintf(stderr,
549 "INFO: Network host \'%s\' is busy; will retry in 30 "
550 "seconds...\n",
ef416fc2 551 hostname);
552 sleep(30);
553 }
554 else if (h_errno)
555 {
556 fprintf(stderr, "INFO: Unable to lookup host \'%s\' - %s\n",
557 hostname, hstrerror(h_errno));
558 sleep(30);
559 }
560 else
561 {
562 perror("ERROR: Unable to connect to IPP host");
563 sleep(30);
564 }
565 }
566 }
567 while (http == NULL);
568
757d2cad 569 fputs("STATE: -connecting-to-device\n", stderr);
ef416fc2 570 fprintf(stderr, "INFO: Connected to %s...\n", hostname);
571
572 /*
573 * Build a URI for the printer and fill the standard IPP attributes for
574 * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it
575 * might contain username:password information...
576 */
577
578 snprintf(uri, sizeof(uri), "%s://%s:%d%s", method, hostname, port, resource);
579
580 /*
581 * First validate the destination and see if the device supports multiple
582 * copies. We have to do this because some IPP servers (e.g. HP JetDirect)
583 * don't support the copies attribute...
584 */
585
fa73b229 586 copies_sup = NULL;
587 format_sup = NULL;
588 supported = NULL;
ef416fc2 589
590 do
591 {
592 /*
593 * Build the IPP request...
594 */
595
fa73b229 596 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
597 request->request.op.version[1] = version;
ef416fc2 598
599 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
600 NULL, uri);
601
602 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
603 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
604 NULL, pattrs);
605
606 /*
607 * Do the request...
608 */
609
610 fputs("DEBUG: Getting supported attributes...\n", stderr);
611
612 if ((supported = cupsDoRequest(http, request, resource)) == NULL)
613 ipp_status = cupsLastError();
614 else
615 ipp_status = supported->request.status.status_code;
616
617 if (ipp_status > IPP_OK_CONFLICT)
618 {
619 if (ipp_status == IPP_PRINTER_BUSY ||
620 ipp_status == IPP_SERVICE_UNAVAILABLE)
621 {
622 fputs("INFO: Printer busy; will retry in 10 seconds...\n", stderr);
623 report_printer_state(supported);
624 sleep(10);
625 }
626 else if ((ipp_status == IPP_BAD_REQUEST ||
627 ipp_status == IPP_VERSION_NOT_SUPPORTED) && version == 1)
628 {
629 /*
630 * Switch to IPP/1.0...
631 */
632
bd7854cb 633 fputs("INFO: Printer does not support IPP/1.1, trying IPP/1.0...\n",
634 stderr);
ef416fc2 635 version = 0;
636 httpReconnect(http);
637 }
638 else if (ipp_status == IPP_NOT_FOUND)
639 {
640 fputs("ERROR: Destination printer does not exist!\n", stderr);
641
642 if (supported)
643 ippDelete(supported);
644
645 return (CUPS_BACKEND_STOP);
646 }
647 else
648 {
649 fprintf(stderr, "ERROR: Unable to get printer status (%s)!\n",
650 ippErrorString(ipp_status));
651 sleep(10);
652 }
653
654 if (supported)
655 ippDelete(supported);
656
657 continue;
658 }
659 else if ((copies_sup = ippFindAttribute(supported, "copies-supported",
660 IPP_TAG_RANGE)) != NULL)
661 {
662 /*
663 * Has the "copies-supported" attribute - does it have an upper
664 * bound > 1?
665 */
666
667 if (copies_sup->values[0].range.upper <= 1)
668 copies_sup = NULL; /* No */
669 }
670
fa73b229 671 format_sup = ippFindAttribute(supported, "document-format-supported",
672 IPP_TAG_MIMETYPE);
ef416fc2 673
674 if (format_sup)
675 {
676 fprintf(stderr, "DEBUG: document-format-supported (%d values)\n",
677 format_sup->num_values);
678 for (i = 0; i < format_sup->num_values; i ++)
679 fprintf(stderr, "DEBUG: [%d] = \"%s\"\n", i,
680 format_sup->values[i].string.text);
681 }
682
683 report_printer_state(supported);
684 }
685 while (ipp_status > IPP_OK_CONFLICT);
686
687 /*
688 * See if the printer is accepting jobs and is not stopped; if either
689 * condition is true and we are printing to a class, requeue the job...
690 */
691
692 if (getenv("CLASS") != NULL)
693 {
694 printer_state = ippFindAttribute(supported, "printer-state",
695 IPP_TAG_ENUM);
696 printer_accepting = ippFindAttribute(supported, "printer-is-accepting-jobs",
697 IPP_TAG_BOOLEAN);
698
699 if (printer_state == NULL ||
bd7854cb 700 (printer_state->values[0].integer > IPP_PRINTER_PROCESSING &&
701 waitprinter) ||
ef416fc2 702 printer_accepting == NULL ||
703 !printer_accepting->values[0].boolean)
704 {
705 /*
706 * If the CLASS environment variable is set, the job was submitted
707 * to a class and not to a specific queue. In this case, we want
708 * to abort immediately so that the job can be requeued on the next
709 * available printer in the class.
710 */
711
bd7854cb 712 fprintf(stderr,
713 "INFO: Unable to queue job on %s, queuing on next printer in "
714 "class...\n",
ef416fc2 715 hostname);
716
717 ippDelete(supported);
718 httpClose(http);
719
720 if (argc == 6 || strcmp(filename, argv[6]))
721 unlink(filename);
722
723 /*
724 * Sleep 5 seconds to keep the job from requeuing too rapidly...
725 */
726
727 sleep(5);
728
729 return (CUPS_BACKEND_FAILED);
730 }
731 }
732
733 /*
734 * See if the printer supports multiple copies...
735 */
736
737 if (copies_sup || argc < 7)
738 copies = 1;
739 else
740 copies = atoi(argv[4]);
741
ef416fc2 742 /*
743 * Then issue the print-job request...
744 */
745
746 reasons = 0;
bd7854cb 747 job_id = 0;
ef416fc2 748
749 while (copies > 0)
750 {
751 /*
752 * Build the IPP request...
753 */
754
bd7854cb 755 if (job_cancelled)
756 break;
757
758 if (num_files > 1)
759 request = ippNewRequest(IPP_CREATE_JOB);
760 else
761 request = ippNewRequest(IPP_PRINT_JOB);
762
fa73b229 763 request->request.op.version[1] = version;
ef416fc2 764
765 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
766 NULL, uri);
767
768 fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri);
769
770 if (argv[2][0])
771 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
772 "requesting-user-name", NULL, argv[2]);
773
774 fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]);
775
776 if (argv[3][0])
777 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
778 argv[3]);
779
780 fprintf(stderr, "DEBUG: job-name = \"%s\"\n", argv[3]);
781
b423cd4c 782#ifdef HAVE_LIBZ
783 if (compression)
784 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
785 "compression", NULL, "gzip");
786#endif /* HAVE_LIBZ */
787
ef416fc2 788 /*
789 * Handle options on the command-line...
790 */
791
792 options = NULL;
793 num_options = cupsParseOptions(argv[5], 0, &options);
794
795#ifdef __APPLE__
bd7854cb 796 if (content_type != NULL &&
797 !strcasecmp(content_type, "application/pictwps") && num_files == 1)
ef416fc2 798 {
799 if (format_sup != NULL)
800 {
801 for (i = 0; i < format_sup->num_values; i ++)
bd7854cb 802 if (!strcasecmp(content_type, format_sup->values[i].string.text))
ef416fc2 803 break;
804 }
805
806 if (format_sup == NULL || i >= format_sup->num_values)
807 {
808 /*
809 * Remote doesn't support "application/pictwps" (i.e. it's not MacOS X)
810 * so convert the document to PostScript...
811 */
812
813 if (run_pictwps_filter(argv, filename))
814 return (CUPS_BACKEND_FAILED);
815
816 filename = pstmpname;
817
818 /*
bd7854cb 819 * Change the MIME type to application/postscript and change the
820 * number of copies to 1...
ef416fc2 821 */
822
823 content_type = "application/postscript";
bd7854cb 824 copies = 1;
ef416fc2 825 }
826 }
827#endif /* __APPLE__ */
828
829 if (content_type != NULL && format_sup != NULL)
830 {
831 for (i = 0; i < format_sup->num_values; i ++)
bd7854cb 832 if (!strcasecmp(content_type, format_sup->values[i].string.text))
ef416fc2 833 break;
834
835 if (i < format_sup->num_values)
836 num_options = cupsAddOption("document-format", content_type,
837 num_options, &options);
838 }
839
840 if (copies_sup)
841 {
842 /*
843 * Only send options if the destination printer supports the copies
844 * attribute. This is a hack for the HP JetDirect implementation of
845 * IPP, which does not accept extension attributes and incorrectly
846 * reports a client-error-bad-request error instead of the
847 * successful-ok-unsupported-attributes status. In short, at least
848 * some HP implementations of IPP are non-compliant.
849 */
850
851 cupsEncodeOptions(request, num_options, options);
852 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies",
853 atoi(argv[4]));
854 }
855
856 cupsFreeOptions(num_options, options);
857
858 /*
859 * If copies aren't supported, then we are likely dealing with an HP
860 * JetDirect. The HP IPP implementation seems to close the connection
861 * after every request (that is, it does *not* implement HTTP Keep-
862 * Alive, which is REQUIRED by HTTP/1.1...
863 */
864
865 if (!copies_sup)
866 httpReconnect(http);
867
868 /*
869 * Do the request...
870 */
871
bd7854cb 872 if (num_files > 1)
873 response = cupsDoRequest(http, request, resource);
ef416fc2 874 else
bd7854cb 875 response = cupsDoFileRequest(http, request, resource, files[0]);
876
877 ipp_status = cupsLastError();
ef416fc2 878
879 if (ipp_status > IPP_OK_CONFLICT)
880 {
881 job_id = 0;
882
bd7854cb 883 if (job_cancelled)
884 break;
885
ef416fc2 886 if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
887 ipp_status == IPP_PRINTER_BUSY)
888 {
889 fputs("INFO: Printer is busy; retrying print job...\n", stderr);
890 sleep(10);
891 }
892 else
893 fprintf(stderr, "ERROR: Print file was not accepted (%s)!\n",
bd7854cb 894 cupsLastErrorString());
ef416fc2 895 }
896 else if ((job_id_attr = ippFindAttribute(response, "job-id",
897 IPP_TAG_INTEGER)) == NULL)
898 {
899 fputs("NOTICE: Print file accepted - job ID unknown.\n", stderr);
900 job_id = 0;
901 }
902 else
903 {
904 job_id = job_id_attr->values[0].integer;
905 fprintf(stderr, "NOTICE: Print file accepted - job ID %d.\n", job_id);
906 }
907
bd7854cb 908 ippDelete(response);
909
910 if (job_cancelled)
911 break;
912
913 if (job_id && num_files > 1)
914 {
915 for (i = 0; i < num_files; i ++)
916 {
917 request = ippNewRequest(IPP_SEND_DOCUMENT);
918
919 request->request.op.version[1] = version;
920
921 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
922 NULL, uri);
923
924 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
925 job_id);
926
927 if (argv[2][0])
928 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
929 "requesting-user-name", NULL, argv[2]);
930
931 if ((i + 1) == num_files)
932 ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
933
934 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
935 "document-format", NULL, content_type);
936
937 ippDelete(cupsDoFileRequest(http, request, resource, files[i]));
938
939 if (cupsLastError() > IPP_OK_CONFLICT)
940 {
941 ipp_status = cupsLastError();
942
943 fprintf(stderr, "ERROR: Unable to add file %d to job: %s\n",
944 job_id, cupsLastErrorString());
945 break;
946 }
947 }
948 }
ef416fc2 949
950 if (ipp_status <= IPP_OK_CONFLICT && argc > 6)
951 {
952 fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1);
953 copies --;
954 }
955 else if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
956 ipp_status == IPP_PRINTER_BUSY)
957 break;
958 else
959 copies --;
960
961 /*
962 * Wait for the job to complete...
963 */
964
965 if (!job_id || !waitjob)
966 continue;
967
968 fputs("INFO: Waiting for job to complete...\n", stderr);
969
bd7854cb 970 for (; !job_cancelled;)
ef416fc2 971 {
972 /*
973 * Build an IPP_GET_JOB_ATTRIBUTES request...
974 */
975
fa73b229 976 request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
977 request->request.op.version[1] = version;
ef416fc2 978
979 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
980 NULL, uri);
981
982 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
983 job_id);
984
985 if (argv[2][0])
986 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
987 "requesting-user-name", NULL, argv[2]);
988
989 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
990 "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]),
991 NULL, jattrs);
992
993 /*
994 * Do the request...
995 */
996
997 if (!copies_sup)
998 httpReconnect(http);
999
bd7854cb 1000 response = cupsDoRequest(http, request, resource);
1001 ipp_status = cupsLastError();
ef416fc2 1002
1003 if (ipp_status == IPP_NOT_FOUND)
1004 {
1005 /*
1006 * Job has gone away and/or the server has no job history...
1007 */
1008
1009 ippDelete(response);
1010
1011 ipp_status = IPP_OK;
1012 break;
1013 }
1014
1015 if (ipp_status > IPP_OK_CONFLICT)
1016 {
1017 if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
1018 ipp_status != IPP_PRINTER_BUSY)
1019 {
bd7854cb 1020 ippDelete(response);
ef416fc2 1021
1022 fprintf(stderr, "ERROR: Unable to get job %d attributes (%s)!\n",
1023 job_id, ippErrorString(ipp_status));
1024 break;
1025 }
1026 }
1027
bd7854cb 1028 if (response)
ef416fc2 1029 {
1030 if ((job_state = ippFindAttribute(response, "job-state",
1031 IPP_TAG_ENUM)) != NULL)
1032 {
1033 /*
1034 * Stop polling if the job is finished or pending-held...
1035 */
1036
1037 if (job_state->values[0].integer > IPP_JOB_PROCESSING ||
1038 job_state->values[0].integer == IPP_JOB_HELD)
1039 {
fa73b229 1040 if ((job_sheets = ippFindAttribute(response,
1041 "job-media-sheets-completed",
1042 IPP_TAG_INTEGER)) != NULL)
bd7854cb 1043 fprintf(stderr, "PAGE: total %d\n",
1044 job_sheets->values[0].integer);
ef416fc2 1045
1046 ippDelete(response);
1047 break;
1048 }
1049 }
1050 }
1051
bd7854cb 1052 ippDelete(response);
ef416fc2 1053
1054 /*
1055 * Check the printer state and report it if necessary...
1056 */
1057
fa73b229 1058 check_printer_state(http, uri, resource, argv[2], version);
ef416fc2 1059
1060 /*
1061 * Wait 10 seconds before polling again...
1062 */
1063
1064 sleep(10);
1065 }
1066 }
1067
1068 /*
bd7854cb 1069 * Cancel the job as needed...
ef416fc2 1070 */
1071
bd7854cb 1072 if (job_cancelled && job_id)
1073 cancel_job(http, uri, job_id, resource, argv[2], version);
1074
1075 /*
1076 * Check the printer state and report it if necessary...
1077 */
ef416fc2 1078
fa73b229 1079 check_printer_state(http, uri, resource, argv[2], version);
ef416fc2 1080
1081 /*
1082 * Free memory...
1083 */
1084
1085 httpClose(http);
1086
bd7854cb 1087 ippDelete(supported);
ef416fc2 1088
1089 /*
1090 * Remove the temporary file(s) if necessary...
1091 */
1092
1093 if (tmpfilename[0])
1094 unlink(tmpfilename);
1095
b423cd4c 1096#ifdef HAVE_LIBZ
1097 if (compression)
1098 {
1099 for (i = 0; i < num_files; i ++)
1100 unlink(files[i]);
1101 }
1102#endif /* HAVE_LIBZ */
1103
ef416fc2 1104#ifdef __APPLE__
1105 if (pstmpname[0])
1106 unlink(pstmpname);
1107#endif /* __APPLE__ */
1108
1109 /*
1110 * Return the queue status...
1111 */
1112
1113 return (ipp_status > IPP_OK_CONFLICT ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
1114}
1115
1116
bd7854cb 1117/*
1118 * 'cancel_job()' - Cancel a print job.
1119 */
1120
1121static void
1122cancel_job(http_t *http, /* I - HTTP connection */
1123 const char *uri, /* I - printer-uri */
1124 int id, /* I - job-id */
1125 const char *resource, /* I - Resource path */
1126 const char *user, /* I - requesting-user-name */
1127 int version) /* I - IPP version */
1128{
1129 ipp_t *request; /* Cancel-Job request */
1130
1131
1132 fputs("INFO: Cancelling print job...\n", stderr);
1133
1134 request = ippNewRequest(IPP_CANCEL_JOB);
1135 request->request.op.version[1] = version;
1136
1137 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1138 NULL, uri);
1139 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", id);
1140
1141 if (user && user[0])
1142 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1143 "requesting-user-name", NULL, user);
1144
1145 /*
1146 * Do the request...
1147 */
1148
1149 ippDelete(cupsDoRequest(http, request, resource));
1150
1151 if (cupsLastError() > IPP_OK_CONFLICT)
1152 fprintf(stderr, "ERROR: Unable to cancel job %d: %s\n", id,
1153 cupsLastErrorString());
1154}
1155
1156
ef416fc2 1157/*
1158 * 'check_printer_state()' - Check the printer state...
1159 */
1160
bd7854cb 1161static void
fa73b229 1162check_printer_state(
1163 http_t *http, /* I - HTTP connection */
1164 const char *uri, /* I - Printer URI */
1165 const char *resource, /* I - Resource path */
1166 const char *user, /* I - Username, if any */
1167 int version) /* I - IPP version */
ef416fc2 1168{
1169 ipp_t *request, /* IPP request */
1170 *response; /* IPP response */
1171
1172
1173 /*
1174 * Check on the printer state...
1175 */
1176
fa73b229 1177 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
1178 request->request.op.version[1] = version;
ef416fc2 1179
1180 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1181 NULL, uri);
1182
1183 if (user && user[0])
1184 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1185 "requesting-user-name", NULL, user);
1186
1187 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1188 "requested-attributes", NULL, "printer-state-reasons");
1189
1190 /*
1191 * Do the request...
1192 */
1193
1194 if ((response = cupsDoRequest(http, request, resource)) != NULL)
1195 {
1196 report_printer_state(response);
1197 ippDelete(response);
1198 }
1199}
1200
1201
b423cd4c 1202#ifdef HAVE_LIBZ
1203/*
1204 * 'compress_files()' - Compress print files...
1205 */
1206
1207static void
1208compress_files(int num_files, /* I - Number of files */
1209 char **files) /* I - Files */
1210{
1211 int i, /* Looping var */
1212 fd; /* Temporary file descriptor */
1213 ssize_t bytes; /* Bytes read/written */
1214 size_t total; /* Total bytes read */
1215 cups_file_t *in, /* Input file */
1216 *out; /* Output file */
1217 struct stat outinfo; /* Output file information */
1218 char filename[1024], /* Temporary filename */
a74454a7 1219 buffer[32768]; /* Copy buffer */
b423cd4c 1220
1221
1222 fprintf(stderr, "DEBUG: Compressing %d job files...\n", num_files);
1223 for (i = 0; i < num_files; i ++)
1224 {
1225 if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
1226 {
1227 perror("ERROR: Unable to create temporary compressed print file");
1228 exit(CUPS_BACKEND_FAILED);
1229 }
1230
1231 if ((out = cupsFileOpenFd(fd, "w9")) == NULL)
1232 {
1233 perror("ERROR: Unable to open temporary compressed print file");
1234 exit(CUPS_BACKEND_FAILED);
1235 }
1236
1237 if ((in = cupsFileOpen(files[i], "r")) == NULL)
1238 {
1239 fprintf(stderr, "ERROR: Unable to open print file \"%s\": %s\n",
1240 files[i], strerror(errno));
1241 cupsFileClose(out);
1242 exit(CUPS_BACKEND_FAILED);
1243 }
1244
1245 total = 0;
1246 while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0)
1247 if (cupsFileWrite(out, buffer, bytes) < bytes)
1248 {
757d2cad 1249 fprintf(stderr, "ERROR: Unable to write " CUPS_LLFMT " bytes to \"%s\": %s\n",
1250 CUPS_LLCAST bytes, filename, strerror(errno));
b423cd4c 1251 cupsFileClose(in);
1252 cupsFileClose(out);
1253 exit(CUPS_BACKEND_FAILED);
1254 }
1255 else
1256 total += bytes;
1257
1258 cupsFileClose(out);
1259 cupsFileClose(in);
1260
1261 files[i] = strdup(filename);
1262
1263 if (!stat(filename, &outinfo))
1264 fprintf(stderr,
1265 "DEBUG: File %d compressed to %.1f%% of original size, "
1266 CUPS_LLFMT " bytes...\n",
e1d6a774 1267 i + 1, 100.0 * outinfo.st_size / total,
1268 CUPS_LLCAST outinfo.st_size);
b423cd4c 1269 }
1270}
1271#endif /* HAVE_LIBZ */
1272
1273
ef416fc2 1274/*
1275 * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
1276 */
1277
bd7854cb 1278static const char * /* O - Password */
fa73b229 1279password_cb(const char *prompt) /* I - Prompt (not used) */
ef416fc2 1280{
1281 (void)prompt;
1282
1283 if (password)
1284 return (password);
1285 else
1286 {
1287 /*
1288 * If there is no password set in the device URI, return the
1289 * "authentication required" exit code...
1290 */
1291
1292 if (tmpfilename[0])
1293 unlink(tmpfilename);
1294
1295#ifdef __APPLE__
1296 if (pstmpname[0])
1297 unlink(pstmpname);
1298#endif /* __APPLE__ */
1299
1300 exit(CUPS_BACKEND_AUTH_REQUIRED);
1301 }
1302}
1303
1304
1305/*
1306 * 'report_printer_state()' - Report the printer state.
1307 */
1308
bd7854cb 1309static int /* O - Number of reasons shown */
ef416fc2 1310report_printer_state(ipp_t *ipp) /* I - IPP response */
1311{
1312 int i; /* Looping var */
1313 int count; /* Count of reasons shown... */
1314 ipp_attribute_t *reasons; /* printer-state-reasons */
1315 const char *reason; /* Current reason */
1316 const char *message; /* Message to show */
1317 char unknown[1024]; /* Unknown message string */
1318 const char *prefix; /* Prefix for STATE: line */
1319 char state[1024]; /* State string */
1320
1321
1322 if ((reasons = ippFindAttribute(ipp, "printer-state-reasons",
1323 IPP_TAG_KEYWORD)) == NULL)
1324 return (0);
1325
1326 state[0] = '\0';
1327 prefix = "STATE: ";
1328
1329 for (i = 0, count = 0; i < reasons->num_values; i ++)
1330 {
1331 reason = reasons->values[i].string.text;
1332
1333 strlcat(state, prefix, sizeof(state));
1334 strlcat(state, reason, sizeof(state));
1335
1336 prefix = ",";
1337 message = NULL;
1338
1339 if (!strncmp(reason, "media-needed", 12))
1340 message = "Media tray needs to be filled.";
1341 else if (!strncmp(reason, "media-jam", 9))
1342 message = "Media jam!";
1343 else if (!strncmp(reason, "moving-to-paused", 16) ||
1344 !strncmp(reason, "paused", 6) ||
1345 !strncmp(reason, "shutdown", 8))
1346 message = "Printer off-line.";
1347 else if (!strncmp(reason, "toner-low", 9))
1348 message = "Toner low.";
1349 else if (!strncmp(reason, "toner-empty", 11))
1350 message = "Out of toner!";
1351 else if (!strncmp(reason, "cover-open", 10))
1352 message = "Cover open.";
1353 else if (!strncmp(reason, "interlock-open", 14))
1354 message = "Interlock open.";
1355 else if (!strncmp(reason, "door-open", 9))
1356 message = "Door open.";
1357 else if (!strncmp(reason, "input-tray-missing", 18))
1358 message = "Media tray missing!";
1359 else if (!strncmp(reason, "media-low", 9))
1360 message = "Media tray almost empty.";
1361 else if (!strncmp(reason, "media-empty", 11))
1362 message = "Media tray empty!";
1363 else if (!strncmp(reason, "output-tray-missing", 19))
1364 message = "Output tray missing!";
1365 else if (!strncmp(reason, "output-area-almost-full", 23))
1366 message = "Output bin almost full.";
1367 else if (!strncmp(reason, "output-area-full", 16))
1368 message = "Output bin full!";
1369 else if (!strncmp(reason, "marker-supply-low", 17))
1370 message = "Ink/toner almost empty.";
1371 else if (!strncmp(reason, "marker-supply-empty", 19))
1372 message = "Ink/toner empty!";
1373 else if (!strncmp(reason, "marker-waste-almost-full", 24))
1374 message = "Ink/toner waste bin almost full.";
1375 else if (!strncmp(reason, "marker-waste-full", 17))
1376 message = "Ink/toner waste bin full!";
1377 else if (!strncmp(reason, "fuser-over-temp", 15))
1378 message = "Fuser temperature high!";
1379 else if (!strncmp(reason, "fuser-under-temp", 16))
1380 message = "Fuser temperature low!";
1381 else if (!strncmp(reason, "opc-near-eol", 12))
1382 message = "OPC almost at end-of-life.";
1383 else if (!strncmp(reason, "opc-life-over", 13))
1384 message = "OPC at end-of-life!";
1385 else if (!strncmp(reason, "developer-low", 13))
1386 message = "Developer almost empty.";
1387 else if (!strncmp(reason, "developer-empty", 15))
1388 message = "Developer empty!";
1389 else if (strstr(reason, "error") != NULL)
1390 {
1391 message = unknown;
1392
1393 snprintf(unknown, sizeof(unknown), "Unknown printer error (%s)!",
1394 reason);
1395 }
1396
1397 if (message)
1398 {
1399 count ++;
1400 if (strstr(reasons->values[i].string.text, "error"))
1401 fprintf(stderr, "ERROR: %s\n", message);
1402 else if (strstr(reasons->values[i].string.text, "warning"))
1403 fprintf(stderr, "WARNING: %s\n", message);
1404 else
1405 fprintf(stderr, "INFO: %s\n", message);
1406 }
1407 }
1408
1409 fprintf(stderr, "%s\n", state);
1410
1411 return (count);
1412}
1413
1414
1415#ifdef __APPLE__
1416/*
1417 * 'run_pictwps_filter()' - Convert PICT files to PostScript when printing
1418 * remotely.
1419 *
1420 * This step is required because the PICT format is not documented and
1421 * subject to change, so developing a filter for other OS's is infeasible.
1422 * Also, fonts required by the PICT file need to be embedded on the
1423 * client side (which has the fonts), so we run the filter to get a
1424 * PostScript file for printing...
1425 */
1426
bd7854cb 1427static int /* O - Exit status of filter */
fa73b229 1428run_pictwps_filter(char **argv, /* I - Command-line arguments */
1429 const char *filename)/* I - Filename */
ef416fc2 1430{
fa73b229 1431 struct stat fileinfo; /* Print file information */
1432 const char *ppdfile; /* PPD file for destination printer */
1433 int pid; /* Child process ID */
1434 int fd; /* Temporary file descriptor */
1435 int status; /* Exit status of filter */
1436 const char *printer; /* PRINTER env var */
1437 static char ppdenv[1024]; /* PPD environment variable */
ef416fc2 1438
1439
1440 /*
1441 * First get the PPD file for the printer...
1442 */
1443
1444 printer = getenv("PRINTER");
1445 if (!printer)
1446 {
1447 fputs("ERROR: PRINTER environment variable not defined!\n", stderr);
1448 return (-1);
1449 }
1450
1451 if ((ppdfile = cupsGetPPD(printer)) == NULL)
1452 {
1453 fprintf(stderr, "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n",
1454 printer, ippErrorString(cupsLastError()));
1455 /*return (-1);*/
1456 }
1457 else
1458 {
1459 snprintf(ppdenv, sizeof(ppdenv), "PPD=%s", ppdfile);
1460 putenv(ppdenv);
1461 }
1462
1463 /*
1464 * Then create a temporary file for printing...
1465 */
1466
1467 if ((fd = cupsTempFd(pstmpname, sizeof(pstmpname))) < 0)
1468 {
1469 fprintf(stderr, "ERROR: Unable to create temporary file - %s.\n",
1470 strerror(errno));
1471 if (ppdfile)
1472 unlink(ppdfile);
1473 return (-1);
1474 }
1475
1476 /*
1477 * Get the owner of the spool file - it is owned by the user we want to run
1478 * as...
1479 */
1480
1481 if (argv[6])
1482 stat(argv[6], &fileinfo);
1483 else
1484 {
1485 /*
1486 * Use the OSX defaults, as an up-stream filter created the PICT
1487 * file...
1488 */
1489
1490 fileinfo.st_uid = 1;
1491 fileinfo.st_gid = 80;
1492 }
1493
1494 if (ppdfile)
1495 chown(ppdfile, fileinfo.st_uid, fileinfo.st_gid);
1496
1497 fchown(fd, fileinfo.st_uid, fileinfo.st_gid);
1498
1499 /*
1500 * Finally, run the filter to convert the file...
1501 */
1502
1503 if ((pid = fork()) == 0)
1504 {
1505 /*
1506 * Child process for pictwpstops... Redirect output of pictwpstops to a
1507 * file...
1508 */
1509
1510 close(1);
1511 dup(fd);
1512 close(fd);
1513
1514 if (!getuid())
1515 {
1516 /*
1517 * Change to an unpriviledged user...
1518 */
1519
1520 setgid(fileinfo.st_gid);
1521 setuid(fileinfo.st_uid);
1522 }
1523
1524 execlp("pictwpstops", printer, argv[1], argv[2], argv[3], argv[4], argv[5],
1525 filename, NULL);
1526 perror("ERROR: Unable to exec pictwpstops");
1527 return (errno);
1528 }
1529
1530 close(fd);
1531
1532 if (pid < 0)
1533 {
1534 /*
1535 * Error!
1536 */
1537
1538 perror("ERROR: Unable to fork pictwpstops");
1539 unlink(filename);
1540 if (ppdfile)
1541 unlink(ppdfile);
1542 return (-1);
1543 }
1544
1545 /*
1546 * Now wait for the filter to complete...
1547 */
1548
1549 if (wait(&status) < 0)
1550 {
1551 perror("ERROR: Unable to wait for pictwpstops");
1552 close(fd);
1553 unlink(filename);
1554 if (ppdfile)
1555 unlink(ppdfile);
1556 return (-1);
1557 }
1558
1559 if (ppdfile)
1560 unlink(ppdfile);
1561
1562 close(fd);
1563
1564 if (status)
1565 {
1566 if (status >= 256)
1567 fprintf(stderr, "ERROR: pictwpstops exited with status %d!\n",
1568 status / 256);
1569 else
1570 fprintf(stderr, "ERROR: pictwpstops exited on signal %d!\n",
1571 status);
1572
1573 unlink(filename);
1574 return (status);
1575 }
1576
1577 /*
1578 * Return with no errors..
1579 */
1580
1581 return (0);
1582}
1583#endif /* __APPLE__ */
1584
1585
1586/*
1587 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1588 */
1589
1590static void
1591sigterm_handler(int sig) /* I - Signal */
1592{
1593 (void)sig; /* remove compiler warnings... */
1594
bd7854cb 1595 if (!job_cancelled)
1596 {
1597 /*
1598 * Flag that the job should be cancelled...
1599 */
1600
1601 job_cancelled = 1;
1602 return;
1603 }
1604
ef416fc2 1605 /*
bd7854cb 1606 * The scheduler already tried to cancel us once, now just terminate
1607 * after removing our temp files!
ef416fc2 1608 */
1609
1610 if (tmpfilename[0])
1611 unlink(tmpfilename);
1612
1613#ifdef __APPLE__
1614 if (pstmpname[0])
1615 unlink(pstmpname);
1616#endif /* __APPLE__ */
1617
1618 exit(1);
1619}
1620
1621
1622/*
c07d5b2d 1623 * End of "$Id: ipp.c 181 2006-06-22 20:01:18Z jlovell $".
ef416fc2 1624 */