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