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