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