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