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