]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/lpd.c
Load cups into easysw/current.
[thirdparty/cups.git] / backend / lpd.c
1 /*
2 * "$Id: lpd.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * "LICENSE" which should have been included with this file. If this
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
19 * main() - Send a file to the printer or server.
20 * lpd_command() - Send an LPR command sequence and wait for a reply.
21 * lpd_queue() - Queue a file using the Line Printer Daemon protocol.
22 * lpd_timeout() - Handle timeout alarms...
23 * lpd_write() - Write a buffer of data to an LPD server.
24 * rresvport_af() - A simple implementation of rresvport_af().
25 * sigterm_handler() - Handle 'terminate' signals that stop the backend.
26 */
27
28 /*
29 * Include necessary headers.
30 */
31
32 #include <cups/backend.h>
33 #include <cups/http-private.h>
34 #include <cups/cups.h>
35 #include <cups/i18n.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <ctype.h>
40 #include <cups/string.h>
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <signal.h>
45
46 #ifdef WIN32
47 # include <winsock.h>
48 #else
49 # include <sys/socket.h>
50 # include <netinet/in.h>
51 # include <arpa/inet.h>
52 # include <netdb.h>
53 #endif /* WIN32 */
54 #ifdef __APPLE__
55 # include <CoreFoundation/CFNumber.h>
56 # include <CoreFoundation/CFPreferences.h>
57 #endif /* __APPLE__ */
58
59
60 /*
61 * Globals...
62 */
63
64 static char tmpfilename[1024] = ""; /* Temporary spool file name */
65 static int abort_job = 0; /* Non-zero if we get SIGTERM */
66
67
68 /*
69 * Print mode...
70 */
71
72 #define MODE_STANDARD 0 /* Queue a copy */
73 #define MODE_STREAM 1 /* Stream a copy */
74
75
76 /*
77 * The order for control and data files in LPD requests...
78 */
79
80 #define ORDER_CONTROL_DATA 0 /* Control file first, then data */
81 #define ORDER_DATA_CONTROL 1 /* Data file first, then control */
82
83
84 /*
85 * What to reserve...
86 */
87
88 #define RESERVE_NONE 0 /* Don't reserve a priviledged port */
89 #define RESERVE_RFC1179 1 /* Reserve port 721-731 */
90 #define RESERVE_ANY 2 /* Reserve port 1-1023 */
91
92
93 /*
94 * Local functions...
95 */
96
97 static int lpd_command(int lpd_fd, int timeout, char *format, ...);
98 static int lpd_queue(const char *hostname, int port, const char *printer,
99 int print_fd, int mode, const char *user,
100 const char *title, int copies, int banner,
101 int format, int order, int reserve,
102 int manual_copies, int timeout, int contimeout);
103 static void lpd_timeout(int sig);
104 static int lpd_write(int lpd_fd, char *buffer, int length);
105 #ifndef HAVE_RRESVPORT_AF
106 static int rresvport_af(int *port, int family);
107 #endif /* !HAVE_RRESVPORT_AF */
108 static void sigterm_handler(int sig);
109
110
111 /*
112 * 'main()' - Send a file to the printer or server.
113 *
114 * Usage:
115 *
116 * printer-uri job-id user title copies options [file]
117 */
118
119 int /* O - Exit status */
120 main(int argc, /* I - Number of command-line arguments (6 or 7) */
121 char *argv[]) /* I - Command-line arguments */
122 {
123 char method[255], /* Method in URI */
124 hostname[1024], /* Hostname */
125 username[255], /* Username info */
126 resource[1024], /* Resource info (printer name) */
127 *options, /* Pointer to options */
128 name[255], /* Name of option */
129 value[255], /* Value of option */
130 *ptr, /* Pointer into name or value */
131 *filename, /* File to print */
132 title[256]; /* Title string */
133 int port; /* Port number */
134 int fd; /* Print file */
135 int status; /* Status of LPD job */
136 int mode; /* Print mode */
137 int banner; /* Print banner page? */
138 int format; /* Print format */
139 int order; /* Order of control/data files */
140 int reserve; /* Reserve priviledged port? */
141 int sanitize_title; /* Sanitize title string? */
142 int manual_copies, /* Do manual copies? */
143 timeout, /* Timeout */
144 contimeout, /* Connection timeout */
145 copies; /* Number of copies */
146 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
147 struct sigaction action; /* Actions for POSIX signals */
148 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
149
150
151 /*
152 * Make sure status messages are not buffered...
153 */
154
155 setbuf(stderr, NULL);
156
157 /*
158 * Ignore SIGPIPE and catch SIGTERM signals...
159 */
160
161 #ifdef HAVE_SIGSET
162 sigset(SIGPIPE, SIG_IGN);
163 sigset(SIGTERM, sigterm_handler);
164 #elif defined(HAVE_SIGACTION)
165 memset(&action, 0, sizeof(action));
166 action.sa_handler = SIG_IGN;
167 sigaction(SIGPIPE, &action, NULL);
168
169 sigemptyset(&action.sa_mask);
170 sigaddset(&action.sa_mask, SIGTERM);
171 action.sa_handler = sigterm_handler;
172 sigaction(SIGTERM, &action, NULL);
173 #else
174 signal(SIGPIPE, SIG_IGN);
175 signal(SIGTERM, sigterm_handler);
176 #endif /* HAVE_SIGSET */
177
178 /*
179 * Check command-line...
180 */
181
182 if (argc == 1)
183 {
184 puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\"");
185 return (CUPS_BACKEND_OK);
186 }
187 else if (argc < 6 || argc > 7)
188 {
189 fprintf(stderr, _("Usage: %s job-id user title copies options [file]\n"),
190 argv[0]);
191 return (CUPS_BACKEND_FAILED);
192 }
193
194 /*
195 * Extract the hostname and printer name from the URI...
196 */
197
198 httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv),
199 method, sizeof(method), username, sizeof(username),
200 hostname, sizeof(hostname), &port,
201 resource, sizeof(resource));
202
203 if (!username[0])
204 {
205 /*
206 * If no username is in the device URI, then use the print job user...
207 */
208
209 strlcpy(username, argv[2], sizeof(username));
210 }
211
212 /*
213 * See if there are any options...
214 */
215
216 mode = MODE_STANDARD;
217 banner = 0;
218 format = 'l';
219 order = ORDER_CONTROL_DATA;
220 reserve = RESERVE_ANY;
221 manual_copies = 1;
222 timeout = 300;
223 contimeout = 7 * 24 * 60 * 60;
224
225 #ifdef __APPLE__
226 /*
227 * We want to pass utf-8 characters, not re-map them (3071945)
228 */
229
230 sanitize_title = 0;
231
232 /*
233 * Get the default timeout from a system preference...
234 */
235
236 {
237 CFPropertyListRef pvalue; /* Preference value */
238 SInt32 toval; /* Timeout value */
239
240
241 pvalue = CFPreferencesCopyValue(CFSTR("timeout"),
242 CFSTR("com.apple.print.backends"),
243 kCFPreferencesAnyUser,
244 kCFPreferencesCurrentHost);
245 if (pvalue)
246 {
247 if (CFGetTypeID(pvalue) == CFNumberGetTypeID())
248 {
249 CFNumberGetValue(pvalue, kCFNumberSInt32Type, &toval);
250 contimeout = (int)toval;
251 }
252
253 CFRelease(pvalue);
254 }
255 }
256 #else
257 sanitize_title = 1;
258 #endif /* __APPLE__ */
259
260 if ((options = strchr(resource, '?')) != NULL)
261 {
262 /*
263 * Yup, terminate the device name string and move to the first
264 * character of the options...
265 */
266
267 *options++ = '\0';
268
269 /*
270 * Parse options...
271 */
272
273 while (*options)
274 {
275 /*
276 * Get the name...
277 */
278
279 for (ptr = name; *options && *options != '=';)
280 if (ptr < (name + sizeof(name) - 1))
281 *ptr++ = *options++;
282 *ptr = '\0';
283
284 if (*options == '=')
285 {
286 /*
287 * Get the value...
288 */
289
290 options ++;
291
292 for (ptr = value; *options && *options != '+' && *options != '&';)
293 if (ptr < (value + sizeof(value) - 1))
294 *ptr++ = *options++;
295 *ptr = '\0';
296
297 if (*options == '+' || *options == '&')
298 options ++;
299 }
300 else
301 value[0] = '\0';
302
303 /*
304 * Process the option...
305 */
306
307 if (!strcasecmp(name, "banner"))
308 {
309 /*
310 * Set the banner...
311 */
312
313 banner = !value[0] || !strcasecmp(value, "on") ||
314 !strcasecmp(value, "yes") || !strcasecmp(value, "true");
315 }
316 else if (!strcasecmp(name, "format") && value[0])
317 {
318 /*
319 * Set output format...
320 */
321
322 if (strchr("cdfglnoprtv", value[0]))
323 format = value[0];
324 else
325 fprintf(stderr, _("ERROR: Unknown format character \"%c\"\n"),
326 value[0]);
327 }
328 else if (!strcasecmp(name, "mode") && value[0])
329 {
330 /*
331 * Set control/data order...
332 */
333
334 if (!strcasecmp(value, "standard"))
335 mode = MODE_STANDARD;
336 else if (!strcasecmp(value, "stream"))
337 mode = MODE_STREAM;
338 else
339 fprintf(stderr, _("ERROR: Unknown print mode \"%s\"\n"), value);
340 }
341 else if (!strcasecmp(name, "order") && value[0])
342 {
343 /*
344 * Set control/data order...
345 */
346
347 if (!strcasecmp(value, "control,data"))
348 order = ORDER_CONTROL_DATA;
349 else if (!strcasecmp(value, "data,control"))
350 order = ORDER_DATA_CONTROL;
351 else
352 fprintf(stderr, _("ERROR: Unknown file order \"%s\"\n"), value);
353 }
354 else if (!strcasecmp(name, "reserve"))
355 {
356 /*
357 * Set port reservation mode...
358 */
359
360 if (!value[0] || !strcasecmp(value, "on") ||
361 !strcasecmp(value, "yes") || !strcasecmp(value, "true") ||
362 !strcasecmp(value, "rfc1179"))
363 reserve = RESERVE_RFC1179;
364 else if (!strcasecmp(value, "any"))
365 reserve = RESERVE_ANY;
366 else
367 reserve = RESERVE_NONE;
368 }
369 else if (!strcasecmp(name, "manual_copies"))
370 {
371 /*
372 * Set manual copies...
373 */
374
375 manual_copies = !value[0] || !strcasecmp(value, "on") ||
376 !strcasecmp(value, "yes") || !strcasecmp(value, "true");
377 }
378 else if (!strcasecmp(name, "sanitize_title"))
379 {
380 /*
381 * Set sanitize title...
382 */
383
384 sanitize_title = !value[0] || !strcasecmp(value, "on") ||
385 !strcasecmp(value, "yes") || !strcasecmp(value, "true");
386 }
387 else if (!strcasecmp(name, "timeout"))
388 {
389 /*
390 * Set the timeout...
391 */
392
393 if (atoi(value) > 0)
394 timeout = atoi(value);
395 }
396 else if (!strcasecmp(name, "contimeout"))
397 {
398 /*
399 * Set the connection timeout...
400 */
401
402 if (atoi(value) > 0)
403 contimeout = atoi(value);
404 }
405 }
406 }
407
408 if (mode == MODE_STREAM)
409 order = ORDER_CONTROL_DATA;
410
411 /*
412 * If we have 7 arguments, print the file named on the command-line.
413 * Otherwise, copy stdin to a temporary file and print the temporary
414 * file.
415 */
416
417 if (argc == 6 && mode == MODE_STANDARD)
418 {
419 /*
420 * Copy stdin to a temporary file...
421 */
422
423 char buffer[8192]; /* Buffer for copying */
424 int bytes; /* Number of bytes read */
425
426
427 if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0)
428 {
429 perror("ERROR: unable to create temporary file");
430 return (CUPS_BACKEND_FAILED);
431 }
432
433 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
434 if (write(fd, buffer, bytes) < bytes)
435 {
436 perror("ERROR: unable to write to temporary file");
437 close(fd);
438 unlink(tmpfilename);
439 return (CUPS_BACKEND_FAILED);
440 }
441
442 filename = tmpfilename;
443 }
444 else if (argc == 6)
445 {
446 /*
447 * Stream from stdin...
448 */
449
450 filename = NULL;
451 fd = 0;
452 }
453 else
454 {
455 filename = argv[6];
456 fd = open(filename, O_RDONLY);
457
458 if (fd == -1)
459 {
460 fprintf(stderr, _("ERROR: Unable to open print file %s: %s\n"),
461 filename, strerror(errno));
462 return (CUPS_BACKEND_FAILED);
463 }
464 }
465
466 /*
467 * Sanitize the document title...
468 */
469
470 strlcpy(title, argv[3], sizeof(title));
471
472 if (sanitize_title)
473 {
474 /*
475 * Sanitize the title string so that we don't cause problems on
476 * the remote end...
477 */
478
479 for (ptr = title; *ptr; ptr ++)
480 if (!isalnum(*ptr & 255) && !isspace(*ptr & 255))
481 *ptr = '_';
482 }
483
484 /*
485 * Queue the job...
486 */
487
488 if (argc > 6)
489 {
490 if (manual_copies)
491 {
492 manual_copies = atoi(argv[4]);
493 copies = 1;
494 }
495 else
496 {
497 manual_copies = 1;
498 copies = atoi(argv[4]);
499 }
500
501 status = lpd_queue(hostname, port, resource + 1, fd, mode,
502 username, title, copies,
503 banner, format, order, reserve, manual_copies,
504 timeout, contimeout);
505
506 if (!status)
507 fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
508 }
509 else
510 status = lpd_queue(hostname, port, resource + 1, fd, mode,
511 username, title, 1,
512 banner, format, order, reserve, 1,
513 timeout, contimeout);
514
515 /*
516 * Remove the temporary file if necessary...
517 */
518
519 if (tmpfilename[0])
520 unlink(tmpfilename);
521
522 if (fd)
523 close(fd);
524
525 /*
526 * Return the queue status...
527 */
528
529 return (status);
530 }
531
532
533 /*
534 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
535 */
536
537 static int /* O - Status of command */
538 lpd_command(int fd, /* I - Socket connection to LPD host */
539 int timeout, /* I - Seconds to wait for a response */
540 char *format, /* I - printf()-style format string */
541 ...) /* I - Additional args as necessary */
542 {
543 va_list ap; /* Argument pointer */
544 char buf[1024]; /* Output buffer */
545 int bytes; /* Number of bytes to output */
546 char status; /* Status from command */
547
548
549 /*
550 * Don't try to send commands if the job has been cancelled...
551 */
552
553 if (abort_job)
554 return (-1);
555
556 /*
557 * Format the string...
558 */
559
560 va_start(ap, format);
561 bytes = vsnprintf(buf, sizeof(buf), format, ap);
562 va_end(ap);
563
564 fprintf(stderr, "DEBUG: lpd_command %2.2x %s", buf[0], buf + 1);
565
566 /*
567 * Send the command...
568 */
569
570 fprintf(stderr, "DEBUG: Sending command string (%d bytes)...\n", bytes);
571
572 if (lpd_write(fd, buf, bytes) < bytes)
573 {
574 perror("ERROR: Unable to send LPD command");
575 return (-1);
576 }
577
578 /*
579 * Read back the status from the command and return it...
580 */
581
582 fputs("DEBUG: Reading command status...\n", stderr);
583
584 alarm(timeout);
585
586 if (recv(fd, &status, 1, 0) < 1)
587 {
588 fprintf(stderr,
589 _("WARNING: Remote host did not respond with command status "
590 "byte after %d seconds!\n"), timeout);
591 status = errno;
592 }
593
594 alarm(0);
595
596 fprintf(stderr, "DEBUG: lpd_command returning %d\n", status);
597
598 return (status);
599 }
600
601
602 /*
603 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
604 */
605
606 static int /* O - Zero on success, non-zero on failure */
607 lpd_queue(const char *hostname, /* I - Host to connect to */
608 int port, /* I - Port to connect on */
609 const char *printer, /* I - Printer/queue name */
610 int print_fd, /* I - File to print */
611 int mode, /* I - Print mode */
612 const char *user, /* I - Requesting user */
613 const char *title, /* I - Job title */
614 int copies, /* I - Number of copies */
615 int banner, /* I - Print LPD banner? */
616 int format, /* I - Format specifier */
617 int order, /* I - Order of data/control files */
618 int reserve, /* I - Reserve ports? */
619 int manual_copies, /* I - Do copies by hand... */
620 int timeout, /* I - Timeout... */
621 int contimeout) /* I - Connection timeout */
622 {
623 char localhost[255]; /* Local host name */
624 int error; /* Error number */
625 struct stat filestats; /* File statistics */
626 int lport; /* LPD connection local port */
627 int fd; /* LPD socket */
628 char control[10240], /* LPD control 'file' */
629 *cptr; /* Pointer into control file string */
630 char status; /* Status byte from command */
631 char portname[255]; /* Port name */
632 int delay; /* Delay for retries... */
633 char addrname[256]; /* Address name */
634 http_addrlist_t *addrlist, /* Address list */
635 *addr; /* Socket address */
636 int copy; /* Copies written */
637 time_t start_time; /* Time of first connect */
638 int recoverable; /* Recoverable error shown? */
639 size_t nbytes; /* Number of bytes written */
640 off_t tbytes; /* Total bytes written */
641 char buffer[32768]; /* Output buffer */
642 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
643 struct sigaction action; /* Actions for POSIX signals */
644 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
645
646
647 /*
648 * Setup an alarm handler for timeouts...
649 */
650
651 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
652 sigset(SIGALRM, lpd_timeout);
653 #elif defined(HAVE_SIGACTION)
654 memset(&action, 0, sizeof(action));
655
656 sigemptyset(&action.sa_mask);
657 action.sa_handler = lpd_timeout;
658 sigaction(SIGALRM, &action, NULL);
659 #else
660 signal(SIGALRM, lpd_timeout);
661 #endif /* HAVE_SIGSET */
662
663 /*
664 * Find the printer...
665 */
666
667 sprintf(portname, "%d", port);
668
669 if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
670 {
671 fprintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"), hostname);
672 return (CUPS_BACKEND_STOP);
673 }
674
675 /*
676 * Remember when we started trying to connect to the printer...
677 */
678
679 recoverable = 0;
680 start_time = time(NULL);
681
682 /*
683 * Loop forever trying to print the file...
684 */
685
686 while (!abort_job)
687 {
688 /*
689 * First try to reserve a port for this connection...
690 */
691
692 fputs("STATE: +connecting-to-device\n", stderr);
693 fprintf(stderr,
694 _("INFO: Attempting to connect to host %s for printer %s\n"),
695 hostname, printer);
696
697 for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist,
698 delay = 5;;
699 addr = addr->next)
700 {
701 /*
702 * Stop if this job has been cancelled...
703 */
704
705 if (abort_job)
706 {
707 httpAddrFreeList(addrlist);
708
709 return (CUPS_BACKEND_FAILED);
710 }
711
712 /*
713 * Choose the next priviledged port...
714 */
715
716 if (!addr)
717 addr = addrlist;
718
719 lport --;
720
721 if (lport < 721 && reserve == RESERVE_RFC1179)
722 lport = 731;
723 else if (lport < 1)
724 lport = 1023;
725
726 #ifdef HAVE_GETEUID
727 if (geteuid() || !reserve)
728 #else
729 if (getuid() || !reserve)
730 #endif /* HAVE_GETEUID */
731 {
732 /*
733 * Just create a regular socket...
734 */
735
736 if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
737 {
738 perror("ERROR: Unable to create socket");
739 sleep(1);
740
741 continue;
742 }
743
744 lport = 0;
745 }
746 else
747 {
748 /*
749 * We're running as root and want to comply with RFC 1179. Reserve a
750 * priviledged lport between 721 and 731...
751 */
752
753 if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0)
754 {
755 perror("ERROR: Unable to reserve port");
756 sleep(1);
757
758 continue;
759 }
760 }
761
762 /*
763 * Connect to the printer or server...
764 */
765
766 if (abort_job)
767 {
768 httpAddrFreeList(addrlist);
769
770 close(fd);
771
772 return (CUPS_BACKEND_FAILED);
773 }
774
775 if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr))))
776 break;
777
778 error = errno;
779 close(fd);
780 fd = -1;
781
782 if (addr->next)
783 continue;
784
785 if (getenv("CLASS") != NULL)
786 {
787 /*
788 * If the CLASS environment variable is set, the job was submitted
789 * to a class and not to a specific queue. In this case, we want
790 * to abort immediately so that the job can be requeued on the next
791 * available printer in the class.
792 */
793
794 fputs(_("INFO: Unable to contact printer, queuing on next "
795 "printer in class...\n"), stderr);
796
797 httpAddrFreeList(addrlist);
798
799 /*
800 * Sleep 5 seconds to keep the job from requeuing too rapidly...
801 */
802
803 sleep(5);
804
805 return (CUPS_BACKEND_FAILED);
806 }
807
808 if (error == ECONNREFUSED || error == EHOSTDOWN ||
809 error == EHOSTUNREACH)
810 {
811 if (contimeout && (time(NULL) - start_time) > contimeout)
812 {
813 fputs(_("ERROR: Printer not responding!\n"), stderr);
814 return (CUPS_BACKEND_FAILED);
815 }
816
817 recoverable = 1;
818
819 fprintf(stderr,
820 _("WARNING: recoverable: Network host \'%s\' is busy; will "
821 "retry in %d seconds...\n"),
822 hostname, delay);
823
824 sleep(delay);
825
826 if (delay < 30)
827 delay += 5;
828 }
829 else if (error == EADDRINUSE)
830 {
831 /*
832 * Try on another port...
833 */
834
835 sleep(1);
836 }
837 else
838 {
839 recoverable = 1;
840
841 fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno));
842 fputs(_("ERROR: recoverable: Unable to connect to printer; will "
843 "retry in 30 seconds...\n"), stderr);
844 sleep(30);
845 }
846 }
847
848 if (recoverable)
849 {
850 /*
851 * If we've shown a recoverable error make sure the printer proxies
852 * have a chance to see the recovered message. Not pretty but
853 * necessary for now...
854 */
855
856 fputs("INFO: recovered: \n", stderr);
857 sleep(5);
858 }
859
860 fputs("STATE: -connecting-to-device\n", stderr);
861 fprintf(stderr, _("INFO: Connected to %s...\n"), hostname);
862
863 #ifdef AF_INET6
864 if (addr->addr.addr.sa_family == AF_INET6)
865 fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6) (local port %d)...\n",
866 httpAddrString(&addr->addr, addrname, sizeof(addrname)),
867 ntohs(addr->addr.ipv6.sin6_port), lport);
868 else
869 #endif /* AF_INET6 */
870 if (addr->addr.addr.sa_family == AF_INET)
871 fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4) (local port %d)...\n",
872 httpAddrString(&addr->addr, addrname, sizeof(addrname)),
873 ntohs(addr->addr.ipv4.sin_port), lport);
874
875 /*
876 * Next, open the print file and figure out its size...
877 */
878
879 if (print_fd)
880 {
881 /*
882 * Use the size from the print file...
883 */
884
885 if (fstat(print_fd, &filestats))
886 {
887 httpAddrFreeList(addrlist);
888 close(fd);
889
890 perror("ERROR: unable to stat print file");
891 return (CUPS_BACKEND_FAILED);
892 }
893
894 filestats.st_size *= manual_copies;
895 }
896 else
897 {
898 /*
899 * Use a "very large value" for the size so that the printer will
900 * keep printing until we close the connection...
901 */
902
903 #ifdef _LARGEFILE_SOURCE
904 filestats.st_size = (size_t)(999999999999.0);
905 #else
906 filestats.st_size = 2147483647;
907 #endif /* _LARGEFILE_SOURCE */
908 }
909
910 /*
911 * Send a job header to the printer, specifying no banner page and
912 * literal output...
913 */
914
915 if (lpd_command(fd, timeout, "\002%s\n",
916 printer)) /* Receive print job(s) */
917 {
918 httpAddrFreeList(addrlist);
919 close(fd);
920 return (CUPS_BACKEND_FAILED);
921 }
922
923 httpGetHostname(NULL, localhost, sizeof(localhost));
924
925 snprintf(control, sizeof(control),
926 "H%.31s\n" /* RFC 1179, Section 7.2 - host name <= 31 chars */
927 "P%.31s\n" /* RFC 1179, Section 7.2 - user name <= 31 chars */
928 "J%.99s\n", /* RFC 1179, Section 7.2 - job name <= 99 chars */
929 localhost, user, title);
930 cptr = control + strlen(control);
931
932 if (banner)
933 {
934 snprintf(cptr, sizeof(control) - (cptr - control),
935 "C%.31s\n" /* RFC 1179, Section 7.2 - class name <= 31 chars */
936 "L%s\n",
937 localhost, user);
938 cptr += strlen(cptr);
939 }
940
941 while (copies > 0)
942 {
943 snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n",
944 format, (int)getpid() % 1000, localhost);
945 cptr += strlen(cptr);
946 copies --;
947 }
948
949 snprintf(cptr, sizeof(control) - (cptr - control),
950 "UdfA%03d%.15s\n"
951 "N%.131s\n", /* RFC 1179, Section 7.2 - sourcefile name <= 131 chars */
952 (int)getpid() % 1000, localhost, title);
953
954 fprintf(stderr, "DEBUG: Control file is:\n%s", control);
955
956 if (order == ORDER_CONTROL_DATA)
957 {
958 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
959 (int)getpid() % 1000, localhost))
960 {
961 httpAddrFreeList(addrlist);
962 close(fd);
963
964 return (CUPS_BACKEND_FAILED);
965 }
966
967 fprintf(stderr, _("INFO: Sending control file (%u bytes)\n"),
968 (unsigned)strlen(control));
969
970 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
971 {
972 status = errno;
973 perror("ERROR: Unable to write control file");
974 }
975 else
976 {
977 alarm(timeout);
978
979 if (read(fd, &status, 1) < 1)
980 {
981 fprintf(stderr,
982 _("WARNING: Remote host did not respond with control "
983 "status byte after %d seconds!\n"), timeout);
984 status = errno;
985 }
986
987 alarm(0);
988 }
989
990 if (status != 0)
991 fprintf(stderr,
992 _("ERROR: Remote host did not accept control file (%d)\n"),
993 status);
994 else
995 fputs(_("INFO: Control file sent successfully\n"), stderr);
996 }
997 else
998 status = 0;
999
1000 if (status == 0)
1001 {
1002 /*
1003 * Send the print file...
1004 */
1005
1006 if (lpd_command(fd, timeout, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
1007 CUPS_LLCAST filestats.st_size, (int)getpid() % 1000,
1008 localhost))
1009 {
1010 httpAddrFreeList(addrlist);
1011 close(fd);
1012
1013 return (CUPS_BACKEND_FAILED);
1014 }
1015
1016 fprintf(stderr,
1017 #ifdef HAVE_LONG_LONG
1018 _("INFO: Sending data file (%lld bytes)\n"),
1019 #else
1020 _("INFO: Sending data file (%ld bytes)\n"),
1021 #endif /* HAVE_LONG_LONG */
1022 CUPS_LLCAST filestats.st_size);
1023
1024 tbytes = 0;
1025 for (copy = 0; copy < manual_copies; copy ++)
1026 {
1027 lseek(print_fd, 0, SEEK_SET);
1028
1029 while ((nbytes = read(print_fd, buffer, sizeof(buffer))) > 0)
1030 {
1031 fprintf(stderr, _("INFO: Spooling LPR job, %.0f%% complete...\n"),
1032 100.0 * tbytes / filestats.st_size);
1033
1034 if (lpd_write(fd, buffer, nbytes) < nbytes)
1035 {
1036 perror("ERROR: Unable to send print file to printer");
1037 break;
1038 }
1039 else
1040 tbytes += nbytes;
1041 }
1042 }
1043
1044 if (mode == MODE_STANDARD)
1045 {
1046 if (tbytes < filestats.st_size)
1047 status = errno;
1048 else if (lpd_write(fd, "", 1) < 1)
1049 {
1050 perror("ERROR: Unable to send trailing nul to printer");
1051 status = errno;
1052 }
1053 else
1054 {
1055 /*
1056 * Read the status byte from the printer; if we can't read the byte
1057 * back now, we should set status to "errno", however at this point
1058 * we know the printer got the whole file and we don't necessarily
1059 * want to requeue it over and over...
1060 */
1061
1062 alarm(timeout);
1063
1064 if (recv(fd, &status, 1, 0) < 1)
1065 {
1066 fprintf(stderr,
1067 _("WARNING: Remote host did not respond with data "
1068 "status byte after %d seconds!\n"), timeout);
1069 status = 0;
1070 }
1071
1072 alarm(0);
1073 }
1074 }
1075 else
1076 status = 0;
1077
1078 if (status != 0)
1079 fprintf(stderr, _("ERROR: Remote host did not accept data file (%d)\n"),
1080 status);
1081 else
1082 fputs(_("INFO: Data file sent successfully\n"), stderr);
1083 }
1084
1085 if (status == 0 && order == ORDER_DATA_CONTROL)
1086 {
1087 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
1088 (int)getpid() % 1000, localhost))
1089 {
1090 httpAddrFreeList(addrlist);
1091 close(fd);
1092
1093 return (CUPS_BACKEND_FAILED);
1094 }
1095
1096 fprintf(stderr, _("INFO: Sending control file (%lu bytes)\n"),
1097 (unsigned long)strlen(control));
1098
1099 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
1100 {
1101 status = errno;
1102 perror("ERROR: Unable to write control file");
1103 }
1104 else
1105 {
1106 alarm(timeout);
1107
1108 if (read(fd, &status, 1) < 1)
1109 {
1110 fprintf(stderr,
1111 _("WARNING: Remote host did not respond with control "
1112 "status byte after %d seconds!\n"), timeout);
1113 status = errno;
1114 }
1115
1116 alarm(0);
1117 }
1118
1119 if (status != 0)
1120 fprintf(stderr,
1121 _("ERROR: Remote host did not accept control file (%d)\n"),
1122 status);
1123 else
1124 fputs(_("INFO: Control file sent successfully\n"), stderr);
1125 }
1126
1127 /*
1128 * Close the socket connection and input file...
1129 */
1130
1131 close(fd);
1132
1133 if (status == 0)
1134 {
1135 httpAddrFreeList(addrlist);
1136
1137 return (CUPS_BACKEND_OK);
1138 }
1139
1140 /*
1141 * Waiting for a retry...
1142 */
1143
1144 sleep(30);
1145 }
1146
1147 httpAddrFreeList(addrlist);
1148
1149 /*
1150 * If we get here, then the job has been cancelled...
1151 */
1152
1153 return (CUPS_BACKEND_FAILED);
1154 }
1155
1156
1157 /*
1158 * 'lpd_timeout()' - Handle timeout alarms...
1159 */
1160
1161 static void
1162 lpd_timeout(int sig) /* I - Signal number */
1163 {
1164 (void)sig;
1165
1166 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1167 signal(SIGALRM, lpd_timeout);
1168 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1169 }
1170
1171
1172 /*
1173 * 'lpd_write()' - Write a buffer of data to an LPD server.
1174 */
1175
1176 static int /* O - Number of bytes written or -1 on error */
1177 lpd_write(int lpd_fd, /* I - LPD socket */
1178 char *buffer, /* I - Buffer to write */
1179 int length) /* I - Number of bytes to write */
1180 {
1181 int bytes, /* Number of bytes written */
1182 total; /* Total number of bytes written */
1183
1184
1185 if (abort_job)
1186 return (-1);
1187
1188 total = 0;
1189 while ((bytes = send(lpd_fd, buffer, length - total, 0)) >= 0)
1190 {
1191 total += bytes;
1192 buffer += bytes;
1193
1194 if (total == length)
1195 break;
1196 }
1197
1198 if (bytes < 0)
1199 return (-1);
1200 else
1201 return (length);
1202 }
1203
1204
1205 #ifndef HAVE_RRESVPORT_AF
1206 /*
1207 * 'rresvport_af()' - A simple implementation of rresvport_af().
1208 */
1209
1210 static int /* O - Socket or -1 on error */
1211 rresvport_af(int *port, /* IO - Port number to bind to */
1212 int family) /* I - Address family */
1213 {
1214 http_addr_t addr; /* Socket address */
1215 int fd; /* Socket file descriptor */
1216
1217
1218 /*
1219 * Try to create an IPv4 socket...
1220 */
1221
1222 if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
1223 return (-1);
1224
1225 /*
1226 * Initialize the address buffer...
1227 */
1228
1229 memset(&addr, 0, sizeof(addr));
1230 addr.addr.sa_family = family;
1231
1232 /*
1233 * Try to bind the socket to a reserved port...
1234 */
1235
1236 while (*port > 511)
1237 {
1238 /*
1239 * Set the port number...
1240 */
1241
1242 # ifdef AF_INET6
1243 if (family == AF_INET6)
1244 addr.ipv6.sin6_port = htons(*port);
1245 else
1246 # endif /* AF_INET6 */
1247 addr.ipv4.sin_port = htons(*port);
1248
1249 /*
1250 * Try binding the port to the socket; return if all is OK...
1251 */
1252
1253 if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
1254 return (fd);
1255
1256 /*
1257 * Stop if we have any error other than "address already in use"...
1258 */
1259
1260 if (errno != EADDRINUSE)
1261 {
1262 # ifdef WIN32
1263 closesocket(fd);
1264 # else
1265 close(fd);
1266 # endif /* WIN32 */
1267
1268 return (-1);
1269 }
1270
1271 /*
1272 * Try the next port...
1273 */
1274
1275 (*port)--;
1276 }
1277
1278 /*
1279 * Wasn't able to bind to a reserved port, so close the socket and return
1280 * -1...
1281 */
1282
1283 # ifdef WIN32
1284 closesocket(fd);
1285 # else
1286 close(fd);
1287 # endif /* WIN32 */
1288
1289 return (-1);
1290 }
1291 #endif /* !HAVE_RRESVPORT_AF */
1292
1293
1294 /*
1295 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1296 */
1297
1298 static void
1299 sigterm_handler(int sig) /* I - Signal */
1300 {
1301 (void)sig; /* remove compiler warnings... */
1302
1303 abort_job = 1;
1304 }
1305
1306
1307 /*
1308 * End of "$Id: lpd.c 6649 2007-07-11 21:46:42Z mike $".
1309 */