]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/lpd.c
Import CUPS 1.4svn-r7585.
[thirdparty/cups.git] / backend / lpd.c
1 /*
2 * "$Id: lpd.c 6910 2007-09-04 20:34:29Z mike $"
3 *
4 * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-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 filename = tmpfilename;
442 }
443 else if (argc == 6)
444 {
445 /*
446 * Stream from stdin...
447 */
448
449 filename = NULL;
450 fd = 0;
451 }
452 else
453 {
454 filename = argv[6];
455 fd = open(filename, O_RDONLY);
456
457 if (fd == -1)
458 {
459 _cupsLangPrintf(stderr, _("ERROR: Unable to open print file %s: %s\n"),
460 filename, strerror(errno));
461 return (CUPS_BACKEND_FAILED);
462 }
463 }
464
465 /*
466 * Sanitize the document title...
467 */
468
469 strlcpy(title, argv[3], sizeof(title));
470
471 if (sanitize_title)
472 {
473 /*
474 * Sanitize the title string so that we don't cause problems on
475 * the remote end...
476 */
477
478 char *ptr;
479
480 for (ptr = title; *ptr; ptr ++)
481 if (!isalnum(*ptr & 255) && !isspace(*ptr & 255))
482 *ptr = '_';
483 }
484
485 /*
486 * Queue the job...
487 */
488
489 if (argc > 6)
490 {
491 if (manual_copies)
492 {
493 manual_copies = atoi(argv[4]);
494 copies = 1;
495 }
496 else
497 {
498 manual_copies = 1;
499 copies = atoi(argv[4]);
500 }
501
502 status = lpd_queue(hostname, port, resource + 1, fd, mode,
503 username, title, copies,
504 banner, format, order, reserve, manual_copies,
505 timeout, contimeout);
506
507 if (!status)
508 fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
509 }
510 else
511 status = lpd_queue(hostname, port, resource + 1, fd, mode,
512 username, title, 1,
513 banner, format, order, reserve, 1,
514 timeout, contimeout);
515
516 /*
517 * Remove the temporary file if necessary...
518 */
519
520 if (tmpfilename[0])
521 unlink(tmpfilename);
522
523 if (fd)
524 close(fd);
525
526 /*
527 * Return the queue status...
528 */
529
530 return (status);
531 }
532
533
534 /*
535 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
536 */
537
538 static int /* O - Status of command */
539 lpd_command(int fd, /* I - Socket connection to LPD host */
540 int timeout, /* I - Seconds to wait for a response */
541 char *format, /* I - printf()-style format string */
542 ...) /* I - Additional args as necessary */
543 {
544 va_list ap; /* Argument pointer */
545 char buf[1024]; /* Output buffer */
546 int bytes; /* Number of bytes to output */
547 char status; /* Status from command */
548
549
550 /*
551 * Don't try to send commands if the job has been cancelled...
552 */
553
554 if (abort_job)
555 return (-1);
556
557 /*
558 * Format the string...
559 */
560
561 va_start(ap, format);
562 bytes = vsnprintf(buf, sizeof(buf), format, ap);
563 va_end(ap);
564
565 fprintf(stderr, "DEBUG: lpd_command %2.2x %s", buf[0], buf + 1);
566
567 /*
568 * Send the command...
569 */
570
571 fprintf(stderr, "DEBUG: Sending command string (%d bytes)...\n", bytes);
572
573 if (lpd_write(fd, buf, bytes) < bytes)
574 {
575 _cupsLangPrintError(_("ERROR: Unable to send LPD command"));
576 return (-1);
577 }
578
579 /*
580 * Read back the status from the command and return it...
581 */
582
583 fputs("DEBUG: Reading command status...\n", stderr);
584
585 alarm(timeout);
586
587 if (recv(fd, &status, 1, 0) < 1)
588 {
589 _cupsLangPrintf(stderr,
590 _("WARNING: Remote host did not respond with command "
591 "status byte after %d seconds!\n"), timeout);
592 status = errno;
593 }
594
595 alarm(0);
596
597 fprintf(stderr, "DEBUG: lpd_command returning %d\n", status);
598
599 return (status);
600 }
601
602
603 /*
604 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
605 */
606
607 static int /* O - Zero on success, non-zero on failure */
608 lpd_queue(const char *hostname, /* I - Host to connect to */
609 int port, /* I - Port to connect on */
610 const char *printer, /* I - Printer/queue name */
611 int print_fd, /* I - File to print */
612 int mode, /* I - Print mode */
613 const char *user, /* I - Requesting user */
614 const char *title, /* I - Job title */
615 int copies, /* I - Number of copies */
616 int banner, /* I - Print LPD banner? */
617 int format, /* I - Format specifier */
618 int order, /* I - Order of data/control files */
619 int reserve, /* I - Reserve ports? */
620 int manual_copies, /* I - Do copies by hand... */
621 int timeout, /* I - Timeout... */
622 int contimeout) /* I - Connection timeout */
623 {
624 char localhost[255]; /* Local host name */
625 int error; /* Error number */
626 struct stat filestats; /* File statistics */
627 int lport; /* LPD connection local port */
628 int fd; /* LPD socket */
629 char control[10240], /* LPD control 'file' */
630 *cptr; /* Pointer into control file string */
631 char status; /* Status byte from command */
632 char portname[255]; /* Port name */
633 int delay; /* Delay for retries... */
634 char addrname[256]; /* Address name */
635 http_addrlist_t *addrlist, /* Address list */
636 *addr; /* Socket address */
637 int snmp_fd, /* SNMP socket */
638 start_count, /* Page count via SNMP at start */
639 page_count; /* Page count via SNMP */
640 int copy; /* Copies written */
641 time_t start_time; /* Time of first connect */
642 int recoverable; /* Recoverable error shown? */
643 size_t nbytes; /* Number of bytes written */
644 off_t tbytes; /* Total bytes written */
645 char buffer[32768]; /* Output buffer */
646 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
647 struct sigaction action; /* Actions for POSIX signals */
648 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
649
650
651 /*
652 * Setup an alarm handler for timeouts...
653 */
654
655 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
656 sigset(SIGALRM, lpd_timeout);
657 #elif defined(HAVE_SIGACTION)
658 memset(&action, 0, sizeof(action));
659
660 sigemptyset(&action.sa_mask);
661 action.sa_handler = lpd_timeout;
662 sigaction(SIGALRM, &action, NULL);
663 #else
664 signal(SIGALRM, lpd_timeout);
665 #endif /* HAVE_SIGSET */
666
667 /*
668 * Find the printer...
669 */
670
671 sprintf(portname, "%d", port);
672
673 if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
674 {
675 _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"),
676 hostname);
677 return (CUPS_BACKEND_STOP);
678 }
679
680 /*
681 * Remember when we started trying to connect to the printer...
682 */
683
684 recoverable = 0;
685 start_time = time(NULL);
686
687 /*
688 * Loop forever trying to print the file...
689 */
690
691 while (!abort_job)
692 {
693 /*
694 * First try to reserve a port for this connection...
695 */
696
697 fputs("STATE: +connecting-to-device\n", stderr);
698 _cupsLangPrintf(stderr,
699 _("INFO: Attempting to connect to host %s for printer %s\n"),
700 hostname, printer);
701
702 for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist,
703 delay = 5;;
704 addr = addr->next)
705 {
706 /*
707 * Stop if this job has been cancelled...
708 */
709
710 if (abort_job)
711 {
712 httpAddrFreeList(addrlist);
713
714 return (CUPS_BACKEND_FAILED);
715 }
716
717 /*
718 * Choose the next priviledged port...
719 */
720
721 if (!addr)
722 addr = addrlist;
723
724 lport --;
725
726 if (lport < 721 && reserve == RESERVE_RFC1179)
727 lport = 731;
728 else if (lport < 1)
729 lport = 1023;
730
731 #ifdef HAVE_GETEUID
732 if (geteuid() || !reserve)
733 #else
734 if (getuid() || !reserve)
735 #endif /* HAVE_GETEUID */
736 {
737 /*
738 * Just create a regular socket...
739 */
740
741 if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
742 {
743 _cupsLangPrintError(_("ERROR: Unable to create socket"));
744 sleep(1);
745
746 continue;
747 }
748
749 lport = 0;
750 }
751 else
752 {
753 /*
754 * We're running as root and want to comply with RFC 1179. Reserve a
755 * priviledged lport between 721 and 731...
756 */
757
758 if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0)
759 {
760 _cupsLangPrintError(_("ERROR: Unable to reserve port"));
761 sleep(1);
762
763 continue;
764 }
765 }
766
767 /*
768 * Connect to the printer or server...
769 */
770
771 if (abort_job)
772 {
773 httpAddrFreeList(addrlist);
774
775 close(fd);
776
777 return (CUPS_BACKEND_FAILED);
778 }
779
780 if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr))))
781 break;
782
783 error = errno;
784 close(fd);
785 fd = -1;
786
787 if (addr->next)
788 continue;
789
790 if (getenv("CLASS") != NULL)
791 {
792 /*
793 * If the CLASS environment variable is set, the job was submitted
794 * to a class and not to a specific queue. In this case, we want
795 * to abort immediately so that the job can be requeued on the next
796 * available printer in the class.
797 */
798
799 _cupsLangPuts(stderr,
800 _("INFO: Unable to contact printer, queuing on next "
801 "printer in class...\n"));
802
803 httpAddrFreeList(addrlist);
804
805 /*
806 * Sleep 5 seconds to keep the job from requeuing too rapidly...
807 */
808
809 sleep(5);
810
811 return (CUPS_BACKEND_FAILED);
812 }
813
814 if (error == ECONNREFUSED || error == EHOSTDOWN ||
815 error == EHOSTUNREACH)
816 {
817 if (contimeout && (time(NULL) - start_time) > contimeout)
818 {
819 _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n"));
820 return (CUPS_BACKEND_FAILED);
821 }
822
823 recoverable = 1;
824
825 _cupsLangPrintf(stderr,
826 _("WARNING: recoverable: Network host \'%s\' is busy; "
827 "will retry in %d seconds...\n"), hostname, delay);
828
829 sleep(delay);
830
831 if (delay < 30)
832 delay += 5;
833 }
834 else if (error == EADDRINUSE)
835 {
836 /*
837 * Try on another port...
838 */
839
840 sleep(1);
841 }
842 else
843 {
844 recoverable = 1;
845
846 fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno));
847 _cupsLangPuts(stderr,
848 _("ERROR: recoverable: Unable to connect to printer; "
849 "will retry in 30 seconds...\n"));
850 sleep(30);
851 }
852 }
853
854 if (recoverable)
855 {
856 /*
857 * If we've shown a recoverable error make sure the printer proxies
858 * have a chance to see the recovered message. Not pretty but
859 * necessary for now...
860 */
861
862 fputs("INFO: recovered: \n", stderr);
863 sleep(5);
864 }
865
866 fputs("STATE: -connecting-to-device\n", stderr);
867 _cupsLangPrintf(stderr, _("INFO: Connected to %s...\n"), hostname);
868
869 #ifdef AF_INET6
870 if (addr->addr.addr.sa_family == AF_INET6)
871 fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6) (local port %d)...\n",
872 httpAddrString(&addr->addr, addrname, sizeof(addrname)),
873 ntohs(addr->addr.ipv6.sin6_port), lport);
874 else
875 #endif /* AF_INET6 */
876 if (addr->addr.addr.sa_family == AF_INET)
877 fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4) (local port %d)...\n",
878 httpAddrString(&addr->addr, addrname, sizeof(addrname)),
879 ntohs(addr->addr.ipv4.sin_port), lport);
880
881 /*
882 * See if the printer supports SNMP...
883 */
884
885 if ((snmp_fd = _cupsSNMPOpen(addr->addr.addr.sa_family)) >= 0)
886 if (backendSNMPSupplies(snmp_fd, &(addr->addr), &start_count, NULL))
887 {
888 /*
889 * No, close it...
890 */
891
892 _cupsSNMPClose(snmp_fd);
893 snmp_fd = -1;
894 }
895
896 /*
897 * Check for side-channel requests...
898 */
899
900 backendCheckSideChannel(snmp_fd, &(addr->addr));
901
902 /*
903 * Next, open the print file and figure out its size...
904 */
905
906 if (print_fd)
907 {
908 /*
909 * Use the size from the print file...
910 */
911
912 if (fstat(print_fd, &filestats))
913 {
914 httpAddrFreeList(addrlist);
915 close(fd);
916
917 _cupsLangPrintError(_("ERROR: unable to stat print file"));
918 return (CUPS_BACKEND_FAILED);
919 }
920
921 filestats.st_size *= manual_copies;
922 }
923 else
924 {
925 /*
926 * Use a "very large value" for the size so that the printer will
927 * keep printing until we close the connection...
928 */
929
930 #ifdef _LARGEFILE_SOURCE
931 filestats.st_size = (size_t)(999999999999.0);
932 #else
933 filestats.st_size = 2147483647;
934 #endif /* _LARGEFILE_SOURCE */
935 }
936
937 /*
938 * Send a job header to the printer, specifying no banner page and
939 * literal output...
940 */
941
942 if (lpd_command(fd, timeout, "\002%s\n",
943 printer)) /* Receive print job(s) */
944 {
945 httpAddrFreeList(addrlist);
946 close(fd);
947 return (CUPS_BACKEND_FAILED);
948 }
949
950 httpGetHostname(NULL, localhost, sizeof(localhost));
951
952 snprintf(control, sizeof(control),
953 "H%.31s\n" /* RFC 1179, Section 7.2 - host name <= 31 chars */
954 "P%.31s\n" /* RFC 1179, Section 7.2 - user name <= 31 chars */
955 "J%.99s\n", /* RFC 1179, Section 7.2 - job name <= 99 chars */
956 localhost, user, title);
957 cptr = control + strlen(control);
958
959 if (banner)
960 {
961 snprintf(cptr, sizeof(control) - (cptr - control),
962 "C%.31s\n" /* RFC 1179, Section 7.2 - class name <= 31 chars */
963 "L%s\n",
964 localhost, user);
965 cptr += strlen(cptr);
966 }
967
968 while (copies > 0)
969 {
970 snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n",
971 format, (int)getpid() % 1000, localhost);
972 cptr += strlen(cptr);
973 copies --;
974 }
975
976 snprintf(cptr, sizeof(control) - (cptr - control),
977 "UdfA%03d%.15s\n"
978 "N%.131s\n", /* RFC 1179, Section 7.2 - sourcefile name <= 131 chars */
979 (int)getpid() % 1000, localhost, title);
980
981 fprintf(stderr, "DEBUG: Control file is:\n%s", control);
982
983 if (order == ORDER_CONTROL_DATA)
984 {
985 /*
986 * Check for side-channel requests...
987 */
988
989 backendCheckSideChannel(snmp_fd, &(addr->addr));
990
991 /*
992 * Send the control file...
993 */
994
995 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
996 (int)getpid() % 1000, localhost))
997 {
998 httpAddrFreeList(addrlist);
999 close(fd);
1000
1001 return (CUPS_BACKEND_FAILED);
1002 }
1003
1004 _cupsLangPrintf(stderr, _("INFO: Sending control file (%u bytes)\n"),
1005 (unsigned)strlen(control));
1006
1007 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
1008 {
1009 status = errno;
1010 _cupsLangPrintError(_("ERROR: Unable to write control file"));
1011 }
1012 else
1013 {
1014 alarm(timeout);
1015
1016 if (read(fd, &status, 1) < 1)
1017 {
1018 _cupsLangPrintf(stderr,
1019 _("WARNING: Remote host did not respond with control "
1020 "status byte after %d seconds!\n"), timeout);
1021 status = errno;
1022 }
1023
1024 alarm(0);
1025 }
1026
1027 if (status != 0)
1028 _cupsLangPrintf(stderr,
1029 _("ERROR: Remote host did not accept control file "
1030 "(%d)\n"), status);
1031 else
1032 _cupsLangPuts(stderr, _("INFO: Control file sent successfully\n"));
1033 }
1034 else
1035 status = 0;
1036
1037 if (status == 0)
1038 {
1039 /*
1040 * Check for side-channel requests...
1041 */
1042
1043 backendCheckSideChannel(snmp_fd, &(addr->addr));
1044
1045 /*
1046 * Send the print file...
1047 */
1048
1049 if (lpd_command(fd, timeout, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
1050 CUPS_LLCAST filestats.st_size, (int)getpid() % 1000,
1051 localhost))
1052 {
1053 httpAddrFreeList(addrlist);
1054 close(fd);
1055
1056 return (CUPS_BACKEND_FAILED);
1057 }
1058
1059 _cupsLangPrintf(stderr,
1060 #ifdef HAVE_LONG_LONG
1061 _("INFO: Sending data file (%lld bytes)\n"),
1062 #else
1063 _("INFO: Sending data file (%ld bytes)\n"),
1064 #endif /* HAVE_LONG_LONG */
1065 CUPS_LLCAST filestats.st_size);
1066
1067 tbytes = 0;
1068 for (copy = 0; copy < manual_copies; copy ++)
1069 {
1070 lseek(print_fd, 0, SEEK_SET);
1071
1072 while ((nbytes = read(print_fd, buffer, sizeof(buffer))) > 0)
1073 {
1074 _cupsLangPrintf(stderr,
1075 _("INFO: Spooling LPR job, %.0f%% complete...\n"),
1076 100.0 * tbytes / filestats.st_size);
1077
1078 if (lpd_write(fd, buffer, nbytes) < nbytes)
1079 {
1080 _cupsLangPrintError(_("ERROR: Unable to send print file to printer"));
1081 break;
1082 }
1083 else
1084 tbytes += nbytes;
1085 }
1086 }
1087
1088 if (mode == MODE_STANDARD)
1089 {
1090 if (tbytes < filestats.st_size)
1091 status = errno;
1092 else if (lpd_write(fd, "", 1) < 1)
1093 {
1094 _cupsLangPrintError(_("ERROR: Unable to send trailing nul to printer"));
1095 status = errno;
1096 }
1097 else
1098 {
1099 /*
1100 * Read the status byte from the printer; if we can't read the byte
1101 * back now, we should set status to "errno", however at this point
1102 * we know the printer got the whole file and we don't necessarily
1103 * want to requeue it over and over...
1104 */
1105
1106 alarm(timeout);
1107
1108 if (recv(fd, &status, 1, 0) < 1)
1109 {
1110 _cupsLangPrintf(stderr,
1111 _("WARNING: Remote host did not respond with data "
1112 "status byte after %d seconds!\n"), timeout);
1113 status = 0;
1114 }
1115
1116 alarm(0);
1117 }
1118 }
1119 else
1120 status = 0;
1121
1122 if (status != 0)
1123 _cupsLangPrintf(stderr,
1124 _("ERROR: Remote host did not accept data file (%d)\n"),
1125 status);
1126 else
1127 _cupsLangPuts(stderr, _("INFO: Data file sent successfully\n"));
1128 }
1129
1130 if (status == 0 && order == ORDER_DATA_CONTROL)
1131 {
1132 /*
1133 * Check for side-channel requests...
1134 */
1135
1136 backendCheckSideChannel(snmp_fd, &(addr->addr));
1137
1138 /*
1139 * Send control file...
1140 */
1141
1142 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
1143 (int)getpid() % 1000, localhost))
1144 {
1145 httpAddrFreeList(addrlist);
1146 close(fd);
1147
1148 return (CUPS_BACKEND_FAILED);
1149 }
1150
1151 _cupsLangPrintf(stderr, _("INFO: Sending control file (%lu bytes)\n"),
1152 (unsigned long)strlen(control));
1153
1154 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
1155 {
1156 status = errno;
1157 _cupsLangPrintError(_("ERROR: Unable to write control file"));
1158 }
1159 else
1160 {
1161 alarm(timeout);
1162
1163 if (read(fd, &status, 1) < 1)
1164 {
1165 _cupsLangPrintf(stderr,
1166 _("WARNING: Remote host did not respond with control "
1167 "status byte after %d seconds!\n"), timeout);
1168 status = errno;
1169 }
1170
1171 alarm(0);
1172 }
1173
1174 if (status != 0)
1175 _cupsLangPrintf(stderr,
1176 _("ERROR: Remote host did not accept control file "
1177 "(%d)\n"), status);
1178 else
1179 _cupsLangPuts(stderr, _("INFO: Control file sent successfully\n"));
1180 }
1181
1182 /*
1183 * Collect the final page count as needed...
1184 */
1185
1186 if (snmp_fd >= 0)
1187 {
1188 int printer_state; /* State of printer */
1189
1190
1191 while (!backendSNMPSupplies(snmp_fd, &(addr->addr), &page_count,
1192 &printer_state) &&
1193 printer_state != CUPS_TC_idle)
1194 sleep(3);
1195
1196 if (page_count > start_count)
1197 fprintf(stderr, "PAGE: total %d\n", page_count - start_count);
1198 }
1199
1200 /*
1201 * Close the socket connection and input file...
1202 */
1203
1204 close(fd);
1205
1206 if (status == 0)
1207 {
1208 httpAddrFreeList(addrlist);
1209
1210 return (CUPS_BACKEND_OK);
1211 }
1212
1213 /*
1214 * Waiting for a retry...
1215 */
1216
1217 sleep(30);
1218 }
1219
1220 httpAddrFreeList(addrlist);
1221
1222 /*
1223 * If we get here, then the job has been cancelled...
1224 */
1225
1226 return (CUPS_BACKEND_FAILED);
1227 }
1228
1229
1230 /*
1231 * 'lpd_timeout()' - Handle timeout alarms...
1232 */
1233
1234 static void
1235 lpd_timeout(int sig) /* I - Signal number */
1236 {
1237 (void)sig;
1238
1239 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1240 signal(SIGALRM, lpd_timeout);
1241 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1242 }
1243
1244
1245 /*
1246 * 'lpd_write()' - Write a buffer of data to an LPD server.
1247 */
1248
1249 static int /* O - Number of bytes written or -1 on error */
1250 lpd_write(int lpd_fd, /* I - LPD socket */
1251 char *buffer, /* I - Buffer to write */
1252 int length) /* I - Number of bytes to write */
1253 {
1254 int bytes, /* Number of bytes written */
1255 total; /* Total number of bytes written */
1256
1257
1258 if (abort_job)
1259 return (-1);
1260
1261 total = 0;
1262 while ((bytes = send(lpd_fd, buffer, length - total, 0)) >= 0)
1263 {
1264 total += bytes;
1265 buffer += bytes;
1266
1267 if (total == length)
1268 break;
1269 }
1270
1271 if (bytes < 0)
1272 return (-1);
1273 else
1274 return (length);
1275 }
1276
1277
1278 #ifndef HAVE_RRESVPORT_AF
1279 /*
1280 * 'rresvport_af()' - A simple implementation of rresvport_af().
1281 */
1282
1283 static int /* O - Socket or -1 on error */
1284 rresvport_af(int *port, /* IO - Port number to bind to */
1285 int family) /* I - Address family */
1286 {
1287 http_addr_t addr; /* Socket address */
1288 int fd; /* Socket file descriptor */
1289
1290
1291 /*
1292 * Try to create an IPv4 socket...
1293 */
1294
1295 if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
1296 return (-1);
1297
1298 /*
1299 * Initialize the address buffer...
1300 */
1301
1302 memset(&addr, 0, sizeof(addr));
1303 addr.addr.sa_family = family;
1304
1305 /*
1306 * Try to bind the socket to a reserved port...
1307 */
1308
1309 while (*port > 511)
1310 {
1311 /*
1312 * Set the port number...
1313 */
1314
1315 # ifdef AF_INET6
1316 if (family == AF_INET6)
1317 addr.ipv6.sin6_port = htons(*port);
1318 else
1319 # endif /* AF_INET6 */
1320 addr.ipv4.sin_port = htons(*port);
1321
1322 /*
1323 * Try binding the port to the socket; return if all is OK...
1324 */
1325
1326 if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
1327 return (fd);
1328
1329 /*
1330 * Stop if we have any error other than "address already in use"...
1331 */
1332
1333 if (errno != EADDRINUSE)
1334 {
1335 # ifdef WIN32
1336 closesocket(fd);
1337 # else
1338 close(fd);
1339 # endif /* WIN32 */
1340
1341 return (-1);
1342 }
1343
1344 /*
1345 * Try the next port...
1346 */
1347
1348 (*port)--;
1349 }
1350
1351 /*
1352 * Wasn't able to bind to a reserved port, so close the socket and return
1353 * -1...
1354 */
1355
1356 # ifdef WIN32
1357 closesocket(fd);
1358 # else
1359 close(fd);
1360 # endif /* WIN32 */
1361
1362 return (-1);
1363 }
1364 #endif /* !HAVE_RRESVPORT_AF */
1365
1366
1367 /*
1368 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1369 */
1370
1371 static void
1372 sigterm_handler(int sig) /* I - Signal */
1373 {
1374 (void)sig; /* remove compiler warnings... */
1375
1376 abort_job = 1;
1377 }
1378
1379
1380 /*
1381 * End of "$Id: lpd.c 6910 2007-09-04 20:34:29Z mike $".
1382 */