2 * "$Id: ipp.c,v 1.76 2003/04/10 12:57:40 mike Exp $"
4 * IPP backend for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2003 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
28 * main() - Send a file to the printer or server.
29 * password_cb() - Disable the password prompt for
30 * cupsDoFileRequest().
31 * report_printer_state() - Report the printer state.
32 * run_pictwps_filter() - Convert PICT files to PostScript when printing
34 * sigterm_handler() - Handle 'terminate' signals that stop the backend.
38 * Include necessary headers.
44 #include <sys/types.h>
46 #include <cups/cups.h>
47 #include <cups/language.h>
48 #include <cups/string.h>
57 static char tmpfilename
[1024] = ""; /* Temporary spool file name */
61 * Some OS's don't have hstrerror(), most notably Solaris...
64 #ifndef HAVE_HSTRERROR
65 # define hstrerror cups_hstrerror
67 const char * /* O - Error string */
68 cups_hstrerror(int error
) /* I - Error number */
70 static const char * const errors
[] =
75 "Unrecoverable lookup error.",
76 "No data associated with name."
80 if (error
< 0 || error
> 4)
81 return ("Unknown hostname lookup error.");
83 return (errors
[error
]);
87 * AIX doesn't provide a prototype but does provide the function...
89 extern const char *hstrerror(int);
90 #endif /* !HAVE_HSTRERROR */
97 const char *password_cb(const char *);
98 int report_printer_state(ipp_t
*ipp
);
101 int run_pictwps_filter(char **argv
, char *filename
, int length
);
102 #endif /* __APPLE__ */
103 static void sigterm_handler(int sig
);
110 char *password
= NULL
;
114 * 'main()' - Send a file to the printer or server.
118 * printer-uri job-id user title copies options [file]
121 int /* O - Exit status */
122 main(int argc
, /* I - Number of command-line arguments (6 or 7) */
123 char *argv
[]) /* I - Command-line arguments */
125 int i
; /* Looping var */
126 int num_options
; /* Number of printer options */
127 cups_option_t
*options
; /* Printer options */
128 char method
[255], /* Method in URI */
129 hostname
[1024], /* Hostname */
130 username
[255], /* Username info */
131 resource
[1024]; /* Resource info (printer name) */
132 const char *filename
; /* File to print */
133 int port
; /* Port number (not used) */
134 char uri
[HTTP_MAX_URI
];/* Updated URI without user/pass */
135 ipp_status_t ipp_status
; /* Status of IPP request */
136 http_t
*http
; /* HTTP connection */
137 ipp_t
*request
, /* IPP request */
138 *response
, /* IPP response */
139 *supported
; /* get-printer-attributes response */
140 ipp_attribute_t
*job_id_attr
; /* job-id attribute */
141 int job_id
; /* job-id value */
142 ipp_attribute_t
*job_sheets
; /* job-media-sheets-completed attribute */
143 ipp_attribute_t
*job_state
; /* job-state attribute */
144 ipp_attribute_t
*copies_sup
; /* copies-supported attribute */
145 ipp_attribute_t
*charset_sup
; /* charset-supported attribute */
146 ipp_attribute_t
*format_sup
; /* document-format-supported attribute */
147 ipp_attribute_t
*printer_state
;
148 /* printer-state attribute */
149 ipp_attribute_t
*printer_accepting
;
150 /* printer-is-accepting-jobs attribute */
151 const char *charset
; /* Character set to use */
152 cups_lang_t
*language
; /* Default language */
153 int copies
; /* Number of copies remaining */
154 const char *content_type
; /* CONTENT_TYPE environment variable */
155 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
156 struct sigaction action
; /* Actions for POSIX signals */
157 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
158 int version
; /* IPP version */
159 int reasons
; /* Number of printer-state-reasons shown */
160 static const char * const pattrs
[] =
161 { /* Printer attributes we want */
164 "document-format-supported",
165 "printer-is-accepting-jobs",
167 "printer-state-reasons",
169 static const char * const jattrs
[] =
170 { /* Job attributes we want */
171 "job-media-sheets-completed",
177 * Make sure status messages are not buffered...
180 setbuf(stderr
, NULL
);
183 * Ignore SIGPIPE and catch SIGTERM signals...
187 sigset(SIGPIPE
, SIG_IGN
);
188 sigset(SIGTERM
, sigterm_handler
);
189 #elif defined(HAVE_SIGACTION)
190 memset(&action
, 0, sizeof(action
));
191 action
.sa_handler
= SIG_IGN
;
192 sigaction(SIGPIPE
, &action
, NULL
);
194 sigemptyset(&action
.sa_mask
);
195 sigaddset(&action
.sa_mask
, SIGTERM
);
196 action
.sa_handler
= sigterm_handler
;
197 sigaction(SIGTERM
, &action
, NULL
);
199 signal(SIGPIPE
, SIG_IGN
);
200 signal(SIGTERM
, sigterm_handler
);
201 #endif /* HAVE_SIGSET */
204 * Check command-line...
211 if ((s
= strrchr(argv
[0], '/')) != NULL
)
216 printf("network %s \"Unknown\" \"Internet Printing Protocol (%s)\"\n", s
, s
);
219 else if (argc
< 6 || argc
> 7)
221 fprintf(stderr
, "Usage: %s job-id user title copies options [file]\n",
227 * Get the content type...
231 content_type
= getenv("CONTENT_TYPE");
233 content_type
= "application/vnd.cups-raw";
235 if (content_type
== NULL
)
236 content_type
= "application/octet-stream";
239 * If we have 7 arguments, print the file named on the command-line.
240 * Otherwise, copy stdin to a temporary file and print the temporary
247 * Copy stdin to a temporary file...
250 int fd
; /* Temporary file */
251 char buffer
[8192]; /* Buffer for copying */
252 int bytes
; /* Number of bytes read */
255 if ((fd
= cupsTempFd(tmpfilename
, sizeof(tmpfilename
))) < 0)
257 perror("ERROR: unable to create temporary file");
261 while ((bytes
= fread(buffer
, 1, sizeof(buffer
), stdin
)) > 0)
262 if (write(fd
, buffer
, bytes
) < bytes
)
264 perror("ERROR: unable to write to temporary file");
271 filename
= tmpfilename
;
277 * Extract the hostname and printer name from the URI...
280 httpSeparate(argv
[0], method
, username
, hostname
, &port
, resource
);
283 * Set the authentication info, if any...
286 cupsSetPasswordCB(password_cb
);
290 if ((password
= strchr(username
, ':')) != NULL
)
293 cupsSetUser(username
);
297 * Try connecting to the remote server...
302 fprintf(stderr
, "INFO: Connecting to %s on port %d...\n", hostname
, port
);
304 if ((http
= httpConnectEncrypt(hostname
, port
, cupsEncryption())) == NULL
)
306 if (getenv("CLASS") != NULL
)
309 * If the CLASS environment variable is set, the job was submitted
310 * to a class and not to a specific queue. In this case, we want
311 * to abort immediately so that the job can be requeued on the next
312 * available printer in the class.
315 fprintf(stderr
, "INFO: Unable to queue job on %s, queuing on next printer in class...\n",
318 if (argc
== 6 || strcmp(filename
, argv
[6]))
322 * Sleep 5 seconds to keep the job from requeuing too rapidly...
330 if (errno
== ECONNREFUSED
|| errno
== EHOSTDOWN
||
331 errno
== EHOSTUNREACH
)
333 fprintf(stderr
, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...",
339 fprintf(stderr
, "INFO: Unable to lookup host \'%s\' - %s\n",
340 hostname
, hstrerror(h_errno
));
345 perror("ERROR: Unable to connect to IPP host");
350 while (http
== NULL
);
352 fprintf(stderr
, "INFO: Connected to %s...\n", hostname
);
355 * Build a URI for the printer and fill the standard IPP attributes for
356 * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it
357 * might contain username:password information...
360 snprintf(uri
, sizeof(uri
), "%s://%s:%d%s", method
, hostname
, port
, resource
);
363 * First validate the destination and see if the device supports multiple
364 * copies. We have to do this because some IPP servers (e.g. HP JetDirect)
365 * don't support the copies attribute...
368 language
= cupsLangDefault();
378 * Build the IPP request...
382 request
->request
.op
.version
[1] = version
;
383 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
384 request
->request
.op
.request_id
= 1;
386 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
387 "attributes-charset", NULL
, "utf-8");
389 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
390 "attributes-natural-language", NULL
,
391 language
!= NULL
? language
->language
: "en");
393 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
396 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
397 "requested-attributes", sizeof(pattrs
) / sizeof(pattrs
[0]),
404 fputs("DEBUG: Getting supported attributes...\n", stderr
);
406 if ((supported
= cupsDoRequest(http
, request
, resource
)) == NULL
)
407 ipp_status
= cupsLastError();
409 ipp_status
= supported
->request
.status
.status_code
;
411 if (ipp_status
> IPP_OK_CONFLICT
)
413 if (ipp_status
== IPP_PRINTER_BUSY
||
414 ipp_status
== IPP_SERVICE_UNAVAILABLE
)
416 fputs("INFO: Printer busy; will retry in 10 seconds...\n", stderr
);
417 report_printer_state(supported
);
420 else if ((ipp_status
== IPP_BAD_REQUEST
||
421 ipp_status
== IPP_VERSION_NOT_SUPPORTED
) && version
== 1)
424 * Switch to IPP/1.0...
427 fputs("INFO: Printer does not support IPP/1.1, trying IPP/1.0...\n", stderr
);
431 else if (ipp_status
== IPP_NOT_FOUND
)
433 fputs("ERROR: Destination printer does not exist!\n", stderr
);
436 ippDelete(supported
);
442 fprintf(stderr
, "ERROR: Unable to get printer status (%s)!\n",
443 ippErrorString(ipp_status
));
448 ippDelete(supported
);
452 else if ((copies_sup
= ippFindAttribute(supported
, "copies-supported",
453 IPP_TAG_RANGE
)) != NULL
)
456 * Has the "copies-supported" attribute - does it have an upper
460 if (copies_sup
->values
[0].range
.upper
<= 1)
461 copies_sup
= NULL
; /* No */
464 charset_sup
= ippFindAttribute(supported
, "charset-supported",
466 format_sup
= ippFindAttribute(supported
, "document-format-supported",
471 fprintf(stderr
, "DEBUG: document-format-supported (%d values)\n",
472 format_sup
->num_values
);
473 for (i
= 0; i
< format_sup
->num_values
; i
++)
474 fprintf(stderr
, "DEBUG: [%d] = \"%s\"\n", i
,
475 format_sup
->values
[i
].string
.text
);
478 report_printer_state(supported
);
480 while (ipp_status
> IPP_OK_CONFLICT
);
483 * See if the printer is accepting jobs and is not stopped; if either
484 * condition is true and we are printing to a class, requeue the job...
487 if (getenv("CLASS") != NULL
)
489 printer_state
= ippFindAttribute(supported
, "printer-state",
491 printer_accepting
= ippFindAttribute(supported
, "printer-is-accepting-jobs",
494 if (printer_state
== NULL
||
495 printer_state
->values
[0].integer
> IPP_PRINTER_PROCESSING
||
496 printer_accepting
== NULL
||
497 !printer_accepting
->values
[0].boolean
)
500 * If the CLASS environment variable is set, the job was submitted
501 * to a class and not to a specific queue. In this case, we want
502 * to abort immediately so that the job can be requeued on the next
503 * available printer in the class.
506 fprintf(stderr
, "INFO: Unable to queue job on %s, queuing on next printer in class...\n",
509 ippDelete(supported
);
512 if (argc
== 6 || strcmp(filename
, argv
[6]))
516 * Sleep 5 seconds to keep the job from requeuing too rapidly...
526 * See if the printer supports multiple copies...
529 if (copies_sup
|| argc
< 7)
532 copies
= atoi(argv
[4]);
535 * Figure out the character set to use...
538 charset
= language
? cupsLangEncoding(language
) : "us-ascii";
543 * See if IPP server supports the requested character set...
546 for (i
= 0; i
< charset_sup
->num_values
; i
++)
547 if (strcasecmp(charset
, charset_sup
->values
[i
].string
.text
) == 0)
551 * If not, choose us-ascii or utf-8...
554 if (i
>= charset_sup
->num_values
)
557 * See if us-ascii is supported...
560 for (i
= 0; i
< charset_sup
->num_values
; i
++)
561 if (strcasecmp("us-ascii", charset_sup
->values
[i
].string
.text
) == 0)
564 if (i
< charset_sup
->num_values
)
565 charset
= "us-ascii";
572 * Then issue the print-job request...
580 * Build the IPP request...
584 request
->request
.op
.version
[1] = version
;
585 request
->request
.op
.operation_id
= IPP_PRINT_JOB
;
586 request
->request
.op
.request_id
= 1;
588 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
589 "attributes-charset", NULL
, charset
);
591 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
592 "attributes-natural-language", NULL
,
593 language
!= NULL
? language
->language
: "en");
595 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
598 fprintf(stderr
, "DEBUG: printer-uri = \"%s\"\n", uri
);
601 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
604 fprintf(stderr
, "DEBUG: requesting-user-name = \"%s\"\n", argv
[2]);
607 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
,
610 fprintf(stderr
, "DEBUG: job-name = \"%s\"\n", argv
[3]);
613 * Handle options on the command-line...
617 num_options
= cupsParseOptions(argv
[5], 0, &options
);
620 if (content_type
!= NULL
&& strcasecmp(content_type
, "application/pictwps") == 0)
622 if (format_sup
!= NULL
)
624 for (i
= 0; i
< format_sup
->num_values
; i
++)
625 if (strcasecmp(content_type
, format_sup
->values
[i
].string
.text
) == 0)
629 if (format_sup
== NULL
|| i
>= format_sup
->num_values
)
632 * Remote doesn't support "application/pictwps" (i.e. it's not MacOS X)
633 * so convert the document to PostScript...
636 if (run_pictwps_filter(argv
, filename
, sizeof(filename
)))
640 * Change the MIME type to application/postscript...
643 content_type
= "application/postscript";
646 #endif /* __APPLE__ */
648 if (content_type
!= NULL
&& format_sup
!= NULL
)
650 for (i
= 0; i
< format_sup
->num_values
; i
++)
651 if (strcasecmp(content_type
, format_sup
->values
[i
].string
.text
) == 0)
654 if (i
< format_sup
->num_values
)
655 num_options
= cupsAddOption("document-format", content_type
,
656 num_options
, &options
);
662 * Only send options if the destination printer supports the copies
663 * attribute. This is a hack for the HP JetDirect implementation of
664 * IPP, which does not accept extension attributes and incorrectly
665 * reports a client-error-bad-request error instead of the
666 * successful-ok-unsupported-attributes status. In short, at least
667 * some HP implementations of IPP are non-compliant.
670 cupsEncodeOptions(request
, num_options
, options
);
671 ippAddInteger(request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "copies",
675 cupsFreeOptions(num_options
, options
);
678 * If copies aren't supported, then we are likely dealing with an HP
679 * JetDirect. The HP IPP implementation seems to close the connection
680 * after every request (that is, it does *not* implement HTTP Keep-
681 * Alive, which is REQUIRED by HTTP/1.1...
691 if ((response
= cupsDoFileRequest(http
, request
, resource
, filename
)) == NULL
)
692 ipp_status
= cupsLastError();
694 ipp_status
= response
->request
.status
.status_code
;
696 if (ipp_status
> IPP_OK_CONFLICT
)
700 if (ipp_status
== IPP_SERVICE_UNAVAILABLE
||
701 ipp_status
== IPP_PRINTER_BUSY
)
703 fputs("INFO: Printer is busy; retrying print job...\n", stderr
);
707 fprintf(stderr
, "ERROR: Print file was not accepted (%s)!\n",
708 ippErrorString(ipp_status
));
710 else if ((job_id_attr
= ippFindAttribute(response
, "job-id",
711 IPP_TAG_INTEGER
)) == NULL
)
713 fputs("INFO: Print file accepted - job ID unknown.\n", stderr
);
718 job_id
= job_id_attr
->values
[0].integer
;
719 fprintf(stderr
, "INFO: Print file accepted - job ID %d.\n", job_id
);
725 if (ipp_status
<= IPP_OK_CONFLICT
&& argc
> 6)
727 fprintf(stderr
, "PAGE: 1 %d\n", copies_sup
? atoi(argv
[4]) : 1);
730 else if (ipp_status
!= IPP_SERVICE_UNAVAILABLE
&&
731 ipp_status
!= IPP_PRINTER_BUSY
)
735 * Wait for the job to complete...
741 fputs("INFO: Waiting for job to complete...\n", stderr
);
746 * Build an IPP_GET_JOB_ATTRIBUTES request...
750 request
->request
.op
.version
[1] = version
;
751 request
->request
.op
.operation_id
= IPP_GET_JOB_ATTRIBUTES
;
752 request
->request
.op
.request_id
= 1;
754 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
755 "attributes-charset", NULL
, charset
);
757 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
758 "attributes-natural-language", NULL
,
759 language
!= NULL
? language
->language
: "en");
761 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
764 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id",
768 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
771 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
772 "requested-attributes", sizeof(jattrs
) / sizeof(jattrs
[0]),
782 if ((response
= cupsDoRequest(http
, request
, resource
)) == NULL
)
783 ipp_status
= cupsLastError();
785 ipp_status
= response
->request
.status
.status_code
;
787 if (ipp_status
== IPP_NOT_FOUND
)
790 * Job has gone away and/or the server has no job history...
799 if (ipp_status
> IPP_OK_CONFLICT
)
801 if (ipp_status
!= IPP_SERVICE_UNAVAILABLE
&&
802 ipp_status
!= IPP_PRINTER_BUSY
)
807 fprintf(stderr
, "ERROR: Unable to get job %d attributes (%s)!\n",
808 job_id
, ippErrorString(ipp_status
));
813 if (response
!= NULL
)
815 if ((job_sheets
= ippFindAttribute(response
, "job-media-sheets-completed",
816 IPP_TAG_INTEGER
)) != NULL
)
817 fprintf(stderr
, "PAGE: total %d\n", job_sheets
->values
[0].integer
);
819 if ((job_state
= ippFindAttribute(response
, "job-state",
820 IPP_TAG_ENUM
)) != NULL
)
823 * Stop polling if the job is finished or pending-held...
826 if (job_state
->values
[0].integer
> IPP_JOB_PROCESSING
||
827 job_state
->values
[0].integer
== IPP_JOB_HELD
)
839 * Now check on the printer state...
843 request
->request
.op
.version
[1] = version
;
844 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
845 request
->request
.op
.request_id
= 1;
847 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
848 "attributes-charset", NULL
, charset
);
850 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
851 "attributes-natural-language", NULL
,
852 language
!= NULL
? language
->language
: "en");
854 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
858 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
861 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
862 "requested-attributes", NULL
, "printer-state-reasons");
871 if ((response
= cupsDoRequest(http
, request
, resource
)) != NULL
)
873 reasons
= report_printer_state(response
);
878 * Wait 10 seconds before polling again...
892 ippDelete(supported
);
895 * Remove the temporary file if necessary...
902 * Return the queue status...
905 if (ipp_status
<= IPP_OK_CONFLICT
&& reasons
== 0)
906 fputs("INFO: Ready to print.\n", stderr
);
908 return (ipp_status
> IPP_OK_CONFLICT
);
913 * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
916 const char * /* O - Password */
917 password_cb(const char *prompt
) /* I - Prompt (not used) */
926 * 'report_printer_state()' - Report the printer state.
929 int /* O - Number of reasons shown */
930 report_printer_state(ipp_t
*ipp
) /* I - IPP response */
932 int i
; /* Looping var */
933 int count
; /* Count of reasons shown... */
934 ipp_attribute_t
*reasons
; /* printer-state-reasons */
935 const char *reason
; /* Current reason */
936 const char *message
; /* Message to show */
937 char unknown
[1024]; /* Unknown message string */
938 const char *prefix
; /* Prefix for STATE: line */
939 char state
[1024]; /* State string */
942 if ((reasons
= ippFindAttribute(ipp
, "printer-state-reasons",
943 IPP_TAG_KEYWORD
)) == NULL
)
949 for (i
= 0, count
= 0; i
< reasons
->num_values
; i
++)
951 reason
= reasons
->values
[i
].string
.text
;
953 strlcat(state
, prefix
, sizeof(state
));
954 strlcat(state
, reason
, sizeof(state
));
959 if (strncmp(reason
, "media-needed", 12) == 0)
960 message
= "Media tray needs to be filled.";
961 else if (strncmp(reason
, "media-jam", 9) == 0)
962 message
= "Media jam!";
963 else if (strncmp(reason
, "moving-to-paused", 16) == 0 ||
964 strncmp(reason
, "paused", 6) == 0 ||
965 strncmp(reason
, "shutdown", 8) == 0)
966 message
= "Printer off-line.";
967 else if (strncmp(reason
, "toner-low", 9) == 0)
968 message
= "Toner low.";
969 else if (strncmp(reason
, "toner-empty", 11) == 0)
970 message
= "Out of toner!";
971 else if (strncmp(reason
, "cover-open", 10) == 0)
972 message
= "Cover open.";
973 else if (strncmp(reason
, "interlock-open", 14) == 0)
974 message
= "Interlock open.";
975 else if (strncmp(reason
, "door-open", 9) == 0)
976 message
= "Door open.";
977 else if (strncmp(reason
, "input-tray-missing", 18) == 0)
978 message
= "Media tray missing!";
979 else if (strncmp(reason
, "media-low", 9) == 0)
980 message
= "Media tray almost empty.";
981 else if (strncmp(reason
, "media-empty", 11) == 0)
982 message
= "Media tray empty!";
983 else if (strncmp(reason
, "output-tray-missing", 19) == 0)
984 message
= "Output tray missing!";
985 else if (strncmp(reason
, "output-area-almost-full", 23) == 0)
986 message
= "Output bin almost full.";
987 else if (strncmp(reason
, "output-area-full", 16) == 0)
988 message
= "Output bin full!";
989 else if (strncmp(reason
, "marker-supply-low", 17) == 0)
990 message
= "Ink/toner almost empty.";
991 else if (strncmp(reason
, "marker-supply-empty", 19) == 0)
992 message
= "Ink/toner empty!";
993 else if (strncmp(reason
, "marker-waste-almost-full", 24) == 0)
994 message
= "Ink/toner waste bin almost full.";
995 else if (strncmp(reason
, "marker-waste-full", 17) == 0)
996 message
= "Ink/toner waste bin full!";
997 else if (strncmp(reason
, "fuser-over-temp", 15) == 0)
998 message
= "Fuser temperature high!";
999 else if (strncmp(reason
, "fuser-under-temp", 16) == 0)
1000 message
= "Fuser temperature low!";
1001 else if (strncmp(reason
, "opc-near-eol", 12) == 0)
1002 message
= "OPC almost at end-of-life.";
1003 else if (strncmp(reason
, "opc-life-over", 13) == 0)
1004 message
= "OPC at end-of-life!";
1005 else if (strncmp(reason
, "developer-low", 13) == 0)
1006 message
= "Developer almost empty.";
1007 else if (strncmp(reason
, "developer-empty", 15) == 0)
1008 message
= "Developer empty!";
1009 else if (strstr(reason
, "error") != NULL
)
1013 snprintf(unknown
, sizeof(unknown
), "Unknown printer error (%s)!",
1020 if (strstr(reasons
->values
[i
].string
.text
, "error"))
1021 fprintf(stderr
, "ERROR: %s\n", message
);
1022 else if (strstr(reasons
->values
[i
].string
.text
, "warning"))
1023 fprintf(stderr
, "WARNING: %s\n", message
);
1025 fprintf(stderr
, "INFO: %s\n", message
);
1029 fprintf(stderr
, "%s\n", state
);
1037 * 'run_pictwps_filter()' - Convert PICT files to PostScript when printing
1040 * This step is required because the PICT format is not documented and
1041 * subject to change, so developing a filter for other OS's is infeasible.
1042 * Also, fonts required by the PICT file need to be embedded on the
1043 * client side (which has the fonts), so we run the filter to get a
1044 * PostScript file for printing...
1047 int /* O - Exit status of filter */
1048 run_pictwps_filter(char **argv
, /* I - Command-line arguments */
1049 char *filename
, /* I - Filename buffer */
1050 int length
) /* I - Size of filename buffer */
1052 struct stat fileinfo
; /* Print file information */
1053 const char *ppdfile
; /* PPD file for destination printer */
1054 int pid
; /* Child process ID */
1055 int fd
; /* Temporary file descriptor */
1056 int status
; /* Exit status of filter */
1057 const char *printer
; /* PRINTER env var */
1058 static char ppdenv
[1024]; /* PPD environment variable */
1062 * First get the PPD file for the printer...
1065 printer
= getenv("PRINTER");
1068 fputs("ERROR: PRINTER environment variable not defined!\n", stderr
);
1072 if ((ppdfile
= cupsGetPPD(printer
)) == NULL
)
1074 fprintf(stderr
, "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n",
1075 printer
, ippErrorString(cupsLastError()));
1080 snprintf(ppdenv
, sizeof(ppdenv
), "PPD=%s", ppdfile
);
1085 * Then create a temporary file for printing...
1088 if ((fd
= cupsTempFd(filename
, length
)) < 0)
1090 fprintf(stderr
, "ERROR: Unable to create temporary file - %s.\n",
1098 * Get the owner of the spool file - it is owned by the user we want to run
1102 stat(argv
[6], &fileinfo
);
1105 chown(ppdfile
, fileinfo
.st_uid
, fileinfo
.st_gid
);
1107 fchown(fd
, fileinfo
.st_uid
, fileinfo
.st_gid
);
1110 * Finally, run the filter to convert the file...
1113 if ((pid
= fork()) == 0)
1116 * Child process for pictwpstops... Redirect output of pictwpstops to a
1127 * Change to an unpriviledged user...
1130 setgid(fileinfo
.st_gid
);
1131 setuid(fileinfo
.st_uid
);
1134 execlp("pictwpstops", printer
, argv
[1], argv
[2], argv
[3], argv
[4], argv
[5],
1136 perror("ERROR: Unable to exec pictwpstops");
1148 perror("ERROR: Unable to fork pictwpstops");
1156 * Now wait for the filter to complete...
1159 if (wait(&status
) < 0)
1161 perror("ERROR: Unable to wait for pictwpstops");
1177 fprintf(stderr
, "ERROR: pictwpstops exited with status %d!\n",
1180 fprintf(stderr
, "ERROR: pictwpstops exited on signal %d!\n",
1188 * Return with no errors..
1193 #endif /* __APPLE__ */
1197 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1201 sigterm_handler(int sig
) /* I - Signal */
1203 (void)sig
; /* remove compiler warnings... */
1206 * Remove the temporary file if necessary...
1210 unlink(tmpfilename
);
1217 * End of "$Id: ipp.c,v 1.76 2003/04/10 12:57:40 mike Exp $".