]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/lpd.c
New IPv6-capable address list stuff for STR #1313. Basically, this
[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 1997-2005 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * main() - Send a file to the printer or server.
29 * lpd_command() - Send an LPR command sequence and wait for a reply.
30 * lpd_queue() - Queue a file using the Line Printer Daemon protocol.
31 * lpd_timeout() - Handle timeout alarms...
32 * lpd_write() - Write a buffer of data to an LPD server.
33 * rresvport_af() - A simple implementation of rresvport_af().
34 * sigterm_handler() - Handle 'terminate' signals that stop the backend.
35 */
36
37 /*
38 * Include necessary headers.
39 */
40
41 #include <cups/backend.h>
42 #include <cups/cups.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdarg.h>
46 #include <ctype.h>
47 #include <cups/http-private.h>
48 #include <cups/string.h>
49 #include <errno.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <signal.h>
53
54 #ifdef WIN32
55 # include <winsock.h>
56 #else
57 # include <sys/socket.h>
58 # include <netinet/in.h>
59 # include <arpa/inet.h>
60 # include <netdb.h>
61 #endif /* WIN32 */
62
63
64 /*
65 * Globals...
66 */
67
68 static char tmpfilename[1024] = ""; /* Temporary spool file name */
69 static int abort_job = 0; /* Non-zero if we get SIGTERM */
70
71
72 /*
73 * The order for control and data files in LPD requests...
74 */
75
76 #define ORDER_CONTROL_DATA 0 /* Control file first, then data */
77 #define ORDER_DATA_CONTROL 1 /* Data file first, then control */
78
79
80 /*
81 * What to reserve...
82 */
83
84 #define RESERVE_NONE 0 /* Don't reserve a priviledged port */
85 #define RESERVE_RFC1179 1 /* Reserve port 721-731 */
86 #define RESERVE_ANY 2 /* Reserve port 1-1023 */
87
88
89 /*
90 * Local functions...
91 */
92
93 static int lpd_command(int lpd_fd, int timeout, char *format, ...);
94 static int lpd_queue(const char *hostname, int port, const char *printer,
95 const char *filename,
96 const char *user, const char *title, int copies,
97 int banner, int format, int order, int reserve,
98 int manual_copies, int timeout);
99 static void lpd_timeout(int sig);
100 static int lpd_write(int lpd_fd, char *buffer, int length);
101 #ifndef HAVE_RRESVPORT_AF
102 extern int rresvport_af(int *port, int family);
103 #endif /* !HAVE_RRESVPORT_AF */
104 static void sigterm_handler(int sig);
105
106
107 /*
108 * 'main()' - Send a file to the printer or server.
109 *
110 * Usage:
111 *
112 * printer-uri job-id user title copies options [file]
113 */
114
115 int /* O - Exit status */
116 main(int argc, /* I - Number of command-line arguments (6 or 7) */
117 char *argv[]) /* I - Command-line arguments */
118 {
119 char method[255], /* Method in URI */
120 hostname[1024], /* Hostname */
121 username[255], /* Username info */
122 resource[1024], /* Resource info (printer name) */
123 *options, /* Pointer to options */
124 name[255], /* Name of option */
125 value[255], /* Value of option */
126 *ptr, /* Pointer into name or value */
127 *filename, /* File to print */
128 title[256]; /* Title string */
129 int port; /* Port number */
130 int status; /* Status of LPD job */
131 int banner; /* Print banner page? */
132 int format; /* Print format */
133 int order; /* Order of control/data files */
134 int reserve; /* Reserve priviledged port? */
135 int sanitize_title; /* Sanitize title string? */
136 int manual_copies, /* Do manual copies? */
137 timeout, /* Timeout */
138 copies; /* Number of copies */
139 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
140 struct sigaction action; /* Actions for POSIX signals */
141 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
142
143
144 /*
145 * Make sure status messages are not buffered...
146 */
147
148 setbuf(stderr, NULL);
149
150 /*
151 * Ignore SIGPIPE and catch SIGTERM signals...
152 */
153
154 #ifdef HAVE_SIGSET
155 sigset(SIGPIPE, SIG_IGN);
156 sigset(SIGTERM, sigterm_handler);
157 #elif defined(HAVE_SIGACTION)
158 memset(&action, 0, sizeof(action));
159 action.sa_handler = SIG_IGN;
160 sigaction(SIGPIPE, &action, NULL);
161
162 sigemptyset(&action.sa_mask);
163 sigaddset(&action.sa_mask, SIGTERM);
164 action.sa_handler = sigterm_handler;
165 sigaction(SIGTERM, &action, NULL);
166 #else
167 signal(SIGPIPE, SIG_IGN);
168 signal(SIGTERM, sigterm_handler);
169 #endif /* HAVE_SIGSET */
170
171 /*
172 * Check command-line...
173 */
174
175 if (argc == 1)
176 {
177 puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\"");
178 return (CUPS_BACKEND_OK);
179 }
180 else if (argc < 6 || argc > 7)
181 {
182 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
183 argv[0]);
184 return (CUPS_BACKEND_FAILED);
185 }
186
187 /*
188 * If we have 7 arguments, print the file named on the command-line.
189 * Otherwise, copy stdin to a temporary file and print the temporary
190 * file.
191 */
192
193 if (argc == 6)
194 {
195 /*
196 * Copy stdin to a temporary file...
197 */
198
199 int fd; /* Temporary file */
200 char buffer[8192]; /* Buffer for copying */
201 int bytes; /* Number of bytes read */
202
203
204 if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0)
205 {
206 perror("ERROR: unable to create temporary file");
207 return (CUPS_BACKEND_FAILED);
208 }
209
210 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
211 if (write(fd, buffer, bytes) < bytes)
212 {
213 perror("ERROR: unable to write to temporary file");
214 close(fd);
215 unlink(tmpfilename);
216 return (CUPS_BACKEND_FAILED);
217 }
218
219 close(fd);
220 filename = tmpfilename;
221 }
222 else
223 filename = argv[6];
224
225 /*
226 * Extract the hostname and printer name from the URI...
227 */
228
229 httpSeparate(argv[0], method, username, hostname, &port, resource);
230
231 if (!username[0])
232 {
233 /*
234 * If no username is in the device URI, then use the print job user...
235 */
236
237 strlcpy(username, argv[2], sizeof(username));
238 }
239
240 /*
241 * See if there are any options...
242 */
243
244 banner = 0;
245 format = 'l';
246 order = ORDER_CONTROL_DATA;
247 reserve = RESERVE_ANY;
248 manual_copies = 1;
249 timeout = 300;
250 sanitize_title = 1;
251
252 #if defined(__APPLE__)
253 /* We want to pass utf-8 characters, not re-map them (3071945) */
254 sanitize_title= 0;
255 #endif
256
257 if ((options = strchr(resource, '?')) != NULL)
258 {
259 /*
260 * Yup, terminate the device name string and move to the first
261 * character of the options...
262 */
263
264 *options++ = '\0';
265
266 /*
267 * Parse options...
268 */
269
270 while (*options)
271 {
272 /*
273 * Get the name...
274 */
275
276 for (ptr = name; *options && *options != '=';)
277 if (ptr < (name + sizeof(name) - 1))
278 *ptr++ = *options++;
279 *ptr = '\0';
280
281 if (*options == '=')
282 {
283 /*
284 * Get the value...
285 */
286
287 options ++;
288
289 for (ptr = value; *options && *options != '+' && *options != '&';)
290 if (ptr < (value + sizeof(value) - 1))
291 *ptr++ = *options++;
292 *ptr = '\0';
293
294 if (*options == '+')
295 options ++;
296 }
297 else
298 value[0] = '\0';
299
300 /*
301 * Process the option...
302 */
303
304 if (strcasecmp(name, "banner") == 0)
305 {
306 /*
307 * Set the banner...
308 */
309
310 banner = !value[0] ||
311 strcasecmp(value, "on") == 0 ||
312 strcasecmp(value, "yes") == 0 ||
313 strcasecmp(value, "true") == 0;
314 }
315 else if (strcasecmp(name, "format") == 0 && value[0])
316 {
317 /*
318 * Set output format...
319 */
320
321 if (strchr("cdfglnoprtv", value[0]) != NULL)
322 format = value[0];
323 else
324 fprintf(stderr, "ERROR: Unknown format character \"%c\"\n", value[0]);
325 }
326 else if (strcasecmp(name, "order") == 0 && value[0])
327 {
328 /*
329 * Set control/data order...
330 */
331
332 if (strcasecmp(value, "control,data") == 0)
333 order = ORDER_CONTROL_DATA;
334 else if (strcasecmp(value, "data,control") == 0)
335 order = ORDER_DATA_CONTROL;
336 else
337 fprintf(stderr, "ERROR: Unknown file order \"%s\"\n", value);
338 }
339 else if (strcasecmp(name, "reserve") == 0)
340 {
341 /*
342 * Set port reservation mode...
343 */
344
345 if (!value[0] ||
346 !strcasecmp(value, "on") ||
347 !strcasecmp(value, "yes") ||
348 !strcasecmp(value, "true") ||
349 !strcasecmp(value, "rfc1179"))
350 reserve = RESERVE_RFC1179;
351 else if (!strcasecmp(value, "any"))
352 reserve = RESERVE_ANY;
353 else
354 reserve = RESERVE_NONE;
355 }
356 else if (strcasecmp(name, "manual_copies") == 0)
357 {
358 /*
359 * Set manual copies...
360 */
361
362 manual_copies = !value[0] ||
363 strcasecmp(value, "on") == 0 ||
364 strcasecmp(value, "yes") == 0 ||
365 strcasecmp(value, "true") == 0;
366 }
367 else if (strcasecmp(name, "sanitize_title") == 0)
368 {
369 /*
370 * Set sanitize title...
371 */
372
373 sanitize_title = !value[0] ||
374 strcasecmp(value, "on") == 0 ||
375 strcasecmp(value, "yes") == 0 ||
376 strcasecmp(value, "true") == 0;
377 }
378 else if (strcasecmp(name, "timeout") == 0)
379 {
380 /*
381 * Set the timeout...
382 */
383
384 if (atoi(value) > 0)
385 timeout = atoi(value);
386 }
387 }
388 }
389
390 /*
391 * Sanitize the document title...
392 */
393
394 strlcpy(title, argv[3], sizeof(title));
395
396 if (sanitize_title)
397 {
398 /*
399 * Sanitize the title string so that we don't cause problems on
400 * the remote end...
401 */
402
403 for (ptr = title; *ptr; ptr ++)
404 if (!isalnum(*ptr & 255) && !isspace(*ptr & 255))
405 *ptr = '_';
406 }
407
408 /*
409 * Queue the job...
410 */
411
412 if (argc > 6)
413 {
414 if (manual_copies)
415 {
416 manual_copies = atoi(argv[4]);
417 copies = 1;
418 }
419 else
420 {
421 manual_copies = 1;
422 copies = atoi(argv[4]);
423 }
424
425 status = lpd_queue(hostname, port, resource + 1, filename,
426 username, title, copies,
427 banner, format, order, reserve, manual_copies, timeout);
428
429 if (!status)
430 fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
431 }
432 else
433 status = lpd_queue(hostname, port, resource + 1, filename,
434 username, title, 1,
435 banner, format, order, reserve, 1, timeout);
436
437 /*
438 * Remove the temporary file if necessary...
439 */
440
441 if (tmpfilename[0])
442 unlink(tmpfilename);
443
444 /*
445 * Return the queue status...
446 */
447
448 return (status);
449 }
450
451
452 /*
453 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
454 */
455
456 static int /* O - Status of command */
457 lpd_command(int fd, /* I - Socket connection to LPD host */
458 int timeout, /* I - Seconds to wait for a response */
459 char *format, /* I - printf()-style format string */
460 ...) /* I - Additional args as necessary */
461 {
462 va_list ap; /* Argument pointer */
463 char buf[1024]; /* Output buffer */
464 int bytes; /* Number of bytes to output */
465 char status; /* Status from command */
466
467
468 /*
469 * Don't try to send commands if the job has been cancelled...
470 */
471
472 if (abort_job)
473 return (-1);
474
475 /*
476 * Format the string...
477 */
478
479 va_start(ap, format);
480 bytes = vsnprintf(buf, sizeof(buf), format, ap);
481 va_end(ap);
482
483 fprintf(stderr, "DEBUG: lpd_command %2.2x %s", buf[0], buf + 1);
484
485 /*
486 * Send the command...
487 */
488
489 fprintf(stderr, "DEBUG: Sending command string (%d bytes)...\n", bytes);
490
491 if (lpd_write(fd, buf, bytes) < bytes)
492 {
493 perror("ERROR: Unable to send LPD command");
494 return (-1);
495 }
496
497 /*
498 * Read back the status from the command and return it...
499 */
500
501 fprintf(stderr, "DEBUG: Reading command status...\n");
502
503 alarm(timeout);
504
505 if (recv(fd, &status, 1, 0) < 1)
506 {
507 fprintf(stderr, "WARNING: Remote host did not respond with command "
508 "status byte after %d seconds!\n", timeout);
509 status = errno;
510 }
511
512 alarm(0);
513
514 fprintf(stderr, "DEBUG: lpd_command returning %d\n", status);
515
516 return (status);
517 }
518
519
520 /*
521 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
522 */
523
524 static int /* O - Zero on success, non-zero on failure */
525 lpd_queue(const char *hostname, /* I - Host to connect to */
526 int port, /* I - Port to connect on */
527 const char *printer, /* I - Printer/queue name */
528 const char *filename, /* I - File to print */
529 const char *user, /* I - Requesting user */
530 const char *title, /* I - Job title */
531 int copies, /* I - Number of copies */
532 int banner, /* I - Print LPD banner? */
533 int format, /* I - Format specifier */
534 int order, /* I - Order of data/control files */
535 int reserve, /* I - Reserve ports? */
536 int manual_copies, /* I - Do copies by hand... */
537 int timeout) /* I - Timeout... */
538 {
539 FILE *fp; /* Job file */
540 char localhost[255]; /* Local host name */
541 int error; /* Error number */
542 struct stat filestats; /* File statistics */
543 int lport; /* LPD connection local port */
544 int fd; /* LPD socket */
545 char control[10240], /* LPD control 'file' */
546 *cptr; /* Pointer into control file string */
547 char status; /* Status byte from command */
548 char portname[255]; /* Port name */
549 http_addrlist_t *addrlist, /* Address list */
550 *addr; /* Socket address */
551 int copy; /* Copies written */
552 size_t nbytes; /* Number of bytes written */
553 off_t tbytes; /* Total bytes written */
554 char buffer[65536]; /* Output buffer */
555 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
556 struct sigaction action; /* Actions for POSIX signals */
557 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
558
559
560 /*
561 * Setup an alarm handler for timeouts...
562 */
563
564 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
565 sigset(SIGALRM, lpd_timeout);
566 #elif defined(HAVE_SIGACTION)
567 memset(&action, 0, sizeof(action));
568
569 sigemptyset(&action.sa_mask);
570 action.sa_handler = lpd_timeout;
571 sigaction(SIGALRM, &action, NULL);
572 #else
573 signal(SIGALRM, lpd_timeout);
574 #endif /* HAVE_SIGSET */
575
576 /*
577 * Find the printer...
578 */
579
580 sprintf(portname, "%d", port);
581
582 if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
583 {
584 fprintf(stderr, "ERROR: Unable to locate printer \'%s\'!\n",
585 hostname);
586 return (CUPS_BACKEND_STOP);
587 }
588
589 /*
590 * Loop forever trying to print the file...
591 */
592
593 while (!abort_job)
594 {
595 /*
596 * First try to reserve a port for this connection...
597 */
598
599 fprintf(stderr, "INFO: Attempting to connect to host %s for printer %s\n",
600 hostname, printer);
601
602 for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist;;
603 addr = addr->next)
604 {
605 /*
606 * Stop if this job has been cancelled...
607 */
608
609 if (abort_job)
610 {
611 httpAddrFreeList(addrlist);
612
613 return (CUPS_BACKEND_FAILED);
614 }
615
616 /*
617 * Choose the next priviledged port...
618 */
619
620 if (!addr)
621 addr = addrlist;
622
623 lport --;
624
625 if (lport < 721 && reserve == RESERVE_RFC1179)
626 lport = 731;
627 else if (lport < 1)
628 lport = 1023;
629
630 #ifdef HAVE_GETEUID
631 if (geteuid() || !reserve)
632 #else
633 if (getuid() || !reserve)
634 #endif /* HAVE_GETEUID */
635 {
636 /*
637 * Just create a regular socket...
638 */
639
640 if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
641 {
642 perror("ERROR: Unable to create socket");
643 sleep(1);
644
645 continue;
646 }
647
648 lport = 0;
649 }
650 else
651 {
652 /*
653 * We're running as root and want to comply with RFC 1179. Reserve a
654 * priviledged lport between 721 and 731...
655 */
656
657 if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0)
658 {
659 perror("ERROR: Unable to reserve port");
660 sleep(1);
661
662 continue;
663 }
664 }
665
666 /*
667 * Connect to the printer or server...
668 */
669
670 if (abort_job)
671 {
672 httpAddrFreeList(addrlist);
673
674 close(fd);
675
676 return (CUPS_BACKEND_FAILED);
677 }
678
679 if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr))))
680 break;
681
682 error = errno;
683 close(fd);
684 fd = -1;
685
686 if (addr->next)
687 continue;
688
689 if (getenv("CLASS") != NULL)
690 {
691 /*
692 * If the CLASS environment variable is set, the job was submitted
693 * to a class and not to a specific queue. In this case, we want
694 * to abort immediately so that the job can be requeued on the next
695 * available printer in the class.
696 */
697
698 fprintf(stderr, "INFO: Unable to connect to %s, queuing on next printer in class...\n",
699 hostname);
700
701 httpAddrFreeList(addrlist);
702
703 /*
704 * Sleep 5 seconds to keep the job from requeuing too rapidly...
705 */
706
707 sleep(5);
708
709 return (CUPS_BACKEND_FAILED);
710 }
711
712 if (error == ECONNREFUSED || error == EHOSTDOWN ||
713 error == EHOSTUNREACH)
714 {
715 fprintf(stderr, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n",
716 hostname);
717 sleep(30);
718 }
719 else if (error == EADDRINUSE)
720 {
721 /*
722 * Try on another port...
723 */
724
725 sleep(1);
726 }
727 else
728 {
729 perror("ERROR: Unable to connect to printer; will retry in 30 seconds...");
730 sleep(30);
731 }
732 }
733
734 fprintf(stderr, "INFO: Connected to %s...\n", hostname);
735 fprintf(stderr, "DEBUG: Connected on ports %d (local %d)...\n", port,
736 lport);
737
738 /*
739 * Next, open the print file and figure out its size...
740 */
741
742 if (stat(filename, &filestats))
743 {
744 httpAddrFreeList(addrlist);
745 close(fd);
746
747 perror("ERROR: unable to stat print file");
748 return (CUPS_BACKEND_FAILED);
749 }
750
751 filestats.st_size *= manual_copies;
752
753 if ((fp = fopen(filename, "rb")) == NULL)
754 {
755 httpAddrFreeList(addrlist);
756 close(fd);
757
758 perror("ERROR: unable to open print file for reading");
759 return (CUPS_BACKEND_FAILED);
760 }
761
762 /*
763 * Send a job header to the printer, specifying no banner page and
764 * literal output...
765 */
766
767 if (lpd_command(fd, timeout, "\002%s\n",
768 printer)) /* Receive print job(s) */
769 {
770 httpAddrFreeList(addrlist);
771 close(fd);
772 return (CUPS_BACKEND_FAILED);
773 }
774
775 httpGetHostname(localhost, sizeof(localhost));
776 localhost[31] = '\0'; /* RFC 1179, Section 7.2 - host name < 32 chars */
777
778 snprintf(control, sizeof(control), "H%s\nP%s\nJ%s\n", localhost, user,
779 title);
780 cptr = control + strlen(control);
781
782 if (banner)
783 {
784 snprintf(cptr, sizeof(control) - (cptr - control), "C%s\nL%s\n",
785 localhost, user);
786 cptr += strlen(cptr);
787 }
788
789 while (copies > 0)
790 {
791 snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n", format,
792 getpid() % 1000, localhost);
793 cptr += strlen(cptr);
794 copies --;
795 }
796
797 snprintf(cptr, sizeof(control) - (cptr - control),
798 "UdfA%03d%.15s\nN%s\n",
799 getpid() % 1000, localhost, title);
800
801 fprintf(stderr, "DEBUG: Control file is:\n%s", control);
802
803 if (order == ORDER_CONTROL_DATA)
804 {
805 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
806 getpid() % 1000, localhost))
807 {
808 httpAddrFreeList(addrlist);
809 close(fd);
810
811 return (CUPS_BACKEND_FAILED);
812 }
813
814 fprintf(stderr, "INFO: Sending control file (%u bytes)\n",
815 (unsigned)strlen(control));
816
817 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
818 {
819 status = errno;
820 perror("ERROR: Unable to write control file");
821 }
822 else
823 {
824 alarm(timeout);
825
826 if (read(fd, &status, 1) < 1)
827 {
828 fprintf(stderr, "WARNING: Remote host did not respond with control "
829 "status byte after %d seconds!\n", timeout);
830 status = errno;
831 }
832
833 alarm(0);
834 }
835
836 if (status != 0)
837 fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n",
838 status);
839 else
840 fputs("INFO: Control file sent successfully\n", stderr);
841 }
842 else
843 status = 0;
844
845 if (status == 0)
846 {
847 /*
848 * Send the print file...
849 */
850
851 if (lpd_command(fd, timeout, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
852 CUPS_LLCAST filestats.st_size, getpid() % 1000,
853 localhost))
854 {
855 httpAddrFreeList(addrlist);
856 close(fd);
857
858 return (CUPS_BACKEND_FAILED);
859 }
860
861 fprintf(stderr, "INFO: Sending data file (" CUPS_LLFMT " bytes)\n",
862 CUPS_LLCAST filestats.st_size);
863
864 tbytes = 0;
865 for (copy = 0; copy < manual_copies; copy ++)
866 {
867 rewind(fp);
868
869 while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
870 {
871 fprintf(stderr, "INFO: Spooling LPR job, %.0f%% complete...\n",
872 100.0 * tbytes / filestats.st_size);
873
874 if (lpd_write(fd, buffer, nbytes) < nbytes)
875 {
876 perror("ERROR: Unable to send print file to printer");
877 break;
878 }
879 else
880 tbytes += nbytes;
881 }
882 }
883
884 if (tbytes < filestats.st_size)
885 status = errno;
886 else if (lpd_write(fd, "", 1) < 1)
887 {
888 perror("ERROR: Unable to send trailing nul to printer");
889 status = errno;
890 }
891 else
892 {
893 /*
894 * Read the status byte from the printer; if we can't read the byte
895 * back now, we should set status to "errno", however at this point
896 * we know the printer got the whole file and we don't necessarily
897 * want to requeue it over and over...
898 */
899
900 alarm(timeout);
901
902 if (recv(fd, &status, 1, 0) < 1)
903 {
904 fprintf(stderr, "WARNING: Remote host did not respond with data "
905 "status byte after %d seconds!\n", timeout);
906 status = 0;
907 }
908
909 alarm(0);
910 }
911
912 if (status != 0)
913 fprintf(stderr, "ERROR: Remote host did not accept data file (%d)\n",
914 status);
915 else
916 fputs("INFO: Data file sent successfully\n", stderr);
917 }
918
919 if (status == 0 && order == ORDER_DATA_CONTROL)
920 {
921 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
922 getpid() % 1000, localhost))
923 {
924 httpAddrFreeList(addrlist);
925 close(fd);
926
927 return (CUPS_BACKEND_FAILED);
928 }
929
930 fprintf(stderr, "INFO: Sending control file (%lu bytes)\n",
931 (unsigned long)strlen(control));
932
933 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
934 {
935 status = errno;
936 perror("ERROR: Unable to write control file");
937 }
938 else
939 {
940 alarm(timeout);
941
942 if (read(fd, &status, 1) < 1)
943 {
944 fprintf(stderr, "WARNING: Remote host did not respond with control "
945 "status byte after %d seconds!\n", timeout);
946 status = errno;
947 }
948
949 alarm(0);
950 }
951
952 if (status != 0)
953 fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n",
954 status);
955 else
956 fputs("INFO: Control file sent successfully\n", stderr);
957 }
958
959 /*
960 * Close the socket connection and input file...
961 */
962
963 close(fd);
964 fclose(fp);
965
966 if (status == 0)
967 {
968 httpAddrFreeList(addrlist);
969
970 return (CUPS_BACKEND_OK);
971 }
972
973 /*
974 * Waiting for a retry...
975 */
976
977 sleep(30);
978 }
979
980 httpAddrFreeList(addrlist);
981
982 /*
983 * If we get here, then the job has been cancelled...
984 */
985
986 return (CUPS_BACKEND_FAILED);
987 }
988
989
990 /*
991 * 'lpd_timeout()' - Handle timeout alarms...
992 */
993
994 static void
995 lpd_timeout(int sig) /* I - Signal number */
996 {
997 (void)sig;
998
999 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1000 signal(SIGALRM, lpd_timeout);
1001 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1002 }
1003
1004
1005 /*
1006 * 'lpd_write()' - Write a buffer of data to an LPD server.
1007 */
1008
1009 static int /* O - Number of bytes written or -1 on error */
1010 lpd_write(int lpd_fd, /* I - LPD socket */
1011 char *buffer, /* I - Buffer to write */
1012 int length) /* I - Number of bytes to write */
1013 {
1014 int bytes, /* Number of bytes written */
1015 total; /* Total number of bytes written */
1016
1017
1018 if (abort_job)
1019 return (-1);
1020
1021 total = 0;
1022 while ((bytes = send(lpd_fd, buffer, length - total, 0)) >= 0)
1023 {
1024 total += bytes;
1025 buffer += bytes;
1026
1027 if (total == length)
1028 break;
1029 }
1030
1031 if (bytes < 0)
1032 return (-1);
1033 else
1034 return (length);
1035 }
1036
1037
1038 #ifndef HAVE_RRESVPORT_AF
1039 /*
1040 * 'rresvport_af()' - A simple implementation of rresvport_af().
1041 */
1042
1043 int /* O - Socket or -1 on error */
1044 rresvport_af(int *port, /* IO - Port number to bind to */
1045 int family) /* I - Address family */
1046 {
1047 http_addr_t addr; /* Socket address */
1048 int fd; /* Socket file descriptor */
1049
1050
1051 /*
1052 * Try to create an IPv4 socket...
1053 */
1054
1055 if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
1056 return (-1);
1057
1058 /*
1059 * Initialize the address buffer...
1060 */
1061
1062 memset(&addr, 0, sizeof(addr));
1063 addr.addr.sa_family = family;
1064
1065 /*
1066 * Try to bind the socket to a reserved port...
1067 */
1068
1069 while (*port > 511)
1070 {
1071 /*
1072 * Set the port number...
1073 */
1074
1075 # ifdef AF_INET6
1076 if (family == AF_INET6
1077 addr.ipv6.sin6_port = htons(*port);
1078 else
1079 # endif /* AF_INET6 */
1080 addr.ipv4.sin_port = htons(*port);
1081
1082 /*
1083 * Try binding the port to the socket; return if all is OK...
1084 */
1085
1086 if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
1087 return (fd);
1088
1089 /*
1090 * Stop if we have any error other than "address already in use"...
1091 */
1092
1093 if (errno != EADDRINUSE)
1094 {
1095 # ifdef WIN32
1096 closesocket(fd);
1097 # else
1098 close(fd);
1099 # endif /* WIN32 */
1100
1101 return (-1);
1102 }
1103
1104 /*
1105 * Try the next port...
1106 */
1107
1108 (*port)--;
1109 }
1110
1111 /*
1112 * Wasn't able to bind to a reserved port, so close the socket and return
1113 * -1...
1114 */
1115
1116 # ifdef WIN32
1117 closesocket(fd);
1118 # else
1119 close(fd);
1120 # endif /* WIN32 */
1121
1122 return (-1);
1123 }
1124 #endif /* !HAVE_RRESVPORT_AF */
1125
1126
1127 /*
1128 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1129 */
1130
1131 static void
1132 sigterm_handler(int sig) /* I - Signal */
1133 {
1134 (void)sig; /* remove compiler warnings... */
1135
1136 abort_job = 1;
1137 }
1138
1139
1140 /*
1141 * End of "$Id$".
1142 */