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