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