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