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