]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/lpd.c
Merge changes from CUPS 1.4svn-r8394.
[thirdparty/cups.git] / backend / lpd.c
1 /*
2 * "$Id: lpd.c 7740 2008-07-14 23:58:05Z mike $"
3 *
4 * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 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/http-private.h>
33 #include "backend-private.h"
34 #include <stdarg.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37
38 #ifdef WIN32
39 # include <winsock.h>
40 #else
41 # include <sys/socket.h>
42 # include <netinet/in.h>
43 # include <arpa/inet.h>
44 # include <netdb.h>
45 #endif /* WIN32 */
46 #ifdef __APPLE__
47 # include <CoreFoundation/CFNumber.h>
48 # include <CoreFoundation/CFPreferences.h>
49 #endif /* __APPLE__ */
50
51
52 /*
53 * Globals...
54 */
55
56 static char tmpfilename[1024] = ""; /* Temporary spool file name */
57 static int abort_job = 0; /* Non-zero if we get SIGTERM */
58
59
60 /*
61 * Print mode...
62 */
63
64 #define MODE_STANDARD 0 /* Queue a copy */
65 #define MODE_STREAM 1 /* Stream a copy */
66
67
68 /*
69 * The order for control and data files in LPD requests...
70 */
71
72 #define ORDER_CONTROL_DATA 0 /* Control file first, then data */
73 #define ORDER_DATA_CONTROL 1 /* Data file first, then control */
74
75
76 /*
77 * What to reserve...
78 */
79
80 #define RESERVE_NONE 0 /* Don't reserve a priviledged port */
81 #define RESERVE_RFC1179 1 /* Reserve port 721-731 */
82 #define RESERVE_ANY 2 /* Reserve port 1-1023 */
83
84
85 /*
86 * Local functions...
87 */
88
89 static int lpd_command(int lpd_fd, int timeout, char *format, ...);
90 static int lpd_queue(const char *hostname, int port, const char *printer,
91 int print_fd, int mode, const char *user,
92 const char *title, int copies, int banner,
93 int format, int order, int reserve,
94 int manual_copies, int timeout, int contimeout);
95 static void lpd_timeout(int sig);
96 static int lpd_write(int lpd_fd, char *buffer, int length);
97 #ifndef HAVE_RRESVPORT_AF
98 static int rresvport_af(int *port, int family);
99 #endif /* !HAVE_RRESVPORT_AF */
100 static void sigterm_handler(int sig);
101
102
103 /*
104 * 'main()' - Send a file to the printer or server.
105 *
106 * Usage:
107 *
108 * printer-uri job-id user title copies options [file]
109 */
110
111 int /* O - Exit status */
112 main(int argc, /* I - Number of command-line arguments (6 or 7) */
113 char *argv[]) /* I - Command-line arguments */
114 {
115 const char *device_uri; /* Device URI */
116 char method[255], /* Method in URI */
117 hostname[1024], /* Hostname */
118 username[255], /* Username info */
119 resource[1024], /* Resource info (printer name) */
120 *options, /* Pointer to options */
121 *name, /* Name of option */
122 *value, /* Value of option */
123 sep, /* Separator character */
124 *filename, /* File to print */
125 title[256]; /* Title string */
126 int port; /* Port number */
127 int fd; /* Print file */
128 int status; /* Status of LPD job */
129 int mode; /* Print mode */
130 int banner; /* Print banner page? */
131 int format; /* Print format */
132 int order; /* Order of control/data files */
133 int reserve; /* Reserve priviledged port? */
134 int sanitize_title; /* Sanitize title string? */
135 int manual_copies, /* Do manual copies? */
136 timeout, /* Timeout */
137 contimeout, /* Connection timeout */
138 copies; /* Number of copies */
139 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
140 struct sigaction action; /* Actions for POSIX signals */
141 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
142
143
144 /*
145 * Make sure status messages are not buffered...
146 */
147
148 setbuf(stderr, NULL);
149
150 /*
151 * Ignore SIGPIPE and catch SIGTERM signals...
152 */
153
154 #ifdef HAVE_SIGSET
155 sigset(SIGPIPE, SIG_IGN);
156 sigset(SIGTERM, sigterm_handler);
157 #elif defined(HAVE_SIGACTION)
158 memset(&action, 0, sizeof(action));
159 action.sa_handler = SIG_IGN;
160 sigaction(SIGPIPE, &action, NULL);
161
162 sigemptyset(&action.sa_mask);
163 sigaddset(&action.sa_mask, SIGTERM);
164 action.sa_handler = sigterm_handler;
165 sigaction(SIGTERM, &action, NULL);
166 #else
167 signal(SIGPIPE, SIG_IGN);
168 signal(SIGTERM, sigterm_handler);
169 #endif /* HAVE_SIGSET */
170
171 /*
172 * Check command-line...
173 */
174
175 if (argc == 1)
176 {
177 printf("network lpd \"Unknown\" \"%s\"\n",
178 _cupsLangString(cupsLangDefault(), _("LPD/LPR Host or Printer")));
179 return (CUPS_BACKEND_OK);
180 }
181 else if (argc < 6 || argc > 7)
182 {
183 _cupsLangPrintf(stderr,
184 _("Usage: %s job-id user title copies options [file]\n"),
185 argv[0]);
186 return (CUPS_BACKEND_FAILED);
187 }
188
189 /*
190 * Extract the hostname and printer name from the URI...
191 */
192
193 if ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
194 return (CUPS_BACKEND_FAILED);
195
196 httpSeparateURI(HTTP_URI_CODING_ALL, device_uri,
197 method, sizeof(method), username, sizeof(username),
198 hostname, sizeof(hostname), &port,
199 resource, sizeof(resource));
200
201 if (!port)
202 port = 515; /* Default to port 515 */
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 _cupsLangPrintError(_("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 _cupsLangPrintError(_("ERROR: Unable to write to temporary file"));
441 close(fd);
442 unlink(tmpfilename);
443 return (CUPS_BACKEND_FAILED);
444 }
445 }
446 else if (argc == 6)
447 {
448 /*
449 * Stream from stdin...
450 */
451
452 filename = NULL;
453 fd = 0;
454 }
455 else
456 {
457 filename = argv[6];
458 fd = open(filename, O_RDONLY);
459
460 if (fd == -1)
461 {
462 _cupsLangPrintf(stderr, _("ERROR: Unable to open print file %s: %s\n"),
463 filename, strerror(errno));
464 return (CUPS_BACKEND_FAILED);
465 }
466 }
467
468 /*
469 * Sanitize the document title...
470 */
471
472 strlcpy(title, argv[3], sizeof(title));
473
474 if (sanitize_title)
475 {
476 /*
477 * Sanitize the title string so that we don't cause problems on
478 * the remote end...
479 */
480
481 char *ptr;
482
483 for (ptr = title; *ptr; ptr ++)
484 if (!isalnum(*ptr & 255) && !isspace(*ptr & 255))
485 *ptr = '_';
486 }
487
488 /*
489 * Queue the job...
490 */
491
492 if (argc > 6)
493 {
494 if (manual_copies)
495 {
496 manual_copies = atoi(argv[4]);
497 copies = 1;
498 }
499 else
500 {
501 manual_copies = 1;
502 copies = atoi(argv[4]);
503 }
504
505 status = lpd_queue(hostname, port, resource + 1, fd, mode,
506 username, title, copies,
507 banner, format, order, reserve, manual_copies,
508 timeout, contimeout);
509
510 if (!status)
511 fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
512 }
513 else
514 status = lpd_queue(hostname, port, resource + 1, fd, mode,
515 username, title, 1,
516 banner, format, order, reserve, 1,
517 timeout, contimeout);
518
519 /*
520 * Remove the temporary file if necessary...
521 */
522
523 if (tmpfilename[0])
524 unlink(tmpfilename);
525
526 if (fd)
527 close(fd);
528
529 /*
530 * Return the queue status...
531 */
532
533 return (status);
534 }
535
536
537 /*
538 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
539 */
540
541 static int /* O - Status of command */
542 lpd_command(int fd, /* I - Socket connection to LPD host */
543 int timeout, /* I - Seconds to wait for a response */
544 char *format, /* I - printf()-style format string */
545 ...) /* I - Additional args as necessary */
546 {
547 va_list ap; /* Argument pointer */
548 char buf[1024]; /* Output buffer */
549 int bytes; /* Number of bytes to output */
550 char status; /* Status from command */
551
552
553 /*
554 * Don't try to send commands if the job has been cancelled...
555 */
556
557 if (abort_job)
558 return (-1);
559
560 /*
561 * Format the string...
562 */
563
564 va_start(ap, format);
565 bytes = vsnprintf(buf, sizeof(buf), format, ap);
566 va_end(ap);
567
568 fprintf(stderr, "DEBUG: lpd_command %2.2x %s", buf[0], buf + 1);
569
570 /*
571 * Send the command...
572 */
573
574 fprintf(stderr, "DEBUG: Sending command string (%d bytes)...\n", bytes);
575
576 if (lpd_write(fd, buf, bytes) < bytes)
577 {
578 _cupsLangPrintError(_("ERROR: Unable to send LPD command"));
579 return (-1);
580 }
581
582 /*
583 * Read back the status from the command and return it...
584 */
585
586 fputs("DEBUG: Reading command status...\n", stderr);
587
588 alarm(timeout);
589
590 if (recv(fd, &status, 1, 0) < 1)
591 {
592 _cupsLangPrintf(stderr,
593 _("WARNING: Remote host did not respond with command "
594 "status byte after %d seconds!\n"), timeout);
595 status = errno;
596 }
597
598 alarm(0);
599
600 fprintf(stderr, "DEBUG: lpd_command returning %d\n", status);
601
602 return (status);
603 }
604
605
606 /*
607 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
608 */
609
610 static int /* O - Zero on success, non-zero on failure */
611 lpd_queue(const char *hostname, /* I - Host to connect to */
612 int port, /* I - Port to connect on */
613 const char *printer, /* I - Printer/queue name */
614 int print_fd, /* I - File to print */
615 int mode, /* I - Print mode */
616 const char *user, /* I - Requesting user */
617 const char *title, /* I - Job title */
618 int copies, /* I - Number of copies */
619 int banner, /* I - Print LPD banner? */
620 int format, /* I - Format specifier */
621 int order, /* I - Order of data/control files */
622 int reserve, /* I - Reserve ports? */
623 int manual_copies, /* I - Do copies by hand... */
624 int timeout, /* I - Timeout... */
625 int contimeout) /* I - Connection timeout */
626 {
627 char localhost[255]; /* Local host name */
628 int error; /* Error number */
629 struct stat filestats; /* File statistics */
630 int lport; /* LPD connection local port */
631 int fd; /* LPD socket */
632 char control[10240], /* LPD control 'file' */
633 *cptr; /* Pointer into control file string */
634 char status; /* Status byte from command */
635 char portname[255]; /* Port name */
636 int delay; /* Delay for retries... */
637 char addrname[256]; /* Address name */
638 http_addrlist_t *addrlist, /* Address list */
639 *addr; /* Socket address */
640 int snmp_fd, /* SNMP socket */
641 have_supplies; /* Printer supports supply levels? */
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 fprintf(stderr, "DEBUG: Connecting to %s:%d for printer %s\n",
701 hostname, port, printer);
702 _cupsLangPuts(stderr, _("INFO: Connecting to printer...\n"));
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 _cupsLangPrintError(_("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 _cupsLangPrintError(_("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 _cupsLangPuts(stderr, _("INFO: Connected to printer...\n"));
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 * See if the printer supports SNMP...
885 */
886
887 if ((snmp_fd = _cupsSNMPOpen(addr->addr.addr.sa_family)) >= 0)
888 have_supplies = !backendSNMPSupplies(snmp_fd, &(addr->addr), NULL, NULL);
889 else
890 have_supplies = 0;
891
892 /*
893 * Check for side-channel requests...
894 */
895
896 backendCheckSideChannel(snmp_fd, &(addr->addr));
897
898 /*
899 * Next, open the print file and figure out its size...
900 */
901
902 if (print_fd)
903 {
904 /*
905 * Use the size from the print file...
906 */
907
908 if (fstat(print_fd, &filestats))
909 {
910 httpAddrFreeList(addrlist);
911 close(fd);
912
913 _cupsLangPrintError(_("ERROR: unable to stat print file"));
914 return (CUPS_BACKEND_FAILED);
915 }
916
917 filestats.st_size *= manual_copies;
918 }
919 else
920 {
921 /*
922 * Use a "very large value" for the size so that the printer will
923 * keep printing until we close the connection...
924 */
925
926 #ifdef _LARGEFILE_SOURCE
927 filestats.st_size = (size_t)(999999999999.0);
928 #else
929 filestats.st_size = 2147483647;
930 #endif /* _LARGEFILE_SOURCE */
931 }
932
933 /*
934 * Send a job header to the printer, specifying no banner page and
935 * literal output...
936 */
937
938 if (lpd_command(fd, timeout, "\002%s\n",
939 printer)) /* Receive print job(s) */
940 {
941 httpAddrFreeList(addrlist);
942 close(fd);
943 return (CUPS_BACKEND_FAILED);
944 }
945
946 httpGetHostname(NULL, localhost, sizeof(localhost));
947
948 snprintf(control, sizeof(control),
949 "H%.31s\n" /* RFC 1179, Section 7.2 - host name <= 31 chars */
950 "P%.31s\n" /* RFC 1179, Section 7.2 - user name <= 31 chars */
951 "J%.99s\n", /* RFC 1179, Section 7.2 - job name <= 99 chars */
952 localhost, user, title);
953 cptr = control + strlen(control);
954
955 if (banner)
956 {
957 snprintf(cptr, sizeof(control) - (cptr - control),
958 "C%.31s\n" /* RFC 1179, Section 7.2 - class name <= 31 chars */
959 "L%s\n",
960 localhost, user);
961 cptr += strlen(cptr);
962 }
963
964 while (copies > 0)
965 {
966 snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n",
967 format, (int)getpid() % 1000, localhost);
968 cptr += strlen(cptr);
969 copies --;
970 }
971
972 snprintf(cptr, sizeof(control) - (cptr - control),
973 "UdfA%03d%.15s\n"
974 "N%.131s\n", /* RFC 1179, Section 7.2 - sourcefile name <= 131 chars */
975 (int)getpid() % 1000, localhost, title);
976
977 fprintf(stderr, "DEBUG: Control file is:\n%s", control);
978
979 if (order == ORDER_CONTROL_DATA)
980 {
981 /*
982 * Check for side-channel requests...
983 */
984
985 backendCheckSideChannel(snmp_fd, &(addr->addr));
986
987 /*
988 * Send the control file...
989 */
990
991 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
992 (int)getpid() % 1000, localhost))
993 {
994 httpAddrFreeList(addrlist);
995 close(fd);
996
997 return (CUPS_BACKEND_FAILED);
998 }
999
1000 _cupsLangPrintf(stderr, _("INFO: Sending control file (%u bytes)\n"),
1001 (unsigned)strlen(control));
1002
1003 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
1004 {
1005 status = errno;
1006 _cupsLangPrintError(_("ERROR: Unable to write control file"));
1007 }
1008 else
1009 {
1010 alarm(timeout);
1011
1012 if (read(fd, &status, 1) < 1)
1013 {
1014 _cupsLangPrintf(stderr,
1015 _("WARNING: Remote host did not respond with control "
1016 "status byte after %d seconds!\n"), timeout);
1017 status = errno;
1018 }
1019
1020 alarm(0);
1021 }
1022
1023 if (status != 0)
1024 _cupsLangPrintf(stderr,
1025 _("ERROR: Remote host did not accept control file "
1026 "(%d)\n"), status);
1027 else
1028 _cupsLangPuts(stderr, _("INFO: Control file sent successfully\n"));
1029 }
1030 else
1031 status = 0;
1032
1033 if (status == 0)
1034 {
1035 /*
1036 * Check for side-channel requests...
1037 */
1038
1039 backendCheckSideChannel(snmp_fd, &(addr->addr));
1040
1041 /*
1042 * Send the print file...
1043 */
1044
1045 if (lpd_command(fd, timeout, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
1046 CUPS_LLCAST filestats.st_size, (int)getpid() % 1000,
1047 localhost))
1048 {
1049 httpAddrFreeList(addrlist);
1050 close(fd);
1051
1052 return (CUPS_BACKEND_FAILED);
1053 }
1054
1055 _cupsLangPrintf(stderr,
1056 #ifdef HAVE_LONG_LONG
1057 _("INFO: Sending data file (%lld bytes)\n"),
1058 #else
1059 _("INFO: Sending data file (%ld bytes)\n"),
1060 #endif /* HAVE_LONG_LONG */
1061 CUPS_LLCAST filestats.st_size);
1062
1063 tbytes = 0;
1064 for (copy = 0; copy < manual_copies; copy ++)
1065 {
1066 lseek(print_fd, 0, SEEK_SET);
1067
1068 while ((nbytes = read(print_fd, buffer, sizeof(buffer))) > 0)
1069 {
1070 _cupsLangPrintf(stderr,
1071 _("INFO: Spooling LPR job, %.0f%% complete...\n"),
1072 100.0 * tbytes / filestats.st_size);
1073
1074 if (lpd_write(fd, buffer, nbytes) < nbytes)
1075 {
1076 _cupsLangPrintError(_("ERROR: Unable to send print file to printer"));
1077 break;
1078 }
1079 else
1080 tbytes += nbytes;
1081 }
1082 }
1083
1084 if (mode == MODE_STANDARD)
1085 {
1086 if (tbytes < filestats.st_size)
1087 status = errno;
1088 else if (lpd_write(fd, "", 1) < 1)
1089 {
1090 _cupsLangPrintError(_("ERROR: Unable to send trailing nul to printer"));
1091 status = errno;
1092 }
1093 else
1094 {
1095 /*
1096 * Read the status byte from the printer; if we can't read the byte
1097 * back now, we should set status to "errno", however at this point
1098 * we know the printer got the whole file and we don't necessarily
1099 * want to requeue it over and over...
1100 */
1101
1102 alarm(timeout);
1103
1104 if (recv(fd, &status, 1, 0) < 1)
1105 {
1106 _cupsLangPrintf(stderr,
1107 _("WARNING: Remote host did not respond with data "
1108 "status byte after %d seconds!\n"), timeout);
1109 status = 0;
1110 }
1111
1112 alarm(0);
1113 }
1114 }
1115 else
1116 status = 0;
1117
1118 if (status != 0)
1119 _cupsLangPrintf(stderr,
1120 _("ERROR: Remote host did not accept data file (%d)\n"),
1121 status);
1122 else
1123 _cupsLangPuts(stderr, _("INFO: Data file sent successfully\n"));
1124 }
1125
1126 if (status == 0 && order == ORDER_DATA_CONTROL)
1127 {
1128 /*
1129 * Check for side-channel requests...
1130 */
1131
1132 backendCheckSideChannel(snmp_fd, &(addr->addr));
1133
1134 /*
1135 * Send control file...
1136 */
1137
1138 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
1139 (int)getpid() % 1000, localhost))
1140 {
1141 httpAddrFreeList(addrlist);
1142 close(fd);
1143
1144 return (CUPS_BACKEND_FAILED);
1145 }
1146
1147 _cupsLangPrintf(stderr, _("INFO: Sending control file (%lu bytes)\n"),
1148 (unsigned long)strlen(control));
1149
1150 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
1151 {
1152 status = errno;
1153 _cupsLangPrintError(_("ERROR: Unable to write control file"));
1154 }
1155 else
1156 {
1157 alarm(timeout);
1158
1159 if (read(fd, &status, 1) < 1)
1160 {
1161 _cupsLangPrintf(stderr,
1162 _("WARNING: Remote host did not respond with control "
1163 "status byte after %d seconds!\n"), timeout);
1164 status = errno;
1165 }
1166
1167 alarm(0);
1168 }
1169
1170 if (status != 0)
1171 _cupsLangPrintf(stderr,
1172 _("ERROR: Remote host did not accept control file "
1173 "(%d)\n"), status);
1174 else
1175 _cupsLangPuts(stderr, _("INFO: Control file sent successfully\n"));
1176 }
1177
1178 /*
1179 * Collect the final supply levels as needed...
1180 */
1181
1182 if (have_supplies)
1183 backendSNMPSupplies(snmp_fd, &(addr->addr), NULL, NULL);
1184
1185 /*
1186 * Close the socket connection and input file...
1187 */
1188
1189 close(fd);
1190
1191 if (status == 0)
1192 {
1193 httpAddrFreeList(addrlist);
1194
1195 return (CUPS_BACKEND_OK);
1196 }
1197
1198 /*
1199 * Waiting for a retry...
1200 */
1201
1202 sleep(30);
1203 }
1204
1205 httpAddrFreeList(addrlist);
1206
1207 /*
1208 * If we get here, then the job has been cancelled...
1209 */
1210
1211 return (CUPS_BACKEND_FAILED);
1212 }
1213
1214
1215 /*
1216 * 'lpd_timeout()' - Handle timeout alarms...
1217 */
1218
1219 static void
1220 lpd_timeout(int sig) /* I - Signal number */
1221 {
1222 (void)sig;
1223
1224 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1225 signal(SIGALRM, lpd_timeout);
1226 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1227 }
1228
1229
1230 /*
1231 * 'lpd_write()' - Write a buffer of data to an LPD server.
1232 */
1233
1234 static int /* O - Number of bytes written or -1 on error */
1235 lpd_write(int lpd_fd, /* I - LPD socket */
1236 char *buffer, /* I - Buffer to write */
1237 int length) /* I - Number of bytes to write */
1238 {
1239 int bytes, /* Number of bytes written */
1240 total; /* Total number of bytes written */
1241
1242
1243 if (abort_job)
1244 return (-1);
1245
1246 total = 0;
1247 while ((bytes = send(lpd_fd, buffer, length - total, 0)) >= 0)
1248 {
1249 total += bytes;
1250 buffer += bytes;
1251
1252 if (total == length)
1253 break;
1254 }
1255
1256 if (bytes < 0)
1257 return (-1);
1258 else
1259 return (length);
1260 }
1261
1262
1263 #ifndef HAVE_RRESVPORT_AF
1264 /*
1265 * 'rresvport_af()' - A simple implementation of rresvport_af().
1266 */
1267
1268 static int /* O - Socket or -1 on error */
1269 rresvport_af(int *port, /* IO - Port number to bind to */
1270 int family) /* I - Address family */
1271 {
1272 http_addr_t addr; /* Socket address */
1273 int fd; /* Socket file descriptor */
1274
1275
1276 /*
1277 * Try to create an IPv4 socket...
1278 */
1279
1280 if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
1281 return (-1);
1282
1283 /*
1284 * Initialize the address buffer...
1285 */
1286
1287 memset(&addr, 0, sizeof(addr));
1288 addr.addr.sa_family = family;
1289
1290 /*
1291 * Try to bind the socket to a reserved port...
1292 */
1293
1294 while (*port > 511)
1295 {
1296 /*
1297 * Set the port number...
1298 */
1299
1300 # ifdef AF_INET6
1301 if (family == AF_INET6)
1302 addr.ipv6.sin6_port = htons(*port);
1303 else
1304 # endif /* AF_INET6 */
1305 addr.ipv4.sin_port = htons(*port);
1306
1307 /*
1308 * Try binding the port to the socket; return if all is OK...
1309 */
1310
1311 if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
1312 return (fd);
1313
1314 /*
1315 * Stop if we have any error other than "address already in use"...
1316 */
1317
1318 if (errno != EADDRINUSE)
1319 {
1320 # ifdef WIN32
1321 closesocket(fd);
1322 # else
1323 close(fd);
1324 # endif /* WIN32 */
1325
1326 return (-1);
1327 }
1328
1329 /*
1330 * Try the next port...
1331 */
1332
1333 (*port)--;
1334 }
1335
1336 /*
1337 * Wasn't able to bind to a reserved port, so close the socket and return
1338 * -1...
1339 */
1340
1341 # ifdef WIN32
1342 closesocket(fd);
1343 # else
1344 close(fd);
1345 # endif /* WIN32 */
1346
1347 return (-1);
1348 }
1349 #endif /* !HAVE_RRESVPORT_AF */
1350
1351
1352 /*
1353 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1354 */
1355
1356 static void
1357 sigterm_handler(int sig) /* I - Signal */
1358 {
1359 (void)sig; /* remove compiler warnings... */
1360
1361 abort_job = 1;
1362 }
1363
1364
1365 /*
1366 * End of "$Id: lpd.c 7740 2008-07-14 23:58:05Z mike $".
1367 */