]> git.pld-linux.org Git - packages/cups.git/blame - add-ipp-backend-of-cups-1.4.patch
- rel 2; add ipp14 backend; fixes for ipp15 backend; other fixes - everything from...
[packages/cups.git] / add-ipp-backend-of-cups-1.4.patch
CommitLineData
ba7599c9
AM
1--- a/backend/Makefile
2+++ b/backend/Makefile
3@@ -21,12 +21,12 @@
4 # Object files...
5 #
6
7-RBACKENDS = ipp lpd $(DNSSD_BACKEND)
8+RBACKENDS = ipp ipp14 lpd $(DNSSD_BACKEND)
9 UBACKENDS = $(LEGACY_BACKENDS) serial snmp socket usb
10 UNITTESTS = test1284 testbackend testsupplies
11 TARGETS = libbackend.a $(RBACKENDS) $(UBACKENDS)
12 LIBOBJS = ieee1284.o network.o runloop.o snmp-supplies.o
13-OBJS = ipp.o lpd.o dnssd.o parallel.o serial.o snmp.o \
14+OBJS = ipp.o ipp14.o lpd.o dnssd.o parallel.o serial.o snmp.o \
15 socket.o test1284.o testbackend.o testsupplies.o usb.o
16
17
18@@ -218,6 +218,17 @@
19
20
21 #
22+# ipp14
23+#
24+
25+ipp14: ipp14.o ../cups/$(LIBCUPS) libbackend.a
26+ echo Linking $@...
27+ $(CC) $(LDFLAGS) -o ipp14 ipp14.o libbackend.a $(LIBS)
28+ #$(RM) http
29+ #$(LN) ipp14 http
30+
31+
32+#
33 # lpd
34 #
35
36--- /dev/null
37+++ b/backend/ipp14.c
38@@ -0,0 +1,1953 @@
39+/*
40+ * "$Id: ipp.c 8950 2010-01-14 22:40:19Z mike $"
41+ *
42+ * IPP backend for the Common UNIX Printing System (CUPS).
43+ *
44+ * Copyright 2007-2010 by Apple Inc.
45+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
46+ *
47+ * These coded instructions, statements, and computer programs are the
48+ * property of Apple Inc. and are protected by Federal copyright
49+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
50+ * "LICENSE" which should have been included with this file. If this
51+ * file is missing or damaged, see the license at "http://www.cups.org/".
52+ *
53+ * This file is subject to the Apple OS-Developed Software exception.
54+ *
55+ * Contents:
56+ *
57+ * main() - Send a file to the printer or server.
58+ * cancel_job() - Cancel a print job.
59+ * check_printer_state() - Check the printer state...
60+ * compress_files() - Compress print files...
61+ * password_cb() - Disable the password prompt for
62+ * cupsDoFileRequest().
63+ * report_attr() - Report an IPP attribute value.
64+ * report_printer_state() - Report the printer state.
65+ * run_pictwps_filter() - Convert PICT files to PostScript when printing
66+ * remotely.
67+ * sigterm_handler() - Handle 'terminate' signals that stop the backend.
68+ */
69+
70+/*
71+ * Include necessary headers.
72+ */
73+
74+#include <cups/http-private.h>
75+#include "backend-private.h"
76+#include <sys/types.h>
77+#include <sys/stat.h>
78+#include <sys/wait.h>
79+
80+/*
81+ * Globals...
82+ */
83+
84+static char *password = NULL; /* Password for device URI */
85+static int password_tries = 0; /* Password tries */
86+static const char *auth_info_required = "none";
87+ /* New auth-info-required value */
88+#ifdef __APPLE__
89+static char pstmpname[1024] = ""; /* Temporary PostScript file name */
90+#endif /* __APPLE__ */
91+static char tmpfilename[1024] = ""; /* Temporary spool file name */
92+static int job_cancelled = 0; /* Job cancelled? */
93+
94+
95+/*
96+ * Local functions...
97+ */
98+
99+static void cancel_job(http_t *http, const char *uri, int id,
100+ const char *resource, const char *user, int version);
101+static void check_printer_state(http_t *http, const char *uri,
102+ const char *resource, const char *user,
103+ int version, int job_id);
104+#ifdef HAVE_LIBZ
105+static void compress_files(int num_files, char **files);
106+#endif /* HAVE_LIBZ */
107+static const char *password_cb(const char *);
108+static void report_attr(ipp_attribute_t *attr);
109+static int report_printer_state(ipp_t *ipp, int job_id);
110+
111+#ifdef __APPLE__
112+static int run_pictwps_filter(char **argv, const char *filename);
113+#endif /* __APPLE__ */
114+static void sigterm_handler(int sig);
115+
116+
117+/*
118+ * 'main()' - Send a file to the printer or server.
119+ *
120+ * Usage:
121+ *
122+ * printer-uri job-id user title copies options [file]
123+ */
124+
125+int /* O - Exit status */
126+main(int argc, /* I - Number of command-line args */
127+ char *argv[]) /* I - Command-line arguments */
128+{
129+ int i; /* Looping var */
130+ int send_options; /* Send job options? */
131+ int num_options; /* Number of printer options */
132+ cups_option_t *options; /* Printer options */
133+ const char *device_uri; /* Device URI */
134+ char scheme[255], /* Scheme in URI */
135+ hostname[1024], /* Hostname */
136+ username[255], /* Username info */
137+ resource[1024], /* Resource info (printer name) */
138+ addrname[256], /* Address name */
139+ *optptr, /* Pointer to URI options */
140+ *name, /* Name of option */
141+ *value, /* Value of option */
142+ sep; /* Separator character */
143+ int snmp_fd, /* SNMP socket */
144+ start_count, /* Page count via SNMP at start */
145+ page_count, /* Page count via SNMP */
146+ have_supplies; /* Printer supports supply levels? */
147+ int num_files; /* Number of files to print */
148+ char **files, /* Files to print */
149+ *filename; /* Pointer to single filename */
150+ int port; /* Port number (not used) */
151+ char uri[HTTP_MAX_URI]; /* Updated URI without user/pass */
152+ ipp_status_t ipp_status; /* Status of IPP request */
153+ http_t *http; /* HTTP connection */
154+ ipp_t *request, /* IPP request */
155+ *response, /* IPP response */
156+ *supported; /* get-printer-attributes response */
157+ time_t start_time; /* Time of first connect */
158+ int recoverable; /* Recoverable error shown? */
159+ int contimeout; /* Connection timeout */
160+ int delay; /* Delay for retries... */
161+ int compression, /* Do compression of the job data? */
162+ waitjob, /* Wait for job complete? */
163+ waitprinter; /* Wait for printer ready? */
164+ ipp_attribute_t *job_id_attr; /* job-id attribute */
165+ int job_id; /* job-id value */
166+ ipp_attribute_t *job_sheets; /* job-media-sheets-completed */
167+ ipp_attribute_t *job_state; /* job-state */
168+ ipp_attribute_t *copies_sup; /* copies-supported */
169+ ipp_attribute_t *format_sup; /* document-format-supported */
170+ ipp_attribute_t *printer_state; /* printer-state attribute */
171+ ipp_attribute_t *printer_accepting; /* printer-is-accepting-jobs */
172+ int copies, /* Number of copies for job */
173+ copies_remaining; /* Number of copies remaining */
174+ const char *content_type, /* CONTENT_TYPE environment variable */
175+ *final_content_type; /* FINAL_CONTENT_TYPE environment var */
176+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
177+ struct sigaction action; /* Actions for POSIX signals */
178+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
179+ int version; /* IPP version */
180+ static const char * const pattrs[] =
181+ { /* Printer attributes we want */
182+ "com.apple.print.recoverable-message",
183+ "copies-supported",
184+ "document-format-supported",
185+ "marker-colors",
186+ "marker-high-levels",
187+ "marker-levels",
188+ "marker-low-levels",
189+ "marker-message",
190+ "marker-names",
191+ "marker-types",
192+ "printer-is-accepting-jobs",
193+ "printer-state",
194+ "printer-state-message",
195+ "printer-state-reasons",
196+ };
197+ static const char * const jattrs[] =
198+ { /* Job attributes we want */
199+ "job-media-sheets-completed",
200+ "job-state"
201+ };
202+
203+
204+ /*
205+ * Make sure status messages are not buffered...
206+ */
207+
208+ setbuf(stderr, NULL);
209+
210+ /*
211+ * Ignore SIGPIPE and catch SIGTERM signals...
212+ */
213+
214+#ifdef HAVE_SIGSET
215+ sigset(SIGPIPE, SIG_IGN);
216+ sigset(SIGTERM, sigterm_handler);
217+#elif defined(HAVE_SIGACTION)
218+ memset(&action, 0, sizeof(action));
219+ action.sa_handler = SIG_IGN;
220+ sigaction(SIGPIPE, &action, NULL);
221+
222+ sigemptyset(&action.sa_mask);
223+ sigaddset(&action.sa_mask, SIGTERM);
224+ action.sa_handler = sigterm_handler;
225+ sigaction(SIGTERM, &action, NULL);
226+#else
227+ signal(SIGPIPE, SIG_IGN);
228+ signal(SIGTERM, sigterm_handler);
229+#endif /* HAVE_SIGSET */
230+
231+ /*
232+ * Check command-line...
233+ */
234+
235+ if (argc == 1)
236+ {
237+ char *s;
238+
239+ if ((s = strrchr(argv[0], '/')) != NULL)
240+ s ++;
241+ else
242+ s = argv[0];
243+
244+ printf("network %s \"Unknown\" \"%s (%s)\"\n",
245+ s, _cupsLangString(cupsLangDefault(),
246+ _("Internet Printing Protocol")), s);
247+ return (CUPS_BACKEND_OK);
248+ }
249+ else if (argc < 6)
250+ {
251+ _cupsLangPrintf(stderr,
252+ _("Usage: %s job-id user title copies options [file]\n"),
253+ argv[0]);
254+ return (CUPS_BACKEND_STOP);
255+ }
256+
257+ /*
258+ * Get the (final) content type...
259+ */
260+
261+ if ((content_type = getenv("CONTENT_TYPE")) == NULL)
262+ content_type = "application/octet-stream";
263+
264+ if ((final_content_type = getenv("FINAL_CONTENT_TYPE")) == NULL)
265+ {
266+ final_content_type = content_type;
267+
268+ if (!strncmp(final_content_type, "printer/", 8))
269+ final_content_type = "application/vnd.cups-raw";
270+ }
271+
272+ /*
273+ * Extract the hostname and printer name from the URI...
274+ */
275+
276+ if ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
277+ return (CUPS_BACKEND_FAILED);
278+
279+ httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme),
280+ username, sizeof(username), hostname, sizeof(hostname), &port,
281+ resource, sizeof(resource));
282+
283+ if (!port)
284+ port = IPP_PORT; /* Default to port 631 */
285+
286+ if (!strcmp(scheme, "https"))
287+ cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
288+ else
289+ cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
290+
291+ /*
292+ * See if there are any options...
293+ */
294+
295+ compression = 0;
296+ version = 11;
297+ waitjob = 1;
298+ waitprinter = 1;
299+ contimeout = 7 * 24 * 60 * 60;
300+
301+ if ((optptr = strchr(resource, '?')) != NULL)
302+ {
303+ /*
304+ * Yup, terminate the device name string and move to the first
305+ * character of the optptr...
306+ */
307+
308+ *optptr++ = '\0';
309+
310+ /*
311+ * Then parse the optptr...
312+ */
313+
314+ while (*optptr)
315+ {
316+ /*
317+ * Get the name...
318+ */
319+
320+ name = optptr;
321+
322+ while (*optptr && *optptr != '=' && *optptr != '+' && *optptr != '&')
323+ optptr ++;
324+
325+ if ((sep = *optptr) != '\0')
326+ *optptr++ = '\0';
327+
328+ if (sep == '=')
329+ {
330+ /*
331+ * Get the value...
332+ */
333+
334+ value = optptr;
335+
336+ while (*optptr && *optptr != '+' && *optptr != '&')
337+ optptr ++;
338+
339+ if (*optptr)
340+ *optptr++ = '\0';
341+ }
342+ else
343+ value = (char *)"";
344+
345+ /*
346+ * Process the option...
347+ */
348+
349+ if (!strcasecmp(name, "waitjob"))
350+ {
351+ /*
352+ * Wait for job completion?
353+ */
354+
355+ waitjob = !strcasecmp(value, "on") ||
356+ !strcasecmp(value, "yes") ||
357+ !strcasecmp(value, "true");
358+ }
359+ else if (!strcasecmp(name, "waitprinter"))
360+ {
361+ /*
362+ * Wait for printer idle?
363+ */
364+
365+ waitprinter = !strcasecmp(value, "on") ||
366+ !strcasecmp(value, "yes") ||
367+ !strcasecmp(value, "true");
368+ }
369+ else if (!strcasecmp(name, "encryption"))
370+ {
371+ /*
372+ * Enable/disable encryption?
373+ */
374+
375+ if (!strcasecmp(value, "always"))
376+ cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
377+ else if (!strcasecmp(value, "required"))
378+ cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
379+ else if (!strcasecmp(value, "never"))
380+ cupsSetEncryption(HTTP_ENCRYPT_NEVER);
381+ else if (!strcasecmp(value, "ifrequested"))
382+ cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
383+ else
384+ {
385+ _cupsLangPrintf(stderr,
386+ _("ERROR: Unknown encryption option value \"%s\"!\n"),
387+ value);
388+ }
389+ }
390+ else if (!strcasecmp(name, "version"))
391+ {
392+ if (!strcmp(value, "1.0"))
393+ version = 10;
394+ else if (!strcmp(value, "1.1"))
395+ version = 11;
396+ else if (!strcmp(value, "2.0"))
397+ version = 20;
398+ else if (!strcmp(value, "2.1"))
399+ version = 21;
400+ else
401+ {
402+ _cupsLangPrintf(stderr,
403+ _("ERROR: Unknown version option value \"%s\"!\n"),
404+ value);
405+ }
406+ }
407+#ifdef HAVE_LIBZ
408+ else if (!strcasecmp(name, "compression"))
409+ {
410+ compression = !strcasecmp(value, "true") ||
411+ !strcasecmp(value, "yes") ||
412+ !strcasecmp(value, "on") ||
413+ !strcasecmp(value, "gzip");
414+ }
415+#endif /* HAVE_LIBZ */
416+ else if (!strcasecmp(name, "contimeout"))
417+ {
418+ /*
419+ * Set the connection timeout...
420+ */
421+
422+ if (atoi(value) > 0)
423+ contimeout = atoi(value);
424+ }
425+ else
426+ {
427+ /*
428+ * Unknown option...
429+ */
430+
431+ _cupsLangPrintf(stderr,
432+ _("ERROR: Unknown option \"%s\" with value \"%s\"!\n"),
433+ name, value);
434+ }
435+ }
436+ }
437+
438+ /*
439+ * If we have 7 arguments, print the file named on the command-line.
440+ * Otherwise, copy stdin to a temporary file and print the temporary
441+ * file.
442+ */
443+
444+ if (argc == 6)
445+ {
446+ /*
447+ * Copy stdin to a temporary file...
448+ */
449+
450+ int fd; /* File descriptor */
451+ http_addrlist_t *addrlist; /* Address list */
452+ off_t tbytes; /* Total bytes copied */
453+
454+
455+ fputs("STATE: +connecting-to-device\n", stderr);
456+ fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);
457+
458+ if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, "1")) == NULL)
459+ {
460+ _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"),
461+ hostname);
462+ return (CUPS_BACKEND_STOP);
463+ }
464+
465+ snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family);
466+
467+ if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0)
468+ {
469+ _cupsLangPrintError("ERROR", _("Unable to create temporary file"));
470+ return (CUPS_BACKEND_FAILED);
471+ }
472+
473+ _cupsLangPuts(stderr, _("INFO: Copying print data...\n"));
474+
475+ tbytes = backendRunLoop(-1, fd, snmp_fd, &(addrlist->addr), 0, 0,
476+ backendNetworkSideCB);
477+
478+ if (snmp_fd >= 0)
479+ _cupsSNMPClose(snmp_fd);
480+
481+ httpAddrFreeList(addrlist);
482+
483+ close(fd);
484+
485+ /*
486+ * Don't try printing files less than 2 bytes...
487+ */
488+
489+ if (tbytes <= 1)
490+ {
491+ _cupsLangPuts(stderr, _("ERROR: Empty print file!\n"));
492+ unlink(tmpfilename);
493+ return (CUPS_BACKEND_FAILED);
494+ }
495+
496+ /*
497+ * Point to the single file from stdin...
498+ */
499+
500+ filename = tmpfilename;
501+ num_files = 1;
502+ files = &filename;
503+ send_options = 0;
504+ }
505+ else
506+ {
507+ /*
508+ * Point to the files on the command-line...
509+ */
510+
511+ num_files = argc - 6;
512+ files = argv + 6;
513+ send_options = 1;
514+
515+#ifdef HAVE_LIBZ
516+ if (compression)
517+ compress_files(num_files, files);
518+#endif /* HAVE_LIBZ */
519+ }
520+
521+ fprintf(stderr, "DEBUG: %d files to send in job...\n", num_files);
522+
523+ /*
524+ * Set the authentication info, if any...
525+ */
526+
527+ cupsSetPasswordCB(password_cb);
528+
529+ if (username[0])
530+ {
531+ /*
532+ * Use authenticaion information in the device URI...
533+ */
534+
535+ if ((password = strchr(username, ':')) != NULL)
536+ *password++ = '\0';
537+
538+ cupsSetUser(username);
539+ }
540+ else if (!getuid())
541+ {
542+ /*
543+ * Try loading authentication information from the environment.
544+ */
545+
546+ const char *ptr = getenv("AUTH_USERNAME");
547+
548+ if (ptr)
549+ cupsSetUser(ptr);
550+
551+ password = getenv("AUTH_PASSWORD");
552+ }
553+
554+ /*
555+ * Try connecting to the remote server...
556+ */
557+
558+ delay = 5;
559+ recoverable = 0;
560+ start_time = time(NULL);
561+
562+ fputs("STATE: +connecting-to-device\n", stderr);
563+
564+ do
565+ {
566+ fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port);
567+ _cupsLangPuts(stderr, _("INFO: Connecting to printer...\n"));
568+
569+ if ((http = httpConnectEncrypt(hostname, port, cupsEncryption())) == NULL)
570+ {
571+ if (job_cancelled)
572+ break;
573+
574+ if (getenv("CLASS") != NULL)
575+ {
576+ /*
577+ * If the CLASS environment variable is set, the job was submitted
578+ * to a class and not to a specific queue. In this case, we want
579+ * to abort immediately so that the job can be requeued on the next
580+ * available printer in the class.
581+ */
582+
583+ _cupsLangPuts(stderr,
584+ _("INFO: Unable to contact printer, queuing on next "
585+ "printer in class...\n"));
586+
587+ if (tmpfilename[0])
588+ unlink(tmpfilename);
589+
590+ /*
591+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
592+ */
593+
594+ sleep(5);
595+
596+ return (CUPS_BACKEND_FAILED);
597+ }
598+
599+ if (errno == ECONNREFUSED || errno == EHOSTDOWN ||
600+ errno == EHOSTUNREACH)
601+ {
602+ if (contimeout && (time(NULL) - start_time) > contimeout)
603+ {
604+ _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n"));
605+ return (CUPS_BACKEND_FAILED);
606+ }
607+
608+ recoverable = 1;
609+
610+ _cupsLangPrintf(stderr,
611+ _("WARNING: recoverable: Network host \'%s\' is busy; "
612+ "will retry in %d seconds...\n"),
613+ hostname, delay);
614+
615+ sleep(delay);
616+
617+ if (delay < 30)
618+ delay += 5;
619+ }
620+ else if (h_errno)
621+ {
622+ _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"),
623+ hostname);
624+ return (CUPS_BACKEND_STOP);
625+ }
626+ else
627+ {
628+ recoverable = 1;
629+
630+ fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno));
631+ _cupsLangPuts(stderr,
632+ _("ERROR: recoverable: Unable to connect to printer; will "
633+ "retry in 30 seconds...\n"));
634+ sleep(30);
635+ }
636+
637+ if (job_cancelled)
638+ break;
639+ }
640+ }
641+ while (http == NULL);
642+
643+ if (job_cancelled || !http)
644+ {
645+ if (tmpfilename[0])
646+ unlink(tmpfilename);
647+
648+ return (CUPS_BACKEND_FAILED);
649+ }
650+
651+ fputs("STATE: -connecting-to-device\n", stderr);
652+ _cupsLangPuts(stderr, _("INFO: Connected to printer...\n"));
653+
654+#ifdef AF_INET6
655+ if (http->hostaddr->addr.sa_family == AF_INET6)
656+ fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6)...\n",
657+ httpAddrString(http->hostaddr, addrname, sizeof(addrname)),
658+ ntohs(http->hostaddr->ipv6.sin6_port));
659+ else
660+#endif /* AF_INET6 */
661+ if (http->hostaddr->addr.sa_family == AF_INET)
662+ fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4)...\n",
663+ httpAddrString(http->hostaddr, addrname, sizeof(addrname)),
664+ ntohs(http->hostaddr->ipv4.sin_port));
665+
666+ /*
667+ * See if the printer supports SNMP...
668+ */
669+
670+ if ((snmp_fd = _cupsSNMPOpen(http->hostaddr->addr.sa_family)) >= 0)
671+ have_supplies = !backendSNMPSupplies(snmp_fd, http->hostaddr, &start_count,
672+ NULL);
673+ else
674+ have_supplies = start_count = 0;
675+
676+ /*
677+ * Build a URI for the printer and fill the standard IPP attributes for
678+ * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it
679+ * might contain username:password information...
680+ */
681+
682+ httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, NULL, hostname,
683+ port, resource);
684+
685+ /*
686+ * First validate the destination and see if the device supports multiple
687+ * copies. We have to do this because some IPP servers (e.g. HP JetDirect)
688+ * don't support the copies attribute...
689+ */
690+
691+ copies_sup = NULL;
692+ format_sup = NULL;
693+ supported = NULL;
694+
695+ do
696+ {
697+ /*
698+ * Check for side-channel requests...
699+ */
700+
701+ backendCheckSideChannel(snmp_fd, http->hostaddr);
702+
703+ /*
704+ * Build the IPP request...
705+ */
706+
707+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
708+ request->request.op.version[0] = version / 10;
709+ request->request.op.version[1] = version % 10;
710+
711+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
712+ NULL, uri);
713+
714+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
715+ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
716+ NULL, pattrs);
717+
718+ /*
719+ * Do the request...
720+ */
721+
722+ fputs("DEBUG: Getting supported attributes...\n", stderr);
723+
724+ if (http->version < HTTP_1_1)
725+ httpReconnect(http);
726+
727+ if ((supported = cupsDoRequest(http, request, resource)) == NULL)
728+ ipp_status = cupsLastError();
729+ else
730+ ipp_status = supported->request.status.status_code;
731+
732+ if (ipp_status > IPP_OK_CONFLICT)
733+ {
734+ if (ipp_status == IPP_PRINTER_BUSY ||
735+ ipp_status == IPP_SERVICE_UNAVAILABLE)
736+ {
737+ if (contimeout && (time(NULL) - start_time) > contimeout)
738+ {
739+ _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n"));
740+ return (CUPS_BACKEND_FAILED);
741+ }
742+
743+ recoverable = 1;
744+
745+ _cupsLangPrintf(stderr,
746+ _("WARNING: recoverable: Network host \'%s\' is busy; "
747+ "will retry in %d seconds...\n"),
748+ hostname, delay);
749+
750+ report_printer_state(supported, 0);
751+
752+ sleep(delay);
753+
754+ if (delay < 30)
755+ delay += 5;
756+ }
757+ else if ((ipp_status == IPP_BAD_REQUEST ||
758+ ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10)
759+ {
760+ /*
761+ * Switch to IPP/1.0...
762+ */
763+
764+ _cupsLangPrintf(stderr,
765+ _("INFO: Printer does not support IPP/%d.%d, trying "
766+ "IPP/1.0...\n"), version / 10, version % 10);
767+ version = 10;
768+ httpReconnect(http);
769+ }
770+ else if (ipp_status == IPP_NOT_FOUND)
771+ {
772+ _cupsLangPuts(stderr, _("ERROR: Destination printer does not exist!\n"));
773+
774+ if (supported)
775+ ippDelete(supported);
776+
777+ return (CUPS_BACKEND_STOP);
778+ }
779+ else if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
780+ {
781+ if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
782+ "Negotiate", 9))
783+ auth_info_required = "negotiate";
784+
785+ fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
786+ return (CUPS_BACKEND_AUTH_REQUIRED);
787+ }
788+ else
789+ {
790+ _cupsLangPrintf(stderr,
791+ _("ERROR: Unable to get printer status (%s)!\n"),
792+ cupsLastErrorString());
793+ sleep(10);
794+ }
795+
796+ if (supported)
797+ ippDelete(supported);
798+
799+ continue;
800+ }
801+ else if ((copies_sup = ippFindAttribute(supported, "copies-supported",
802+ IPP_TAG_RANGE)) != NULL)
803+ {
804+ /*
805+ * Has the "copies-supported" attribute - does it have an upper
806+ * bound > 1?
807+ */
808+
809+ if (copies_sup->values[0].range.upper <= 1)
810+ copies_sup = NULL; /* No */
811+ }
812+
813+ format_sup = ippFindAttribute(supported, "document-format-supported",
814+ IPP_TAG_MIMETYPE);
815+
816+ if (format_sup)
817+ {
818+ fprintf(stderr, "DEBUG: document-format-supported (%d values)\n",
819+ format_sup->num_values);
820+ for (i = 0; i < format_sup->num_values; i ++)
821+ fprintf(stderr, "DEBUG: [%d] = \"%s\"\n", i,
822+ format_sup->values[i].string.text);
823+ }
824+
825+ report_printer_state(supported, 0);
826+ }
827+ while (ipp_status > IPP_OK_CONFLICT);
828+
829+ /*
830+ * See if the printer is accepting jobs and is not stopped; if either
831+ * condition is true and we are printing to a class, requeue the job...
832+ */
833+
834+ if (getenv("CLASS") != NULL)
835+ {
836+ printer_state = ippFindAttribute(supported, "printer-state",
837+ IPP_TAG_ENUM);
838+ printer_accepting = ippFindAttribute(supported, "printer-is-accepting-jobs",
839+ IPP_TAG_BOOLEAN);
840+
841+ if (printer_state == NULL ||
842+ (printer_state->values[0].integer > IPP_PRINTER_PROCESSING &&
843+ waitprinter) ||
844+ printer_accepting == NULL ||
845+ !printer_accepting->values[0].boolean)
846+ {
847+ /*
848+ * If the CLASS environment variable is set, the job was submitted
849+ * to a class and not to a specific queue. In this case, we want
850+ * to abort immediately so that the job can be requeued on the next
851+ * available printer in the class.
852+ */
853+
854+ _cupsLangPuts(stderr,
855+ _("INFO: Unable to contact printer, queuing on next "
856+ "printer in class...\n"));
857+
858+ ippDelete(supported);
859+ httpClose(http);
860+
861+ if (tmpfilename[0])
862+ unlink(tmpfilename);
863+
864+ /*
865+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
866+ */
867+
868+ sleep(5);
869+
870+ return (CUPS_BACKEND_FAILED);
871+ }
872+ }
873+
874+ if (recoverable)
875+ {
876+ /*
877+ * If we've shown a recoverable error make sure the printer proxies
878+ * have a chance to see the recovered message. Not pretty but
879+ * necessary for now...
880+ */
881+
882+ fputs("INFO: recovered: \n", stderr);
883+ sleep(5);
884+ }
885+
886+ /*
887+ * See if the printer supports multiple copies...
888+ */
889+
890+ copies = atoi(argv[4]);
891+
892+ if (copies_sup || argc < 7)
893+ {
894+ copies_remaining = 1;
895+
896+ if (argc < 7)
897+ copies = 1;
898+ }
899+ else
900+ copies_remaining = copies;
901+
902+ /*
903+ * Then issue the print-job request...
904+ */
905+
906+ job_id = 0;
907+
908+ while (copies_remaining > 0)
909+ {
910+ /*
911+ * Check for side-channel requests...
912+ */
913+
914+ backendCheckSideChannel(snmp_fd, http->hostaddr);
915+
916+ /*
917+ * Build the IPP request...
918+ */
919+
920+ if (job_cancelled)
921+ break;
922+
923+ if (num_files > 1)
924+ request = ippNewRequest(IPP_CREATE_JOB);
925+ else
926+ request = ippNewRequest(IPP_PRINT_JOB);
927+
928+ request->request.op.version[0] = version / 10;
929+ request->request.op.version[1] = version % 10;
930+
931+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
932+ NULL, uri);
933+
934+ fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri);
935+
936+ if (argv[2][0])
937+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
938+ "requesting-user-name", NULL, argv[2]);
939+
940+ fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]);
941+
942+ /*
943+ * Only add a "job-name" attribute if the remote server supports
944+ * copy generation - some IPP implementations like HP's don't seem
945+ * to like UTF-8 job names (STR #1837)...
946+ */
947+
948+ if (argv[3][0] && copies_sup)
949+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
950+ argv[3]);
951+
952+ fprintf(stderr, "DEBUG: job-name = \"%s\"\n", argv[3]);
953+
954+#ifdef HAVE_LIBZ
955+ if (compression)
956+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
957+ "compression", NULL, "gzip");
958+#endif /* HAVE_LIBZ */
959+
960+ /*
961+ * Handle options on the command-line...
962+ */
963+
964+ options = NULL;
965+ num_options = cupsParseOptions(argv[5], 0, &options);
966+
967+#ifdef __APPLE__
968+ if (!strcasecmp(final_content_type, "application/pictwps") &&
969+ num_files == 1)
970+ {
971+ if (format_sup != NULL)
972+ {
973+ for (i = 0; i < format_sup->num_values; i ++)
974+ if (!strcasecmp(final_content_type, format_sup->values[i].string.text))
975+ break;
976+ }
977+
978+ if (format_sup == NULL || i >= format_sup->num_values)
979+ {
980+ /*
981+ * Remote doesn't support "application/pictwps" (i.e. it's not MacOS X)
982+ * so convert the document to PostScript...
983+ */
984+
985+ if (run_pictwps_filter(argv, files[0]))
986+ {
987+ if (pstmpname[0])
988+ unlink(pstmpname);
989+
990+ if (tmpfilename[0])
991+ unlink(tmpfilename);
992+
993+ return (CUPS_BACKEND_FAILED);
994+ }
995+
996+ files[0] = pstmpname;
997+
998+ /*
999+ * Change the MIME type to application/postscript and change the
1000+ * number of copies to 1...
1001+ */
1002+
1003+ final_content_type = "application/postscript";
1004+ copies = 1;
1005+ copies_remaining = 1;
1006+ send_options = 0;
1007+ }
1008+ }
1009+#endif /* __APPLE__ */
1010+
1011+ if (format_sup != NULL)
1012+ {
1013+ for (i = 0; i < format_sup->num_values; i ++)
1014+ if (!strcasecmp(final_content_type, format_sup->values[i].string.text))
1015+ break;
1016+
1017+ if (i < format_sup->num_values)
1018+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1019+ "document-format", NULL, final_content_type);
1020+ }
1021+
1022+ if (copies_sup && version > 10 && send_options)
1023+ {
1024+ /*
1025+ * Only send options if the destination printer supports the copies
1026+ * attribute and IPP/1.1. This is a hack for the HP and Lexmark
1027+ * implementations of IPP, which do not accept extension attributes
1028+ * and incorrectly report a client-error-bad-request error instead of
1029+ * the successful-ok-unsupported-attributes status. In short, at least
1030+ * some HP and Lexmark implementations of IPP are non-compliant.
1031+ */
1032+
1033+ cupsEncodeOptions(request, num_options, options);
1034+
1035+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies",
1036+ copies);
1037+ }
1038+
1039+ cupsFreeOptions(num_options, options);
1040+
1041+ /*
1042+ * If copies aren't supported, then we are likely dealing with an HP
1043+ * JetDirect. The HP IPP implementation seems to close the connection
1044+ * after every request - that is, it does *not* implement HTTP Keep-
1045+ * Alive, which is REQUIRED by HTTP/1.1...
1046+ */
1047+
1048+ if (!copies_sup)
1049+ httpReconnect(http);
1050+
1051+ /*
1052+ * Do the request...
1053+ */
1054+
1055+ if (http->version < HTTP_1_1)
1056+ httpReconnect(http);
1057+
1058+ if (num_files > 1)
1059+ response = cupsDoRequest(http, request, resource);
1060+ else
1061+ response = cupsDoFileRequest(http, request, resource, files[0]);
1062+
1063+ ipp_status = cupsLastError();
1064+
1065+ if (ipp_status > IPP_OK_CONFLICT)
1066+ {
1067+ job_id = 0;
1068+
1069+ if (job_cancelled)
1070+ break;
1071+
1072+ if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1073+ ipp_status == IPP_PRINTER_BUSY)
1074+ {
1075+ _cupsLangPuts(stderr,
1076+ _("INFO: Printer busy; will retry in 10 seconds...\n"));
1077+ sleep(10);
1078+ }
1079+ else if ((ipp_status == IPP_BAD_REQUEST ||
1080+ ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10)
1081+ {
1082+ /*
1083+ * Switch to IPP/1.0...
1084+ */
1085+
1086+ _cupsLangPrintf(stderr,
1087+ _("INFO: Printer does not support IPP/%d.%d, trying "
1088+ "IPP/1.0...\n"), version / 10, version % 10);
1089+ version = 10;
1090+ httpReconnect(http);
1091+ }
1092+ else
1093+ {
1094+ /*
1095+ * Update auth-info-required as needed...
1096+ */
1097+
1098+ _cupsLangPrintf(stderr, _("ERROR: Print file was not accepted (%s)!\n"),
1099+ cupsLastErrorString());
1100+
1101+ if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
1102+ {
1103+ fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n",
1104+ httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE));
1105+
1106+ /*
1107+ * Normal authentication goes through the password callback, which sets
1108+ * auth_info_required to "username,password". Kerberos goes directly
1109+ * through GSSAPI, so look for Negotiate in the WWW-Authenticate header
1110+ * here and set auth_info_required as needed...
1111+ */
1112+
1113+ if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
1114+ "Negotiate", 9))
1115+ auth_info_required = "negotiate";
1116+ }
1117+ }
1118+ }
1119+ else if ((job_id_attr = ippFindAttribute(response, "job-id",
1120+ IPP_TAG_INTEGER)) == NULL)
1121+ {
1122+ _cupsLangPuts(stderr,
1123+ _("NOTICE: Print file accepted - job ID unknown.\n"));
1124+ job_id = 0;
1125+ }
1126+ else
1127+ {
1128+ job_id = job_id_attr->values[0].integer;
1129+ _cupsLangPrintf(stderr, _("NOTICE: Print file accepted - job ID %d.\n"),
1130+ job_id);
1131+ }
1132+
1133+ ippDelete(response);
1134+
1135+ if (job_cancelled)
1136+ break;
1137+
1138+ if (job_id && num_files > 1)
1139+ {
1140+ for (i = 0; i < num_files; i ++)
1141+ {
1142+ /*
1143+ * Check for side-channel requests...
1144+ */
1145+
1146+ backendCheckSideChannel(snmp_fd, http->hostaddr);
1147+
1148+ /*
1149+ * Send the next file in the job...
1150+ */
1151+
1152+ request = ippNewRequest(IPP_SEND_DOCUMENT);
1153+ request->request.op.version[0] = version / 10;
1154+ request->request.op.version[1] = version % 10;
1155+
1156+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1157+ NULL, uri);
1158+
1159+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
1160+ job_id);
1161+
1162+ if (argv[2][0])
1163+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1164+ "requesting-user-name", NULL, argv[2]);
1165+
1166+ if ((i + 1) == num_files)
1167+ ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
1168+
1169+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1170+ "document-format", NULL, content_type);
1171+
1172+ if (http->version < HTTP_1_1)
1173+ httpReconnect(http);
1174+
1175+ ippDelete(cupsDoFileRequest(http, request, resource, files[i]));
1176+
1177+ if (cupsLastError() > IPP_OK_CONFLICT)
1178+ {
1179+ ipp_status = cupsLastError();
1180+
1181+ _cupsLangPrintf(stderr,
1182+ _("ERROR: Unable to add file %d to job: %s\n"),
1183+ job_id, cupsLastErrorString());
1184+ break;
1185+ }
1186+ }
1187+ }
1188+
1189+ if (ipp_status <= IPP_OK_CONFLICT && argc > 6)
1190+ {
1191+ fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1);
1192+ copies_remaining --;
1193+ }
1194+ else if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1195+ ipp_status == IPP_PRINTER_BUSY)
1196+ continue;
1197+ else
1198+ copies_remaining --;
1199+
1200+ /*
1201+ * Wait for the job to complete...
1202+ */
1203+
1204+ if (!job_id || !waitjob)
1205+ continue;
1206+
1207+ _cupsLangPuts(stderr, _("INFO: Waiting for job to complete...\n"));
1208+
1209+ for (delay = 1; !job_cancelled;)
1210+ {
1211+ /*
1212+ * Check for side-channel requests...
1213+ */
1214+
1215+ backendCheckSideChannel(snmp_fd, http->hostaddr);
1216+
1217+ /*
1218+ * Build an IPP_GET_JOB_ATTRIBUTES request...
1219+ */
1220+
1221+ request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
1222+ request->request.op.version[0] = version / 10;
1223+ request->request.op.version[1] = version % 10;
1224+
1225+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1226+ NULL, uri);
1227+
1228+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
1229+ job_id);
1230+
1231+ if (argv[2][0])
1232+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1233+ "requesting-user-name", NULL, argv[2]);
1234+
1235+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1236+ "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]),
1237+ NULL, jattrs);
1238+
1239+ /*
1240+ * Do the request...
1241+ */
1242+
1243+ if (!copies_sup || http->version < HTTP_1_1)
1244+ httpReconnect(http);
1245+
1246+ response = cupsDoRequest(http, request, resource);
1247+ ipp_status = cupsLastError();
1248+
1249+ if (ipp_status == IPP_NOT_FOUND)
1250+ {
1251+ /*
1252+ * Job has gone away and/or the server has no job history...
1253+ */
1254+
1255+ ippDelete(response);
1256+
1257+ ipp_status = IPP_OK;
1258+ break;
1259+ }
1260+
1261+ if (ipp_status > IPP_OK_CONFLICT)
1262+ {
1263+ if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
1264+ ipp_status != IPP_PRINTER_BUSY)
1265+ {
1266+ ippDelete(response);
1267+
1268+ _cupsLangPrintf(stderr,
1269+ _("ERROR: Unable to get job %d attributes (%s)!\n"),
1270+ job_id, cupsLastErrorString());
1271+ break;
1272+ }
1273+ }
1274+
1275+ if (response)
1276+ {
1277+ if ((job_state = ippFindAttribute(response, "job-state",
1278+ IPP_TAG_ENUM)) != NULL)
1279+ {
1280+ /*
1281+ * Stop polling if the job is finished or pending-held...
1282+ */
1283+
1284+ if (job_state->values[0].integer > IPP_JOB_STOPPED)
1285+ {
1286+ if ((job_sheets = ippFindAttribute(response,
1287+ "job-media-sheets-completed",
1288+ IPP_TAG_INTEGER)) != NULL)
1289+ fprintf(stderr, "PAGE: total %d\n",
1290+ job_sheets->values[0].integer);
1291+
1292+ ippDelete(response);
1293+ break;
1294+ }
1295+ }
1296+ else
1297+ {
1298+ /*
1299+ * If the printer does not return a job-state attribute, it does not
1300+ * conform to the IPP specification - break out immediately and fail
1301+ * the job...
1302+ */
1303+
1304+ fputs("DEBUG: No job-state available from printer - stopping queue.\n",
1305+ stderr);
1306+ ipp_status = IPP_INTERNAL_ERROR;
1307+ break;
1308+ }
1309+ }
1310+
1311+ ippDelete(response);
1312+
1313+ /*
1314+ * Check the printer state and report it if necessary...
1315+ */
1316+
1317+ check_printer_state(http, uri, resource, argv[2], version, job_id);
1318+
1319+ /*
1320+ * Wait 1-10 seconds before polling again...
1321+ */
1322+
1323+ sleep(delay);
1324+
1325+ delay ++;
1326+ if (delay > 10)
1327+ delay = 1;
1328+ }
1329+ }
1330+
1331+ /*
1332+ * Cancel the job as needed...
1333+ */
1334+
1335+ if (job_cancelled && job_id)
1336+ cancel_job(http, uri, job_id, resource, argv[2], version);
1337+
1338+ /*
1339+ * Check the printer state and report it if necessary...
1340+ */
1341+
1342+ check_printer_state(http, uri, resource, argv[2], version, job_id);
1343+
1344+ /*
1345+ * Collect the final page count as needed...
1346+ */
1347+
1348+ if (have_supplies &&
1349+ !backendSNMPSupplies(snmp_fd, http->hostaddr, &page_count, NULL) &&
1350+ page_count > start_count)
1351+ fprintf(stderr, "PAGE: total %d\n", page_count - start_count);
1352+
1353+#ifdef HAVE_GSSAPI
1354+ /*
1355+ * See if we used Kerberos at all...
1356+ */
1357+
1358+ if (http->gssctx)
1359+ auth_info_required = "negotiate";
1360+#endif /* HAVE_GSSAPI */
1361+
1362+ /*
1363+ * Free memory...
1364+ */
1365+
1366+ httpClose(http);
1367+
1368+ ippDelete(supported);
1369+
1370+ /*
1371+ * Remove the temporary file(s) if necessary...
1372+ */
1373+
1374+ if (tmpfilename[0])
1375+ unlink(tmpfilename);
1376+
1377+#ifdef HAVE_LIBZ
1378+ if (compression)
1379+ {
1380+ for (i = 0; i < num_files; i ++)
1381+ unlink(files[i]);
1382+ }
1383+#endif /* HAVE_LIBZ */
1384+
1385+#ifdef __APPLE__
1386+ if (pstmpname[0])
1387+ unlink(pstmpname);
1388+#endif /* __APPLE__ */
1389+
1390+ /*
1391+ * Return the queue status...
1392+ */
1393+
1394+ fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
1395+
1396+ if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
1397+ return (CUPS_BACKEND_AUTH_REQUIRED);
1398+ else if (ipp_status == IPP_INTERNAL_ERROR)
1399+ return (CUPS_BACKEND_STOP);
1400+ else if (ipp_status > IPP_OK_CONFLICT)
1401+ return (CUPS_BACKEND_FAILED);
1402+ else
1403+ {
1404+ _cupsLangPuts(stderr, _("INFO: Ready to print.\n"));
1405+ return (CUPS_BACKEND_OK);
1406+ }
1407+}
1408+
1409+
1410+/*
1411+ * 'cancel_job()' - Cancel a print job.
1412+ */
1413+
1414+static void
1415+cancel_job(http_t *http, /* I - HTTP connection */
1416+ const char *uri, /* I - printer-uri */
1417+ int id, /* I - job-id */
1418+ const char *resource, /* I - Resource path */
1419+ const char *user, /* I - requesting-user-name */
1420+ int version) /* I - IPP version */
1421+{
1422+ ipp_t *request; /* Cancel-Job request */
1423+
1424+
1425+ _cupsLangPuts(stderr, _("INFO: Canceling print job...\n"));
1426+
1427+ request = ippNewRequest(IPP_CANCEL_JOB);
1428+ request->request.op.version[0] = version / 10;
1429+ request->request.op.version[1] = version % 10;
1430+
1431+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1432+ NULL, uri);
1433+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", id);
1434+
1435+ if (user && user[0])
1436+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1437+ "requesting-user-name", NULL, user);
1438+
1439+ /*
1440+ * Do the request...
1441+ */
1442+
1443+ if (http->version < HTTP_1_1)
1444+ httpReconnect(http);
1445+
1446+ ippDelete(cupsDoRequest(http, request, resource));
1447+
1448+ if (cupsLastError() > IPP_OK_CONFLICT)
1449+ _cupsLangPrintf(stderr, _("ERROR: Unable to cancel job %d: %s\n"), id,
1450+ cupsLastErrorString());
1451+}
1452+
1453+
1454+/*
1455+ * 'check_printer_state()' - Check the printer state...
1456+ */
1457+
1458+static void
1459+check_printer_state(
1460+ http_t *http, /* I - HTTP connection */
1461+ const char *uri, /* I - Printer URI */
1462+ const char *resource, /* I - Resource path */
1463+ const char *user, /* I - Username, if any */
1464+ int version, /* I - IPP version */
1465+ int job_id) /* I - Current job ID */
1466+{
1467+ ipp_t *request, /* IPP request */
1468+ *response; /* IPP response */
1469+ static const char * const attrs[] = /* Attributes we want */
1470+ {
1471+ "com.apple.print.recoverable-message",
1472+ "marker-colors",
1473+ "marker-levels",
1474+ "marker-message",
1475+ "marker-names",
1476+ "marker-types",
1477+ "printer-state-message",
1478+ "printer-state-reasons"
1479+ };
1480+
1481+
1482+ /*
1483+ * Check on the printer state...
1484+ */
1485+
1486+ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
1487+ request->request.op.version[0] = version / 10;
1488+ request->request.op.version[1] = version % 10;
1489+
1490+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1491+ NULL, uri);
1492+
1493+ if (user && user[0])
1494+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1495+ "requesting-user-name", NULL, user);
1496+
1497+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1498+ "requested-attributes",
1499+ (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
1500+
1501+ /*
1502+ * Do the request...
1503+ */
1504+
1505+ if (http->version < HTTP_1_1)
1506+ httpReconnect(http);
1507+
1508+ if ((response = cupsDoRequest(http, request, resource)) != NULL)
1509+ {
1510+ report_printer_state(response, job_id);
1511+ ippDelete(response);
1512+ }
1513+}
1514+
1515+
1516+#ifdef HAVE_LIBZ
1517+/*
1518+ * 'compress_files()' - Compress print files...
1519+ */
1520+
1521+static void
1522+compress_files(int num_files, /* I - Number of files */
1523+ char **files) /* I - Files */
1524+{
1525+ int i, /* Looping var */
1526+ fd; /* Temporary file descriptor */
1527+ ssize_t bytes; /* Bytes read/written */
1528+ size_t total; /* Total bytes read */
1529+ cups_file_t *in, /* Input file */
1530+ *out; /* Output file */
1531+ struct stat outinfo; /* Output file information */
1532+ char filename[1024], /* Temporary filename */
1533+ buffer[32768]; /* Copy buffer */
1534+
1535+
1536+ fprintf(stderr, "DEBUG: Compressing %d job files...\n", num_files);
1537+ for (i = 0; i < num_files; i ++)
1538+ {
1539+ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
1540+ {
1541+ _cupsLangPrintf(stderr,
1542+ _("ERROR: Unable to create temporary compressed print "
1543+ "file: %s\n"), strerror(errno));
1544+ exit(CUPS_BACKEND_FAILED);
1545+ }
1546+
1547+ if ((out = cupsFileOpenFd(fd, "w9")) == NULL)
1548+ {
1549+ _cupsLangPrintf(stderr,
1550+ _("ERROR: Unable to open temporary compressed print "
1551+ "file: %s\n"), strerror(errno));
1552+ exit(CUPS_BACKEND_FAILED);
1553+ }
1554+
1555+ if ((in = cupsFileOpen(files[i], "r")) == NULL)
1556+ {
1557+ _cupsLangPrintf(stderr,
1558+ _("ERROR: Unable to open print file \"%s\": %s\n"),
1559+ files[i], strerror(errno));
1560+ cupsFileClose(out);
1561+ exit(CUPS_BACKEND_FAILED);
1562+ }
1563+
1564+ total = 0;
1565+ while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0)
1566+ if (cupsFileWrite(out, buffer, bytes) < bytes)
1567+ {
1568+ _cupsLangPrintf(stderr,
1569+ _("ERROR: Unable to write %d bytes to \"%s\": %s\n"),
1570+ (int)bytes, filename, strerror(errno));
1571+ cupsFileClose(in);
1572+ cupsFileClose(out);
1573+ exit(CUPS_BACKEND_FAILED);
1574+ }
1575+ else
1576+ total += bytes;
1577+
1578+ cupsFileClose(out);
1579+ cupsFileClose(in);
1580+
1581+ files[i] = strdup(filename);
1582+
1583+ if (!stat(filename, &outinfo))
1584+ fprintf(stderr,
1585+ "DEBUG: File %d compressed to %.1f%% of original size, "
1586+ CUPS_LLFMT " bytes...\n",
1587+ i + 1, 100.0 * outinfo.st_size / total,
1588+ CUPS_LLCAST outinfo.st_size);
1589+ }
1590+}
1591+#endif /* HAVE_LIBZ */
1592+
1593+
1594+/*
1595+ * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
1596+ */
1597+
1598+static const char * /* O - Password */
1599+password_cb(const char *prompt) /* I - Prompt (not used) */
1600+{
1601+ (void)prompt;
1602+
1603+ /*
1604+ * Remember that we need to authenticate...
1605+ */
1606+
1607+ auth_info_required = "username,password";
1608+
1609+ if (password && *password && password_tries < 3)
1610+ {
1611+ password_tries ++;
1612+
1613+ return (password);
1614+ }
1615+ else
1616+ {
1617+ /*
1618+ * Give up after 3 tries or if we don't have a password to begin with...
1619+ */
1620+
1621+ return (NULL);
1622+ }
1623+}
1624+
1625+
1626+/*
1627+ * 'report_attr()' - Report an IPP attribute value.
1628+ */
1629+
1630+static void
1631+report_attr(ipp_attribute_t *attr) /* I - Attribute */
1632+{
1633+ int i; /* Looping var */
1634+ char value[1024], /* Value string */
1635+ *valptr, /* Pointer into value string */
1636+ *attrptr; /* Pointer into attribute value */
1637+
1638+
1639+ /*
1640+ * Convert the attribute values into quoted strings...
1641+ */
1642+
1643+ for (i = 0, valptr = value;
1644+ i < attr->num_values && valptr < (value + sizeof(value) - 10);
1645+ i ++)
1646+ {
1647+ if (i > 0)
1648+ *valptr++ = ',';
1649+
1650+ switch (attr->value_tag)
1651+ {
1652+ case IPP_TAG_INTEGER :
1653+ case IPP_TAG_ENUM :
1654+ snprintf(valptr, sizeof(value) - (valptr - value), "%d",
1655+ attr->values[i].integer);
1656+ valptr += strlen(valptr);
1657+ break;
1658+
1659+ case IPP_TAG_TEXT :
1660+ case IPP_TAG_NAME :
1661+ case IPP_TAG_KEYWORD :
1662+ *valptr++ = '\"';
1663+ for (attrptr = attr->values[i].string.text;
1664+ *attrptr && valptr < (value + sizeof(value) - 10);
1665+ attrptr ++)
1666+ {
1667+ if (*attrptr == '\\' || *attrptr == '\"')
1668+ *valptr++ = '\\';
1669+
1670+ *valptr++ = *attrptr;
1671+ }
1672+ *valptr++ = '\"';
1673+ break;
1674+
1675+ default :
1676+ /*
1677+ * Unsupported value type...
1678+ */
1679+
1680+ return;
1681+ }
1682+ }
1683+
1684+ *valptr = '\0';
1685+
1686+ /*
1687+ * Tell the scheduler about the new values...
1688+ */
1689+
1690+ fprintf(stderr, "ATTR: %s=%s\n", attr->name, value);
1691+}
1692+
1693+
1694+/*
1695+ * 'report_printer_state()' - Report the printer state.
1696+ */
1697+
1698+static int /* O - Number of reasons shown */
1699+report_printer_state(ipp_t *ipp, /* I - IPP response */
1700+ int job_id) /* I - Current job ID */
1701+{
1702+ int i; /* Looping var */
1703+ int count; /* Count of reasons shown... */
1704+ ipp_attribute_t *caprm, /* com.apple.print.recoverable-message */
1705+ *psm, /* printer-state-message */
1706+ *reasons, /* printer-state-reasons */
1707+ *marker; /* marker-* attributes */
1708+ const char *reason; /* Current reason */
1709+ const char *prefix; /* Prefix for STATE: line */
1710+ char state[1024]; /* State string */
1711+ int saw_caprw; /* Saw com.apple.print.recoverable-warning state */
1712+
1713+
1714+ if ((psm = ippFindAttribute(ipp, "printer-state-message",
1715+ IPP_TAG_TEXT)) != NULL)
1716+ fprintf(stderr, "INFO: %s\n", psm->values[0].string.text);
1717+
1718+ if ((reasons = ippFindAttribute(ipp, "printer-state-reasons",
1719+ IPP_TAG_KEYWORD)) == NULL)
1720+ return (0);
1721+
1722+ saw_caprw = 0;
1723+ state[0] = '\0';
1724+ prefix = "STATE: ";
1725+
1726+ for (i = 0, count = 0; i < reasons->num_values; i ++)
1727+ {
1728+ reason = reasons->values[i].string.text;
1729+
1730+ if (!strcmp(reason, "com.apple.print.recoverable-warning"))
1731+ saw_caprw = 1;
1732+ else if (strcmp(reason, "paused"))
1733+ {
1734+ strlcat(state, prefix, sizeof(state));
1735+ strlcat(state, reason, sizeof(state));
1736+
1737+ prefix = ",";
1738+ }
1739+ }
1740+
1741+ if (state[0])
1742+ fprintf(stderr, "%s\n", state);
1743+
1744+ /*
1745+ * Relay com.apple.print.recoverable-message...
1746+ */
1747+
1748+ if ((caprm = ippFindAttribute(ipp, "com.apple.print.recoverable-message",
1749+ IPP_TAG_TEXT)) != NULL)
1750+ fprintf(stderr, "WARNING: %s: %s\n",
1751+ saw_caprw ? "recoverable" : "recovered",
1752+ caprm->values[0].string.text);
1753+
1754+ /*
1755+ * Relay the current marker-* attribute values...
1756+ */
1757+
1758+ if ((marker = ippFindAttribute(ipp, "marker-colors", IPP_TAG_NAME)) != NULL)
1759+ report_attr(marker);
1760+ if ((marker = ippFindAttribute(ipp, "marker-high-levels",
1761+ IPP_TAG_INTEGER)) != NULL)
1762+ report_attr(marker);
1763+ if ((marker = ippFindAttribute(ipp, "marker-levels",
1764+ IPP_TAG_INTEGER)) != NULL)
1765+ report_attr(marker);
1766+ if ((marker = ippFindAttribute(ipp, "marker-low-levels",
1767+ IPP_TAG_INTEGER)) != NULL)
1768+ report_attr(marker);
1769+ if ((marker = ippFindAttribute(ipp, "marker-message", IPP_TAG_TEXT)) != NULL)
1770+ report_attr(marker);
1771+ if ((marker = ippFindAttribute(ipp, "marker-names", IPP_TAG_NAME)) != NULL)
1772+ report_attr(marker);
1773+ if ((marker = ippFindAttribute(ipp, "marker-types", IPP_TAG_KEYWORD)) != NULL)
1774+ report_attr(marker);
1775+
1776+ return (count);
1777+}
1778+
1779+
1780+#ifdef __APPLE__
1781+/*
1782+ * 'run_pictwps_filter()' - Convert PICT files to PostScript when printing
1783+ * remotely.
1784+ *
1785+ * This step is required because the PICT format is not documented and
1786+ * subject to change, so developing a filter for other OS's is infeasible.
1787+ * Also, fonts required by the PICT file need to be embedded on the
1788+ * client side (which has the fonts), so we run the filter to get a
1789+ * PostScript file for printing...
1790+ */
1791+
1792+static int /* O - Exit status of filter */
1793+run_pictwps_filter(char **argv, /* I - Command-line arguments */
1794+ const char *filename)/* I - Filename */
1795+{
1796+ struct stat fileinfo; /* Print file information */
1797+ const char *ppdfile; /* PPD file for destination printer */
1798+ int pid; /* Child process ID */
1799+ int fd; /* Temporary file descriptor */
1800+ int status; /* Exit status of filter */
1801+ const char *printer; /* PRINTER env var */
1802+ static char ppdenv[1024]; /* PPD environment variable */
1803+
1804+
1805+ /*
1806+ * First get the PPD file for the printer...
1807+ */
1808+
1809+ printer = getenv("PRINTER");
1810+ if (!printer)
1811+ {
1812+ _cupsLangPuts(stderr,
1813+ _("ERROR: PRINTER environment variable not defined!\n"));
1814+ return (-1);
1815+ }
1816+
1817+ if ((ppdfile = cupsGetPPD(printer)) == NULL)
1818+ {
1819+ _cupsLangPrintf(stderr,
1820+ _("ERROR: Unable to get PPD file for printer \"%s\" - "
1821+ "%s.\n"), printer, cupsLastErrorString());
1822+ }
1823+ else
1824+ {
1825+ snprintf(ppdenv, sizeof(ppdenv), "PPD=%s", ppdfile);
1826+ putenv(ppdenv);
1827+ }
1828+
1829+ /*
1830+ * Then create a temporary file for printing...
1831+ */
1832+
1833+ if ((fd = cupsTempFd(pstmpname, sizeof(pstmpname))) < 0)
1834+ {
1835+ _cupsLangPrintError("ERROR", _("Unable to create temporary file"));
1836+ if (ppdfile)
1837+ unlink(ppdfile);
1838+ return (-1);
1839+ }
1840+
1841+ /*
1842+ * Get the owner of the spool file - it is owned by the user we want to run
1843+ * as...
1844+ */
1845+
1846+ if (argv[6])
1847+ stat(argv[6], &fileinfo);
1848+ else
1849+ {
1850+ /*
1851+ * Use the OSX defaults, as an up-stream filter created the PICT
1852+ * file...
1853+ */
1854+
1855+ fileinfo.st_uid = 1;
1856+ fileinfo.st_gid = 80;
1857+ }
1858+
1859+ if (ppdfile)
1860+ chown(ppdfile, fileinfo.st_uid, fileinfo.st_gid);
1861+
1862+ fchown(fd, fileinfo.st_uid, fileinfo.st_gid);
1863+
1864+ /*
1865+ * Finally, run the filter to convert the file...
1866+ */
1867+
1868+ if ((pid = fork()) == 0)
1869+ {
1870+ /*
1871+ * Child process for pictwpstops... Redirect output of pictwpstops to a
1872+ * file...
1873+ */
1874+
1875+ dup2(fd, 1);
1876+ close(fd);
1877+
1878+ if (!getuid())
1879+ {
1880+ /*
1881+ * Change to an unpriviledged user...
1882+ */
1883+
1884+ if (setgid(fileinfo.st_gid))
1885+ return (errno);
1886+
1887+ if (setuid(fileinfo.st_uid))
1888+ return (errno);
1889+ }
1890+
1891+ execlp("pictwpstops", printer, argv[1], argv[2], argv[3], argv[4], argv[5],
1892+ filename, NULL);
1893+ _cupsLangPrintf(stderr, _("ERROR: Unable to exec pictwpstops: %s\n"),
1894+ strerror(errno));
1895+ return (errno);
1896+ }
1897+
1898+ close(fd);
1899+
1900+ if (pid < 0)
1901+ {
1902+ /*
1903+ * Error!
1904+ */
1905+
1906+ _cupsLangPrintf(stderr, _("ERROR: Unable to fork pictwpstops: %s\n"),
1907+ strerror(errno));
1908+ if (ppdfile)
1909+ unlink(ppdfile);
1910+ return (-1);
1911+ }
1912+
1913+ /*
1914+ * Now wait for the filter to complete...
1915+ */
1916+
1917+ if (wait(&status) < 0)
1918+ {
1919+ _cupsLangPrintf(stderr, _("ERROR: Unable to wait for pictwpstops: %s\n"),
1920+ strerror(errno));
1921+ close(fd);
1922+ if (ppdfile)
1923+ unlink(ppdfile);
1924+ return (-1);
1925+ }
1926+
1927+ if (ppdfile)
1928+ unlink(ppdfile);
1929+
1930+ close(fd);
1931+
1932+ if (status)
1933+ {
1934+ if (status >= 256)
1935+ _cupsLangPrintf(stderr, _("ERROR: pictwpstops exited with status %d!\n"),
1936+ status / 256);
1937+ else
1938+ _cupsLangPrintf(stderr, _("ERROR: pictwpstops exited on signal %d!\n"),
1939+ status);
1940+
1941+ return (status);
1942+ }
1943+
1944+ /*
1945+ * Return with no errors..
1946+ */
1947+
1948+ return (0);
1949+}
1950+#endif /* __APPLE__ */
1951+
1952+
1953+/*
1954+ * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1955+ */
1956+
1957+static void
1958+sigterm_handler(int sig) /* I - Signal */
1959+{
1960+ (void)sig; /* remove compiler warnings... */
1961+
1962+ if (!job_cancelled)
1963+ {
1964+ /*
1965+ * Flag that the job should be cancelled...
1966+ */
1967+
1968+ job_cancelled = 1;
1969+ return;
1970+ }
1971+
1972+ /*
1973+ * The scheduler already tried to cancel us once, now just terminate
1974+ * after removing our temp files!
1975+ */
1976+
1977+ if (tmpfilename[0])
1978+ unlink(tmpfilename);
1979+
1980+#ifdef __APPLE__
1981+ if (pstmpname[0])
1982+ unlink(pstmpname);
1983+#endif /* __APPLE__ */
1984+
1985+ exit(1);
1986+}
1987+
1988+
1989+/*
1990+ * End of "$Id: ipp.c 8950 2010-01-14 22:40:19Z mike $".
1991+ */
This page took 0.372298 seconds and 4 git commands to generate.