4 # See http://www.cups.org/documentation.php/api-filter.html for more info...
26 +ipp14: ipp14.o ../cups/$(LIBCUPS) libbackend.a
28 + $(CC) $(LDFLAGS) -o ipp14 ipp14.o libbackend.a $(LIBS)
41 + * "$Id: ipp.c 8950 2010-01-14 22:40:19Z mike $"
43 + * IPP backend for the Common UNIX Printing System (CUPS).
45 + * Copyright 2007-2010 by Apple Inc.
46 + * Copyright 1997-2007 by Easy Software Products, all rights reserved.
48 + * These coded instructions, statements, and computer programs are the
49 + * property of Apple Inc. and are protected by Federal copyright
50 + * law. Distribution and use rights are outlined in the file "LICENSE.txt"
51 + * "LICENSE" which should have been included with this file. If this
52 + * file is missing or damaged, see the license at "http://www.cups.org/".
54 + * This file is subject to the Apple OS-Developed Software exception.
58 + * main() - Send a file to the printer or server.
59 + * cancel_job() - Cancel a print job.
60 + * check_printer_state() - Check the printer state...
61 + * compress_files() - Compress print files...
62 + * password_cb() - Disable the password prompt for
63 + * cupsDoFileRequest().
64 + * report_attr() - Report an IPP attribute value.
65 + * report_printer_state() - Report the printer state.
66 + * run_pictwps_filter() - Convert PICT files to PostScript when printing
68 + * sigterm_handler() - Handle 'terminate' signals that stop the backend.
72 + * Include necessary headers.
75 +#include <cups/http-private.h>
76 +#include "backend-private.h"
77 +#include <sys/types.h>
78 +#include <sys/stat.h>
79 +#include <sys/wait.h>
85 +static char *password = NULL; /* Password for device URI */
86 +static int password_tries = 0; /* Password tries */
87 +static const char *auth_info_required = "none";
88 + /* New auth-info-required value */
90 +static char pstmpname[1024] = ""; /* Temporary PostScript file name */
91 +#endif /* __APPLE__ */
92 +static char tmpfilename[1024] = ""; /* Temporary spool file name */
93 +static int job_cancelled = 0; /* Job cancelled? */
97 + * Local functions...
100 +static void cancel_job(http_t *http, const char *uri, int id,
101 + const char *resource, const char *user, int version);
102 +static void check_printer_state(http_t *http, const char *uri,
103 + const char *resource, const char *user,
104 + int version, int job_id);
106 +static void compress_files(int num_files, char **files);
107 +#endif /* HAVE_LIBZ */
108 +static const char *password_cb(const char *);
109 +static void report_attr(ipp_attribute_t *attr);
110 +static int report_printer_state(ipp_t *ipp, int job_id);
113 +static int run_pictwps_filter(char **argv, const char *filename);
114 +#endif /* __APPLE__ */
115 +static void sigterm_handler(int sig);
119 + * 'main()' - Send a file to the printer or server.
123 + * printer-uri job-id user title copies options [file]
126 +int /* O - Exit status */
127 +main(int argc, /* I - Number of command-line args */
128 + char *argv[]) /* I - Command-line arguments */
130 + int i; /* Looping var */
131 + int send_options; /* Send job options? */
132 + int num_options; /* Number of printer options */
133 + cups_option_t *options; /* Printer options */
134 + const char *device_uri; /* Device URI */
135 + char scheme[255], /* Scheme in URI */
136 + hostname[1024], /* Hostname */
137 + username[255], /* Username info */
138 + resource[1024], /* Resource info (printer name) */
139 + addrname[256], /* Address name */
140 + *optptr, /* Pointer to URI options */
141 + *name, /* Name of option */
142 + *value, /* Value of option */
143 + sep; /* Separator character */
144 + int snmp_fd, /* SNMP socket */
145 + start_count, /* Page count via SNMP at start */
146 + page_count, /* Page count via SNMP */
147 + have_supplies; /* Printer supports supply levels? */
148 + int num_files; /* Number of files to print */
149 + char **files, /* Files to print */
150 + *filename; /* Pointer to single filename */
151 + int port; /* Port number (not used) */
152 + char uri[HTTP_MAX_URI]; /* Updated URI without user/pass */
153 + ipp_status_t ipp_status; /* Status of IPP request */
154 + http_t *http; /* HTTP connection */
155 + ipp_t *request, /* IPP request */
156 + *response, /* IPP response */
157 + *supported; /* get-printer-attributes response */
158 + time_t start_time; /* Time of first connect */
159 + int recoverable; /* Recoverable error shown? */
160 + int contimeout; /* Connection timeout */
161 + int delay; /* Delay for retries... */
162 + int compression, /* Do compression of the job data? */
163 + waitjob, /* Wait for job complete? */
164 + waitprinter; /* Wait for printer ready? */
165 + ipp_attribute_t *job_id_attr; /* job-id attribute */
166 + int job_id; /* job-id value */
167 + ipp_attribute_t *job_sheets; /* job-media-sheets-completed */
168 + ipp_attribute_t *job_state; /* job-state */
169 + ipp_attribute_t *copies_sup; /* copies-supported */
170 + ipp_attribute_t *format_sup; /* document-format-supported */
171 + ipp_attribute_t *printer_state; /* printer-state attribute */
172 + ipp_attribute_t *printer_accepting; /* printer-is-accepting-jobs */
173 + int copies, /* Number of copies for job */
174 + copies_remaining; /* Number of copies remaining */
175 + const char *content_type, /* CONTENT_TYPE environment variable */
176 + *final_content_type; /* FINAL_CONTENT_TYPE environment var */
177 +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
178 + struct sigaction action; /* Actions for POSIX signals */
179 +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
180 + int version; /* IPP version */
181 + static const char * const pattrs[] =
182 + { /* Printer attributes we want */
183 + "com.apple.print.recoverable-message",
184 + "copies-supported",
185 + "document-format-supported",
187 + "marker-high-levels",
189 + "marker-low-levels",
193 + "printer-is-accepting-jobs",
195 + "printer-state-message",
196 + "printer-state-reasons",
198 + static const char * const jattrs[] =
199 + { /* Job attributes we want */
200 + "job-media-sheets-completed",
206 + * Make sure status messages are not buffered...
209 + setbuf(stderr, NULL);
212 + * Ignore SIGPIPE and catch SIGTERM signals...
216 + sigset(SIGPIPE, SIG_IGN);
217 + sigset(SIGTERM, sigterm_handler);
218 +#elif defined(HAVE_SIGACTION)
219 + memset(&action, 0, sizeof(action));
220 + action.sa_handler = SIG_IGN;
221 + sigaction(SIGPIPE, &action, NULL);
223 + sigemptyset(&action.sa_mask);
224 + sigaddset(&action.sa_mask, SIGTERM);
225 + action.sa_handler = sigterm_handler;
226 + sigaction(SIGTERM, &action, NULL);
228 + signal(SIGPIPE, SIG_IGN);
229 + signal(SIGTERM, sigterm_handler);
230 +#endif /* HAVE_SIGSET */
233 + * Check command-line...
240 + if ((s = strrchr(argv[0], '/')) != NULL)
245 + printf("network %s \"Unknown\" \"%s (%s)\"\n",
246 + s, _cupsLangString(cupsLangDefault(),
247 + _("Internet Printing Protocol")), s);
248 + return (CUPS_BACKEND_OK);
252 + _cupsLangPrintf(stderr,
253 + _("Usage: %s job-id user title copies options [file]\n"),
255 + return (CUPS_BACKEND_STOP);
259 + * Get the (final) content type...
262 + if ((content_type = getenv("CONTENT_TYPE")) == NULL)
263 + content_type = "application/octet-stream";
265 + if ((final_content_type = getenv("FINAL_CONTENT_TYPE")) == NULL)
267 + final_content_type = content_type;
269 + if (!strncmp(final_content_type, "printer/", 8))
270 + final_content_type = "application/vnd.cups-raw";
274 + * Extract the hostname and printer name from the URI...
277 + if ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
278 + return (CUPS_BACKEND_FAILED);
280 + httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme),
281 + username, sizeof(username), hostname, sizeof(hostname), &port,
282 + resource, sizeof(resource));
285 + port = IPP_PORT; /* Default to port 631 */
287 + if (!strcmp(scheme, "https"))
288 + cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
290 + cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
293 + * See if there are any options...
300 + contimeout = 7 * 24 * 60 * 60;
302 + if ((optptr = strchr(resource, '?')) != NULL)
305 + * Yup, terminate the device name string and move to the first
306 + * character of the optptr...
312 + * Then parse the optptr...
323 + while (*optptr && *optptr != '=' && *optptr != '+' && *optptr != '&')
326 + if ((sep = *optptr) != '\0')
337 + while (*optptr && *optptr != '+' && *optptr != '&')
344 + value = (char *)"";
347 + * Process the option...
350 + if (!strcasecmp(name, "waitjob"))
353 + * Wait for job completion?
356 + waitjob = !strcasecmp(value, "on") ||
357 + !strcasecmp(value, "yes") ||
358 + !strcasecmp(value, "true");
360 + else if (!strcasecmp(name, "waitprinter"))
363 + * Wait for printer idle?
366 + waitprinter = !strcasecmp(value, "on") ||
367 + !strcasecmp(value, "yes") ||
368 + !strcasecmp(value, "true");
370 + else if (!strcasecmp(name, "encryption"))
373 + * Enable/disable encryption?
376 + if (!strcasecmp(value, "always"))
377 + cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
378 + else if (!strcasecmp(value, "required"))
379 + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
380 + else if (!strcasecmp(value, "never"))
381 + cupsSetEncryption(HTTP_ENCRYPT_NEVER);
382 + else if (!strcasecmp(value, "ifrequested"))
383 + cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
386 + _cupsLangPrintf(stderr,
387 + _("ERROR: Unknown encryption option value \"%s\"!\n"),
391 + else if (!strcasecmp(name, "version"))
393 + if (!strcmp(value, "1.0"))
395 + else if (!strcmp(value, "1.1"))
397 + else if (!strcmp(value, "2.0"))
399 + else if (!strcmp(value, "2.1"))
403 + _cupsLangPrintf(stderr,
404 + _("ERROR: Unknown version option value \"%s\"!\n"),
409 + else if (!strcasecmp(name, "compression"))
411 + compression = !strcasecmp(value, "true") ||
412 + !strcasecmp(value, "yes") ||
413 + !strcasecmp(value, "on") ||
414 + !strcasecmp(value, "gzip");
416 +#endif /* HAVE_LIBZ */
417 + else if (!strcasecmp(name, "contimeout"))
420 + * Set the connection timeout...
423 + if (atoi(value) > 0)
424 + contimeout = atoi(value);
429 + * Unknown option...
432 + _cupsLangPrintf(stderr,
433 + _("ERROR: Unknown option \"%s\" with value \"%s\"!\n"),
440 + * If we have 7 arguments, print the file named on the command-line.
441 + * Otherwise, copy stdin to a temporary file and print the temporary
448 + * Copy stdin to a temporary file...
451 + int fd; /* File descriptor */
452 + http_addrlist_t *addrlist; /* Address list */
453 + off_t tbytes; /* Total bytes copied */
456 + fputs("STATE: +connecting-to-device\n", stderr);
457 + fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);
459 + if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, "1")) == NULL)
461 + _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"),
463 + return (CUPS_BACKEND_STOP);
466 + snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family);
468 + if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0)
470 + _cupsLangPrintError("ERROR", _("Unable to create temporary file"));
471 + return (CUPS_BACKEND_FAILED);
474 + _cupsLangPuts(stderr, _("INFO: Copying print data...\n"));
476 + tbytes = backendRunLoop(-1, fd, snmp_fd, &(addrlist->addr), 0, 0,
477 + backendNetworkSideCB);
480 + _cupsSNMPClose(snmp_fd);
482 + httpAddrFreeList(addrlist);
487 + * Don't try printing files less than 2 bytes...
492 + _cupsLangPuts(stderr, _("ERROR: Empty print file!\n"));
493 + unlink(tmpfilename);
494 + return (CUPS_BACKEND_FAILED);
498 + * Point to the single file from stdin...
501 + filename = tmpfilename;
509 + * Point to the files on the command-line...
512 + num_files = argc - 6;
518 + compress_files(num_files, files);
519 +#endif /* HAVE_LIBZ */
522 + fprintf(stderr, "DEBUG: %d files to send in job...\n", num_files);
525 + * Set the authentication info, if any...
528 + cupsSetPasswordCB(password_cb);
533 + * Use authenticaion information in the device URI...
536 + if ((password = strchr(username, ':')) != NULL)
537 + *password++ = '\0';
539 + cupsSetUser(username);
541 + else if (!getuid())
544 + * Try loading authentication information from the environment.
547 + const char *ptr = getenv("AUTH_USERNAME");
552 + password = getenv("AUTH_PASSWORD");
556 + * Try connecting to the remote server...
561 + start_time = time(NULL);
563 + fputs("STATE: +connecting-to-device\n", stderr);
567 + fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port);
568 + _cupsLangPuts(stderr, _("INFO: Connecting to printer...\n"));
570 + if ((http = httpConnectEncrypt(hostname, port, cupsEncryption())) == NULL)
575 + if (getenv("CLASS") != NULL)
578 + * If the CLASS environment variable is set, the job was submitted
579 + * to a class and not to a specific queue. In this case, we want
580 + * to abort immediately so that the job can be requeued on the next
581 + * available printer in the class.
584 + _cupsLangPuts(stderr,
585 + _("INFO: Unable to contact printer, queuing on next "
586 + "printer in class...\n"));
588 + if (tmpfilename[0])
589 + unlink(tmpfilename);
592 + * Sleep 5 seconds to keep the job from requeuing too rapidly...
597 + return (CUPS_BACKEND_FAILED);
600 + if (errno == ECONNREFUSED || errno == EHOSTDOWN ||
601 + errno == EHOSTUNREACH)
603 + if (contimeout && (time(NULL) - start_time) > contimeout)
605 + _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n"));
606 + return (CUPS_BACKEND_FAILED);
611 + _cupsLangPrintf(stderr,
612 + _("WARNING: recoverable: Network host \'%s\' is busy; "
613 + "will retry in %d seconds...\n"),
623 + _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"),
625 + return (CUPS_BACKEND_STOP);
631 + fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno));
632 + _cupsLangPuts(stderr,
633 + _("ERROR: recoverable: Unable to connect to printer; will "
634 + "retry in 30 seconds...\n"));
642 + while (http == NULL);
644 + if (job_cancelled || !http)
646 + if (tmpfilename[0])
647 + unlink(tmpfilename);
649 + return (CUPS_BACKEND_FAILED);
652 + fputs("STATE: -connecting-to-device\n", stderr);
653 + _cupsLangPuts(stderr, _("INFO: Connected to printer...\n"));
656 + if (http->hostaddr->addr.sa_family == AF_INET6)
657 + fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6)...\n",
658 + httpAddrString(http->hostaddr, addrname, sizeof(addrname)),
659 + ntohs(http->hostaddr->ipv6.sin6_port));
661 +#endif /* AF_INET6 */
662 + if (http->hostaddr->addr.sa_family == AF_INET)
663 + fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4)...\n",
664 + httpAddrString(http->hostaddr, addrname, sizeof(addrname)),
665 + ntohs(http->hostaddr->ipv4.sin_port));
668 + * See if the printer supports SNMP...
671 + if ((snmp_fd = _cupsSNMPOpen(http->hostaddr->addr.sa_family)) >= 0)
672 + have_supplies = !backendSNMPSupplies(snmp_fd, http->hostaddr, &start_count,
675 + have_supplies = start_count = 0;
678 + * Build a URI for the printer and fill the standard IPP attributes for
679 + * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it
680 + * might contain username:password information...
683 + httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, NULL, hostname,
687 + * First validate the destination and see if the device supports multiple
688 + * copies. We have to do this because some IPP servers (e.g. HP JetDirect)
689 + * don't support the copies attribute...
699 + * Check for side-channel requests...
702 + backendCheckSideChannel(snmp_fd, http->hostaddr);
705 + * Build the IPP request...
708 + request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
709 + request->request.op.version[0] = version / 10;
710 + request->request.op.version[1] = version % 10;
712 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
715 + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
716 + "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
720 + * Do the request...
723 + fputs("DEBUG: Getting supported attributes...\n", stderr);
725 + if (http->version < HTTP_1_1)
726 + httpReconnect(http);
728 + if ((supported = cupsDoRequest(http, request, resource)) == NULL)
729 + ipp_status = cupsLastError();
731 + ipp_status = supported->request.status.status_code;
733 + if (ipp_status > IPP_OK_CONFLICT)
735 + if (ipp_status == IPP_PRINTER_BUSY ||
736 + ipp_status == IPP_SERVICE_UNAVAILABLE)
738 + if (contimeout && (time(NULL) - start_time) > contimeout)
740 + _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n"));
741 + return (CUPS_BACKEND_FAILED);
746 + _cupsLangPrintf(stderr,
747 + _("WARNING: recoverable: Network host \'%s\' is busy; "
748 + "will retry in %d seconds...\n"),
751 + report_printer_state(supported, 0);
758 + else if ((ipp_status == IPP_BAD_REQUEST ||
759 + ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10)
762 + * Switch to IPP/1.0...
765 + _cupsLangPrintf(stderr,
766 + _("INFO: Printer does not support IPP/%d.%d, trying "
767 + "IPP/1.0...\n"), version / 10, version % 10);
769 + httpReconnect(http);
771 + else if (ipp_status == IPP_NOT_FOUND)
773 + _cupsLangPuts(stderr, _("ERROR: Destination printer does not exist!\n"));
776 + ippDelete(supported);
778 + return (CUPS_BACKEND_STOP);
780 + else if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
782 + if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
784 + auth_info_required = "negotiate";
786 + fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
787 + return (CUPS_BACKEND_AUTH_REQUIRED);
791 + _cupsLangPrintf(stderr,
792 + _("ERROR: Unable to get printer status (%s)!\n"),
793 + cupsLastErrorString());
798 + ippDelete(supported);
802 + else if ((copies_sup = ippFindAttribute(supported, "copies-supported",
803 + IPP_TAG_RANGE)) != NULL)
806 + * Has the "copies-supported" attribute - does it have an upper
810 + if (copies_sup->values[0].range.upper <= 1)
811 + copies_sup = NULL; /* No */
814 + format_sup = ippFindAttribute(supported, "document-format-supported",
819 + fprintf(stderr, "DEBUG: document-format-supported (%d values)\n",
820 + format_sup->num_values);
821 + for (i = 0; i < format_sup->num_values; i ++)
822 + fprintf(stderr, "DEBUG: [%d] = \"%s\"\n", i,
823 + format_sup->values[i].string.text);
826 + report_printer_state(supported, 0);
828 + while (ipp_status > IPP_OK_CONFLICT);
831 + * See if the printer is accepting jobs and is not stopped; if either
832 + * condition is true and we are printing to a class, requeue the job...
835 + if (getenv("CLASS") != NULL)
837 + printer_state = ippFindAttribute(supported, "printer-state",
839 + printer_accepting = ippFindAttribute(supported, "printer-is-accepting-jobs",
842 + if (printer_state == NULL ||
843 + (printer_state->values[0].integer > IPP_PRINTER_PROCESSING &&
845 + printer_accepting == NULL ||
846 + !printer_accepting->values[0].boolean)
849 + * If the CLASS environment variable is set, the job was submitted
850 + * to a class and not to a specific queue. In this case, we want
851 + * to abort immediately so that the job can be requeued on the next
852 + * available printer in the class.
855 + _cupsLangPuts(stderr,
856 + _("INFO: Unable to contact printer, queuing on next "
857 + "printer in class...\n"));
859 + ippDelete(supported);
862 + if (tmpfilename[0])
863 + unlink(tmpfilename);
866 + * Sleep 5 seconds to keep the job from requeuing too rapidly...
871 + return (CUPS_BACKEND_FAILED);
878 + * If we've shown a recoverable error make sure the printer proxies
879 + * have a chance to see the recovered message. Not pretty but
880 + * necessary for now...
883 + fputs("INFO: recovered: \n", stderr);
888 + * See if the printer supports multiple copies...
891 + copies = atoi(argv[4]);
893 + if (copies_sup || argc < 7)
895 + copies_remaining = 1;
901 + copies_remaining = copies;
904 + * Then issue the print-job request...
909 + while (copies_remaining > 0)
912 + * Check for side-channel requests...
915 + backendCheckSideChannel(snmp_fd, http->hostaddr);
918 + * Build the IPP request...
925 + request = ippNewRequest(IPP_CREATE_JOB);
927 + request = ippNewRequest(IPP_PRINT_JOB);
929 + request->request.op.version[0] = version / 10;
930 + request->request.op.version[1] = version % 10;
932 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
935 + fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri);
938 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
939 + "requesting-user-name", NULL, argv[2]);
941 + fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]);
944 + * Only add a "job-name" attribute if the remote server supports
945 + * copy generation - some IPP implementations like HP's don't seem
946 + * to like UTF-8 job names (STR #1837)...
949 + if (argv[3][0] && copies_sup)
950 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
953 + fprintf(stderr, "DEBUG: job-name = \"%s\"\n", argv[3]);
957 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
958 + "compression", NULL, "gzip");
959 +#endif /* HAVE_LIBZ */
962 + * Handle options on the command-line...
966 + num_options = cupsParseOptions(argv[5], 0, &options);
969 + if (!strcasecmp(final_content_type, "application/pictwps") &&
972 + if (format_sup != NULL)
974 + for (i = 0; i < format_sup->num_values; i ++)
975 + if (!strcasecmp(final_content_type, format_sup->values[i].string.text))
979 + if (format_sup == NULL || i >= format_sup->num_values)
982 + * Remote doesn't support "application/pictwps" (i.e. it's not MacOS X)
983 + * so convert the document to PostScript...
986 + if (run_pictwps_filter(argv, files[0]))
991 + if (tmpfilename[0])
992 + unlink(tmpfilename);
994 + return (CUPS_BACKEND_FAILED);
997 + files[0] = pstmpname;
1000 + * Change the MIME type to application/postscript and change the
1001 + * number of copies to 1...
1004 + final_content_type = "application/postscript";
1006 + copies_remaining = 1;
1010 +#endif /* __APPLE__ */
1012 + if (format_sup != NULL)
1014 + for (i = 0; i < format_sup->num_values; i ++)
1015 + if (!strcasecmp(final_content_type, format_sup->values[i].string.text))
1018 + if (i < format_sup->num_values)
1019 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1020 + "document-format", NULL, final_content_type);
1023 + if (copies_sup && version > 10 && send_options)
1026 + * Only send options if the destination printer supports the copies
1027 + * attribute and IPP/1.1. This is a hack for the HP and Lexmark
1028 + * implementations of IPP, which do not accept extension attributes
1029 + * and incorrectly report a client-error-bad-request error instead of
1030 + * the successful-ok-unsupported-attributes status. In short, at least
1031 + * some HP and Lexmark implementations of IPP are non-compliant.
1034 + cupsEncodeOptions(request, num_options, options);
1036 + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies",
1040 + cupsFreeOptions(num_options, options);
1043 + * If copies aren't supported, then we are likely dealing with an HP
1044 + * JetDirect. The HP IPP implementation seems to close the connection
1045 + * after every request - that is, it does *not* implement HTTP Keep-
1046 + * Alive, which is REQUIRED by HTTP/1.1...
1050 + httpReconnect(http);
1053 + * Do the request...
1056 + if (http->version < HTTP_1_1)
1057 + httpReconnect(http);
1059 + if (num_files > 1)
1060 + response = cupsDoRequest(http, request, resource);
1062 + response = cupsDoFileRequest(http, request, resource, files[0]);
1064 + ipp_status = cupsLastError();
1066 + if (ipp_status > IPP_OK_CONFLICT)
1070 + if (job_cancelled)
1073 + if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1074 + ipp_status == IPP_PRINTER_BUSY)
1076 + _cupsLangPuts(stderr,
1077 + _("INFO: Printer busy; will retry in 10 seconds...\n"));
1080 + else if ((ipp_status == IPP_BAD_REQUEST ||
1081 + ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10)
1084 + * Switch to IPP/1.0...
1087 + _cupsLangPrintf(stderr,
1088 + _("INFO: Printer does not support IPP/%d.%d, trying "
1089 + "IPP/1.0...\n"), version / 10, version % 10);
1091 + httpReconnect(http);
1096 + * Update auth-info-required as needed...
1099 + _cupsLangPrintf(stderr, _("ERROR: Print file was not accepted (%s)!\n"),
1100 + cupsLastErrorString());
1102 + if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
1104 + fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n",
1105 + httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE));
1108 + * Normal authentication goes through the password callback, which sets
1109 + * auth_info_required to "username,password". Kerberos goes directly
1110 + * through GSSAPI, so look for Negotiate in the WWW-Authenticate header
1111 + * here and set auth_info_required as needed...
1114 + if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
1116 + auth_info_required = "negotiate";
1120 + else if ((job_id_attr = ippFindAttribute(response, "job-id",
1121 + IPP_TAG_INTEGER)) == NULL)
1123 + _cupsLangPuts(stderr,
1124 + _("NOTICE: Print file accepted - job ID unknown.\n"));
1129 + job_id = job_id_attr->values[0].integer;
1130 + _cupsLangPrintf(stderr, _("NOTICE: Print file accepted - job ID %d.\n"),
1134 + ippDelete(response);
1136 + if (job_cancelled)
1139 + if (job_id && num_files > 1)
1141 + for (i = 0; i < num_files; i ++)
1144 + * Check for side-channel requests...
1147 + backendCheckSideChannel(snmp_fd, http->hostaddr);
1150 + * Send the next file in the job...
1153 + request = ippNewRequest(IPP_SEND_DOCUMENT);
1154 + request->request.op.version[0] = version / 10;
1155 + request->request.op.version[1] = version % 10;
1157 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1160 + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
1164 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1165 + "requesting-user-name", NULL, argv[2]);
1167 + if ((i + 1) == num_files)
1168 + ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
1170 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1171 + "document-format", NULL, content_type);
1173 + if (http->version < HTTP_1_1)
1174 + httpReconnect(http);
1176 + ippDelete(cupsDoFileRequest(http, request, resource, files[i]));
1178 + if (cupsLastError() > IPP_OK_CONFLICT)
1180 + ipp_status = cupsLastError();
1182 + _cupsLangPrintf(stderr,
1183 + _("ERROR: Unable to add file %d to job: %s\n"),
1184 + job_id, cupsLastErrorString());
1190 + if (ipp_status <= IPP_OK_CONFLICT && argc > 6)
1192 + fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1);
1193 + copies_remaining --;
1195 + else if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1196 + ipp_status == IPP_PRINTER_BUSY)
1199 + copies_remaining --;
1202 + * Wait for the job to complete...
1205 + if (!job_id || !waitjob)
1208 + _cupsLangPuts(stderr, _("INFO: Waiting for job to complete...\n"));
1210 + for (delay = 1; !job_cancelled;)
1213 + * Check for side-channel requests...
1216 + backendCheckSideChannel(snmp_fd, http->hostaddr);
1219 + * Build an IPP_GET_JOB_ATTRIBUTES request...
1222 + request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
1223 + request->request.op.version[0] = version / 10;
1224 + request->request.op.version[1] = version % 10;
1226 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1229 + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
1233 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1234 + "requesting-user-name", NULL, argv[2]);
1236 + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1237 + "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]),
1241 + * Do the request...
1244 + if (!copies_sup || http->version < HTTP_1_1)
1245 + httpReconnect(http);
1247 + response = cupsDoRequest(http, request, resource);
1248 + ipp_status = cupsLastError();
1250 + if (ipp_status == IPP_NOT_FOUND)
1253 + * Job has gone away and/or the server has no job history...
1256 + ippDelete(response);
1258 + ipp_status = IPP_OK;
1262 + if (ipp_status > IPP_OK_CONFLICT)
1264 + if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
1265 + ipp_status != IPP_PRINTER_BUSY)
1267 + ippDelete(response);
1269 + _cupsLangPrintf(stderr,
1270 + _("ERROR: Unable to get job %d attributes (%s)!\n"),
1271 + job_id, cupsLastErrorString());
1278 + if ((job_state = ippFindAttribute(response, "job-state",
1279 + IPP_TAG_ENUM)) != NULL)
1282 + * Stop polling if the job is finished or pending-held...
1285 + if (job_state->values[0].integer > IPP_JOB_STOPPED)
1287 + if ((job_sheets = ippFindAttribute(response,
1288 + "job-media-sheets-completed",
1289 + IPP_TAG_INTEGER)) != NULL)
1290 + fprintf(stderr, "PAGE: total %d\n",
1291 + job_sheets->values[0].integer);
1293 + ippDelete(response);
1300 + * If the printer does not return a job-state attribute, it does not
1301 + * conform to the IPP specification - break out immediately and fail
1305 + fputs("DEBUG: No job-state available from printer - stopping queue.\n",
1307 + ipp_status = IPP_INTERNAL_ERROR;
1312 + ippDelete(response);
1315 + * Check the printer state and report it if necessary...
1318 + check_printer_state(http, uri, resource, argv[2], version, job_id);
1321 + * Wait 1-10 seconds before polling again...
1333 + * Cancel the job as needed...
1336 + if (job_cancelled && job_id)
1337 + cancel_job(http, uri, job_id, resource, argv[2], version);
1340 + * Check the printer state and report it if necessary...
1343 + check_printer_state(http, uri, resource, argv[2], version, job_id);
1346 + * Collect the final page count as needed...
1349 + if (have_supplies &&
1350 + !backendSNMPSupplies(snmp_fd, http->hostaddr, &page_count, NULL) &&
1351 + page_count > start_count)
1352 + fprintf(stderr, "PAGE: total %d\n", page_count - start_count);
1356 + * See if we used Kerberos at all...
1360 + auth_info_required = "negotiate";
1361 +#endif /* HAVE_GSSAPI */
1369 + ippDelete(supported);
1372 + * Remove the temporary file(s) if necessary...
1375 + if (tmpfilename[0])
1376 + unlink(tmpfilename);
1381 + for (i = 0; i < num_files; i ++)
1384 +#endif /* HAVE_LIBZ */
1388 + unlink(pstmpname);
1389 +#endif /* __APPLE__ */
1392 + * Return the queue status...
1395 + fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
1397 + if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
1398 + return (CUPS_BACKEND_AUTH_REQUIRED);
1399 + else if (ipp_status == IPP_INTERNAL_ERROR)
1400 + return (CUPS_BACKEND_STOP);
1401 + else if (ipp_status > IPP_OK_CONFLICT)
1402 + return (CUPS_BACKEND_FAILED);
1405 + _cupsLangPuts(stderr, _("INFO: Ready to print.\n"));
1406 + return (CUPS_BACKEND_OK);
1412 + * 'cancel_job()' - Cancel a print job.
1416 +cancel_job(http_t *http, /* I - HTTP connection */
1417 + const char *uri, /* I - printer-uri */
1418 + int id, /* I - job-id */
1419 + const char *resource, /* I - Resource path */
1420 + const char *user, /* I - requesting-user-name */
1421 + int version) /* I - IPP version */
1423 + ipp_t *request; /* Cancel-Job request */
1426 + _cupsLangPuts(stderr, _("INFO: Canceling print job...\n"));
1428 + request = ippNewRequest(IPP_CANCEL_JOB);
1429 + request->request.op.version[0] = version / 10;
1430 + request->request.op.version[1] = version % 10;
1432 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1434 + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", id);
1436 + if (user && user[0])
1437 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1438 + "requesting-user-name", NULL, user);
1441 + * Do the request...
1444 + if (http->version < HTTP_1_1)
1445 + httpReconnect(http);
1447 + ippDelete(cupsDoRequest(http, request, resource));
1449 + if (cupsLastError() > IPP_OK_CONFLICT)
1450 + _cupsLangPrintf(stderr, _("ERROR: Unable to cancel job %d: %s\n"), id,
1451 + cupsLastErrorString());
1456 + * 'check_printer_state()' - Check the printer state...
1460 +check_printer_state(
1461 + http_t *http, /* I - HTTP connection */
1462 + const char *uri, /* I - Printer URI */
1463 + const char *resource, /* I - Resource path */
1464 + const char *user, /* I - Username, if any */
1465 + int version, /* I - IPP version */
1466 + int job_id) /* I - Current job ID */
1468 + ipp_t *request, /* IPP request */
1469 + *response; /* IPP response */
1470 + static const char * const attrs[] = /* Attributes we want */
1472 + "com.apple.print.recoverable-message",
1478 + "printer-state-message",
1479 + "printer-state-reasons"
1484 + * Check on the printer state...
1487 + request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
1488 + request->request.op.version[0] = version / 10;
1489 + request->request.op.version[1] = version % 10;
1491 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1494 + if (user && user[0])
1495 + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1496 + "requesting-user-name", NULL, user);
1498 + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1499 + "requested-attributes",
1500 + (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
1503 + * Do the request...
1506 + if (http->version < HTTP_1_1)
1507 + httpReconnect(http);
1509 + if ((response = cupsDoRequest(http, request, resource)) != NULL)
1511 + report_printer_state(response, job_id);
1512 + ippDelete(response);
1519 + * 'compress_files()' - Compress print files...
1523 +compress_files(int num_files, /* I - Number of files */
1524 + char **files) /* I - Files */
1526 + int i, /* Looping var */
1527 + fd; /* Temporary file descriptor */
1528 + ssize_t bytes; /* Bytes read/written */
1529 + size_t total; /* Total bytes read */
1530 + cups_file_t *in, /* Input file */
1531 + *out; /* Output file */
1532 + struct stat outinfo; /* Output file information */
1533 + char filename[1024], /* Temporary filename */
1534 + buffer[32768]; /* Copy buffer */
1537 + fprintf(stderr, "DEBUG: Compressing %d job files...\n", num_files);
1538 + for (i = 0; i < num_files; i ++)
1540 + if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
1542 + _cupsLangPrintf(stderr,
1543 + _("ERROR: Unable to create temporary compressed print "
1544 + "file: %s\n"), strerror(errno));
1545 + exit(CUPS_BACKEND_FAILED);
1548 + if ((out = cupsFileOpenFd(fd, "w9")) == NULL)
1550 + _cupsLangPrintf(stderr,
1551 + _("ERROR: Unable to open temporary compressed print "
1552 + "file: %s\n"), strerror(errno));
1553 + exit(CUPS_BACKEND_FAILED);
1556 + if ((in = cupsFileOpen(files[i], "r")) == NULL)
1558 + _cupsLangPrintf(stderr,
1559 + _("ERROR: Unable to open print file \"%s\": %s\n"),
1560 + files[i], strerror(errno));
1561 + cupsFileClose(out);
1562 + exit(CUPS_BACKEND_FAILED);
1566 + while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0)
1567 + if (cupsFileWrite(out, buffer, bytes) < bytes)
1569 + _cupsLangPrintf(stderr,
1570 + _("ERROR: Unable to write %d bytes to \"%s\": %s\n"),
1571 + (int)bytes, filename, strerror(errno));
1572 + cupsFileClose(in);
1573 + cupsFileClose(out);
1574 + exit(CUPS_BACKEND_FAILED);
1579 + cupsFileClose(out);
1580 + cupsFileClose(in);
1582 + files[i] = strdup(filename);
1584 + if (!stat(filename, &outinfo))
1586 + "DEBUG: File %d compressed to %.1f%% of original size, "
1587 + CUPS_LLFMT " bytes...\n",
1588 + i + 1, 100.0 * outinfo.st_size / total,
1589 + CUPS_LLCAST outinfo.st_size);
1592 +#endif /* HAVE_LIBZ */
1596 + * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
1599 +static const char * /* O - Password */
1600 +password_cb(const char *prompt) /* I - Prompt (not used) */
1605 + * Remember that we need to authenticate...
1608 + auth_info_required = "username,password";
1610 + if (password && *password && password_tries < 3)
1612 + password_tries ++;
1614 + return (password);
1619 + * Give up after 3 tries or if we don't have a password to begin with...
1628 + * 'report_attr()' - Report an IPP attribute value.
1632 +report_attr(ipp_attribute_t *attr) /* I - Attribute */
1634 + int i; /* Looping var */
1635 + char value[1024], /* Value string */
1636 + *valptr, /* Pointer into value string */
1637 + *attrptr; /* Pointer into attribute value */
1641 + * Convert the attribute values into quoted strings...
1644 + for (i = 0, valptr = value;
1645 + i < attr->num_values && valptr < (value + sizeof(value) - 10);
1651 + switch (attr->value_tag)
1653 + case IPP_TAG_INTEGER :
1654 + case IPP_TAG_ENUM :
1655 + snprintf(valptr, sizeof(value) - (valptr - value), "%d",
1656 + attr->values[i].integer);
1657 + valptr += strlen(valptr);
1660 + case IPP_TAG_TEXT :
1661 + case IPP_TAG_NAME :
1662 + case IPP_TAG_KEYWORD :
1664 + for (attrptr = attr->values[i].string.text;
1665 + *attrptr && valptr < (value + sizeof(value) - 10);
1668 + if (*attrptr == '\\' || *attrptr == '\"')
1671 + *valptr++ = *attrptr;
1678 + * Unsupported value type...
1688 + * Tell the scheduler about the new values...
1691 + fprintf(stderr, "ATTR: %s=%s\n", attr->name, value);
1696 + * 'report_printer_state()' - Report the printer state.
1699 +static int /* O - Number of reasons shown */
1700 +report_printer_state(ipp_t *ipp, /* I - IPP response */
1701 + int job_id) /* I - Current job ID */
1703 + int i; /* Looping var */
1704 + int count; /* Count of reasons shown... */
1705 + ipp_attribute_t *caprm, /* com.apple.print.recoverable-message */
1706 + *psm, /* printer-state-message */
1707 + *reasons, /* printer-state-reasons */
1708 + *marker; /* marker-* attributes */
1709 + const char *reason; /* Current reason */
1710 + const char *prefix; /* Prefix for STATE: line */
1711 + char state[1024]; /* State string */
1712 + int saw_caprw; /* Saw com.apple.print.recoverable-warning state */
1715 + if ((psm = ippFindAttribute(ipp, "printer-state-message",
1716 + IPP_TAG_TEXT)) != NULL)
1717 + fprintf(stderr, "INFO: %s\n", psm->values[0].string.text);
1719 + if ((reasons = ippFindAttribute(ipp, "printer-state-reasons",
1720 + IPP_TAG_KEYWORD)) == NULL)
1725 + prefix = "STATE: ";
1727 + for (i = 0, count = 0; i < reasons->num_values; i ++)
1729 + reason = reasons->values[i].string.text;
1731 + if (!strcmp(reason, "com.apple.print.recoverable-warning"))
1733 + else if (strcmp(reason, "paused"))
1735 + strlcat(state, prefix, sizeof(state));
1736 + strlcat(state, reason, sizeof(state));
1743 + fprintf(stderr, "%s\n", state);
1746 + * Relay com.apple.print.recoverable-message...
1749 + if ((caprm = ippFindAttribute(ipp, "com.apple.print.recoverable-message",
1750 + IPP_TAG_TEXT)) != NULL)
1751 + fprintf(stderr, "WARNING: %s: %s\n",
1752 + saw_caprw ? "recoverable" : "recovered",
1753 + caprm->values[0].string.text);
1756 + * Relay the current marker-* attribute values...
1759 + if ((marker = ippFindAttribute(ipp, "marker-colors", IPP_TAG_NAME)) != NULL)
1760 + report_attr(marker);
1761 + if ((marker = ippFindAttribute(ipp, "marker-high-levels",
1762 + IPP_TAG_INTEGER)) != NULL)
1763 + report_attr(marker);
1764 + if ((marker = ippFindAttribute(ipp, "marker-levels",
1765 + IPP_TAG_INTEGER)) != NULL)
1766 + report_attr(marker);
1767 + if ((marker = ippFindAttribute(ipp, "marker-low-levels",
1768 + IPP_TAG_INTEGER)) != NULL)
1769 + report_attr(marker);
1770 + if ((marker = ippFindAttribute(ipp, "marker-message", IPP_TAG_TEXT)) != NULL)
1771 + report_attr(marker);
1772 + if ((marker = ippFindAttribute(ipp, "marker-names", IPP_TAG_NAME)) != NULL)
1773 + report_attr(marker);
1774 + if ((marker = ippFindAttribute(ipp, "marker-types", IPP_TAG_KEYWORD)) != NULL)
1775 + report_attr(marker);
1783 + * 'run_pictwps_filter()' - Convert PICT files to PostScript when printing
1786 + * This step is required because the PICT format is not documented and
1787 + * subject to change, so developing a filter for other OS's is infeasible.
1788 + * Also, fonts required by the PICT file need to be embedded on the
1789 + * client side (which has the fonts), so we run the filter to get a
1790 + * PostScript file for printing...
1793 +static int /* O - Exit status of filter */
1794 +run_pictwps_filter(char **argv, /* I - Command-line arguments */
1795 + const char *filename)/* I - Filename */
1797 + struct stat fileinfo; /* Print file information */
1798 + const char *ppdfile; /* PPD file for destination printer */
1799 + int pid; /* Child process ID */
1800 + int fd; /* Temporary file descriptor */
1801 + int status; /* Exit status of filter */
1802 + const char *printer; /* PRINTER env var */
1803 + static char ppdenv[1024]; /* PPD environment variable */
1807 + * First get the PPD file for the printer...
1810 + printer = getenv("PRINTER");
1813 + _cupsLangPuts(stderr,
1814 + _("ERROR: PRINTER environment variable not defined!\n"));
1818 + if ((ppdfile = cupsGetPPD(printer)) == NULL)
1820 + _cupsLangPrintf(stderr,
1821 + _("ERROR: Unable to get PPD file for printer \"%s\" - "
1822 + "%s.\n"), printer, cupsLastErrorString());
1826 + snprintf(ppdenv, sizeof(ppdenv), "PPD=%s", ppdfile);
1831 + * Then create a temporary file for printing...
1834 + if ((fd = cupsTempFd(pstmpname, sizeof(pstmpname))) < 0)
1836 + _cupsLangPrintError("ERROR", _("Unable to create temporary file"));
1843 + * Get the owner of the spool file - it is owned by the user we want to run
1848 + stat(argv[6], &fileinfo);
1852 + * Use the OSX defaults, as an up-stream filter created the PICT
1856 + fileinfo.st_uid = 1;
1857 + fileinfo.st_gid = 80;
1861 + chown(ppdfile, fileinfo.st_uid, fileinfo.st_gid);
1863 + fchown(fd, fileinfo.st_uid, fileinfo.st_gid);
1866 + * Finally, run the filter to convert the file...
1869 + if ((pid = fork()) == 0)
1872 + * Child process for pictwpstops... Redirect output of pictwpstops to a
1882 + * Change to an unpriviledged user...
1885 + if (setgid(fileinfo.st_gid))
1888 + if (setuid(fileinfo.st_uid))
1892 + execlp("pictwpstops", printer, argv[1], argv[2], argv[3], argv[4], argv[5],
1894 + _cupsLangPrintf(stderr, _("ERROR: Unable to exec pictwpstops: %s\n"),
1907 + _cupsLangPrintf(stderr, _("ERROR: Unable to fork pictwpstops: %s\n"),
1915 + * Now wait for the filter to complete...
1918 + if (wait(&status) < 0)
1920 + _cupsLangPrintf(stderr, _("ERROR: Unable to wait for pictwpstops: %s\n"),
1935 + if (status >= 256)
1936 + _cupsLangPrintf(stderr, _("ERROR: pictwpstops exited with status %d!\n"),
1939 + _cupsLangPrintf(stderr, _("ERROR: pictwpstops exited on signal %d!\n"),
1946 + * Return with no errors..
1951 +#endif /* __APPLE__ */
1955 + * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1959 +sigterm_handler(int sig) /* I - Signal */
1961 + (void)sig; /* remove compiler warnings... */
1963 + if (!job_cancelled)
1966 + * Flag that the job should be cancelled...
1969 + job_cancelled = 1;
1974 + * The scheduler already tried to cancel us once, now just terminate
1975 + * after removing our temp files!
1978 + if (tmpfilename[0])
1979 + unlink(tmpfilename);
1983 + unlink(pstmpname);
1984 +#endif /* __APPLE__ */
1991 + * End of "$Id: ipp.c 8950 2010-01-14 22:40:19Z mike $".