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