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