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