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