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