]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/lpd.c
Merge changes from CUPS 1.4svn-r8492.
[thirdparty/cups.git] / backend / lpd.c
CommitLineData
ef416fc2 1/*
b19ccc9e 2 * "$Id: lpd.c 7740 2008-07-14 23:58:05Z mike $"
ef416fc2 3 *
4 * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
5 *
8b116e60 6 * Copyright 2007-2009 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{
1f0275e3 115 const char *device_uri; /* Device URI */
7a14d768
MS
116 char method[255], /* Method in URI */
117 hostname[1024], /* Hostname */
118 username[255], /* Username info */
119 resource[1024], /* Resource info (printer name) */
120 *options, /* Pointer to options */
121 *name, /* Name of option */
122 *value, /* Value of option */
123 sep, /* Separator character */
124 *filename, /* File to print */
125 title[256]; /* Title string */
126 int port; /* Port number */
127 int fd; /* Print file */
128 int status; /* Status of LPD job */
129 int mode; /* Print mode */
130 int banner; /* Print banner page? */
131 int format; /* Print format */
132 int order; /* Order of control/data files */
133 int reserve; /* Reserve priviledged port? */
134 int sanitize_title; /* Sanitize title string? */
135 int manual_copies, /* Do manual copies? */
136 timeout, /* Timeout */
137 contimeout, /* Connection timeout */
138 copies; /* Number of copies */
ef416fc2 139#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
7a14d768 140 struct sigaction action; /* Actions for POSIX signals */
ef416fc2 141#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
142
143
144 /*
145 * Make sure status messages are not buffered...
146 */
147
148 setbuf(stderr, NULL);
149
150 /*
151 * Ignore SIGPIPE and catch SIGTERM signals...
152 */
153
154#ifdef HAVE_SIGSET
155 sigset(SIGPIPE, SIG_IGN);
156 sigset(SIGTERM, sigterm_handler);
157#elif defined(HAVE_SIGACTION)
158 memset(&action, 0, sizeof(action));
159 action.sa_handler = SIG_IGN;
160 sigaction(SIGPIPE, &action, NULL);
161
162 sigemptyset(&action.sa_mask);
163 sigaddset(&action.sa_mask, SIGTERM);
164 action.sa_handler = sigterm_handler;
165 sigaction(SIGTERM, &action, NULL);
166#else
167 signal(SIGPIPE, SIG_IGN);
168 signal(SIGTERM, sigterm_handler);
169#endif /* HAVE_SIGSET */
170
171 /*
172 * Check command-line...
173 */
174
175 if (argc == 1)
176 {
8b450588
MS
177 printf("network lpd \"Unknown\" \"%s\"\n",
178 _cupsLangString(cupsLangDefault(), _("LPD/LPR Host or Printer")));
ef416fc2 179 return (CUPS_BACKEND_OK);
180 }
181 else if (argc < 6 || argc > 7)
182 {
db1f069b
MS
183 _cupsLangPrintf(stderr,
184 _("Usage: %s job-id user title copies options [file]\n"),
185 argv[0]);
ef416fc2 186 return (CUPS_BACKEND_FAILED);
187 }
188
ef416fc2 189 /*
190 * Extract the hostname and printer name from the URI...
191 */
192
1f0275e3
MS
193 if ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
194 return (CUPS_BACKEND_FAILED);
195
196 httpSeparateURI(HTTP_URI_CODING_ALL, device_uri,
a4d04587 197 method, sizeof(method), username, sizeof(username),
198 hostname, sizeof(hostname), &port,
ef416fc2 199 resource, sizeof(resource));
200
a41f09e2
MS
201 if (!port)
202 port = 515; /* Default to port 515 */
203
ef416fc2 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") ||
8b116e60 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 {
080811b1 433 _cupsLangPrintError(_("ERROR: Unable to create temporary file"));
f42414bf 434 return (CUPS_BACKEND_FAILED);
435 }
436
8b116e60
MS
437 _cupsLangPuts(stderr, _("INFO: Copying print data...\n"));
438
f42414bf 439 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
440 if (write(fd, buffer, bytes) < bytes)
441 {
080811b1 442 _cupsLangPrintError(_("ERROR: Unable to write to temporary file"));
f42414bf 443 close(fd);
444 unlink(tmpfilename);
445 return (CUPS_BACKEND_FAILED);
446 }
f42414bf 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 {
080811b1 580 _cupsLangPrintError(_("ERROR: Unable to send LPD command"));
ef416fc2 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 */
426c6a59
MS
642 int snmp_fd, /* SNMP socket */
643 have_supplies; /* Printer supports supply levels? */
ef416fc2 644 int copy; /* Copies written */
fa73b229 645 time_t start_time; /* Time of first connect */
fa73b229 646 int recoverable; /* Recoverable error shown? */
ef416fc2 647 size_t nbytes; /* Number of bytes written */
648 off_t tbytes; /* Total bytes written */
a74454a7 649 char buffer[32768]; /* Output buffer */
ef416fc2 650#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
651 struct sigaction action; /* Actions for POSIX signals */
652#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
653
654
655 /*
656 * Setup an alarm handler for timeouts...
657 */
658
659#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
660 sigset(SIGALRM, lpd_timeout);
661#elif defined(HAVE_SIGACTION)
662 memset(&action, 0, sizeof(action));
663
664 sigemptyset(&action.sa_mask);
665 action.sa_handler = lpd_timeout;
666 sigaction(SIGALRM, &action, NULL);
667#else
668 signal(SIGALRM, lpd_timeout);
669#endif /* HAVE_SIGSET */
670
671 /*
672 * Find the printer...
673 */
674
675 sprintf(portname, "%d", port);
676
1340db2d
MS
677 fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);
678
ef416fc2 679 if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
680 {
db1f069b
MS
681 _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"),
682 hostname);
ef416fc2 683 return (CUPS_BACKEND_STOP);
684 }
685
fa73b229 686 /*
c0e1af83 687 * Remember when we started trying to connect to the printer...
fa73b229 688 */
689
fa73b229 690 recoverable = 0;
fa73b229 691 start_time = time(NULL);
692
ef416fc2 693 /*
694 * Loop forever trying to print the file...
695 */
696
697 while (!abort_job)
698 {
699 /*
700 * First try to reserve a port for this connection...
701 */
702
757d2cad 703 fputs("STATE: +connecting-to-device\n", stderr);
8b450588
MS
704 fprintf(stderr, "DEBUG: Connecting to %s:%d for printer %s\n",
705 hostname, port, printer);
706 _cupsLangPuts(stderr, _("INFO: Connecting to printer...\n"));
ef416fc2 707
c0e1af83 708 for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist,
709 delay = 5;;
ef416fc2 710 addr = addr->next)
711 {
712 /*
713 * Stop if this job has been cancelled...
714 */
715
716 if (abort_job)
717 {
718 httpAddrFreeList(addrlist);
719
720 return (CUPS_BACKEND_FAILED);
721 }
722
723 /*
724 * Choose the next priviledged port...
725 */
726
727 if (!addr)
728 addr = addrlist;
729
730 lport --;
731
732 if (lport < 721 && reserve == RESERVE_RFC1179)
733 lport = 731;
734 else if (lport < 1)
735 lport = 1023;
736
737#ifdef HAVE_GETEUID
738 if (geteuid() || !reserve)
739#else
740 if (getuid() || !reserve)
741#endif /* HAVE_GETEUID */
742 {
743 /*
744 * Just create a regular socket...
745 */
746
747 if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
748 {
080811b1 749 _cupsLangPrintError(_("ERROR: Unable to create socket"));
ef416fc2 750 sleep(1);
751
752 continue;
753 }
754
755 lport = 0;
756 }
757 else
758 {
759 /*
760 * We're running as root and want to comply with RFC 1179. Reserve a
761 * priviledged lport between 721 and 731...
762 */
763
764 if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0)
765 {
080811b1 766 _cupsLangPrintError(_("ERROR: Unable to reserve port"));
ef416fc2 767 sleep(1);
768
769 continue;
770 }
771 }
772
773 /*
774 * Connect to the printer or server...
775 */
776
777 if (abort_job)
778 {
779 httpAddrFreeList(addrlist);
780
781 close(fd);
782
783 return (CUPS_BACKEND_FAILED);
784 }
785
786 if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr))))
787 break;
788
789 error = errno;
790 close(fd);
791 fd = -1;
792
793 if (addr->next)
794 continue;
795
796 if (getenv("CLASS") != NULL)
797 {
798 /*
799 * If the CLASS environment variable is set, the job was submitted
800 * to a class and not to a specific queue. In this case, we want
801 * to abort immediately so that the job can be requeued on the next
802 * available printer in the class.
803 */
804
db1f069b
MS
805 _cupsLangPuts(stderr,
806 _("INFO: Unable to contact printer, queuing on next "
807 "printer in class...\n"));
ef416fc2 808
809 httpAddrFreeList(addrlist);
810
811 /*
812 * Sleep 5 seconds to keep the job from requeuing too rapidly...
813 */
814
815 sleep(5);
816
817 return (CUPS_BACKEND_FAILED);
818 }
819
820 if (error == ECONNREFUSED || error == EHOSTDOWN ||
821 error == EHOSTUNREACH)
822 {
fa73b229 823 if (contimeout && (time(NULL) - start_time) > contimeout)
824 {
db1f069b 825 _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n"));
fa73b229 826 return (CUPS_BACKEND_FAILED);
827 }
828
fa73b229 829 recoverable = 1;
c0e1af83 830
db1f069b
MS
831 _cupsLangPrintf(stderr,
832 _("WARNING: recoverable: Network host \'%s\' is busy; "
833 "will retry in %d seconds...\n"), hostname, delay);
c0e1af83 834
835 sleep(delay);
836
837 if (delay < 30)
838 delay += 5;
ef416fc2 839 }
840 else if (error == EADDRINUSE)
841 {
842 /*
843 * Try on another port...
844 */
845
846 sleep(1);
847 }
848 else
849 {
fa73b229 850 recoverable = 1;
c0e1af83 851
852 fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno));
db1f069b
MS
853 _cupsLangPuts(stderr,
854 _("ERROR: recoverable: Unable to connect to printer; "
855 "will retry in 30 seconds...\n"));
c0e1af83 856 sleep(30);
ef416fc2 857 }
858 }
859
fa73b229 860 if (recoverable)
861 {
862 /*
863 * If we've shown a recoverable error make sure the printer proxies
864 * have a chance to see the recovered message. Not pretty but
865 * necessary for now...
866 */
867
868 fputs("INFO: recovered: \n", stderr);
869 sleep(5);
870 }
fa73b229 871
757d2cad 872 fputs("STATE: -connecting-to-device\n", stderr);
8b450588 873 _cupsLangPuts(stderr, _("INFO: Connected to printer...\n"));
26d47ec6 874
875#ifdef AF_INET6
876 if (addr->addr.addr.sa_family == AF_INET6)
877 fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6) (local port %d)...\n",
c0e1af83 878 httpAddrString(&addr->addr, addrname, sizeof(addrname)),
879 ntohs(addr->addr.ipv6.sin6_port), lport);
26d47ec6 880 else
881#endif /* AF_INET6 */
882 if (addr->addr.addr.sa_family == AF_INET)
883 fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4) (local port %d)...\n",
c0e1af83 884 httpAddrString(&addr->addr, addrname, sizeof(addrname)),
885 ntohs(addr->addr.ipv4.sin_port), lport);
ef416fc2 886
7a14d768
MS
887 /*
888 * See if the printer supports SNMP...
889 */
890
891 if ((snmp_fd = _cupsSNMPOpen(addr->addr.addr.sa_family)) >= 0)
426c6a59
MS
892 have_supplies = !backendSNMPSupplies(snmp_fd, &(addr->addr), NULL, NULL);
893 else
894 have_supplies = 0;
7a14d768
MS
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 1182 /*
52f6f666 1183 * Collect the final supply levels as needed...
7a14d768
MS
1184 */
1185
426c6a59 1186 if (have_supplies)
52f6f666 1187 backendSNMPSupplies(snmp_fd, &(addr->addr), NULL, NULL);
7a14d768 1188
ef416fc2 1189 /*
1190 * Close the socket connection and input file...
1191 */
1192
1193 close(fd);
ef416fc2 1194
1195 if (status == 0)
1196 {
1197 httpAddrFreeList(addrlist);
1198
1199 return (CUPS_BACKEND_OK);
1200 }
1201
1202 /*
1203 * Waiting for a retry...
1204 */
1205
1206 sleep(30);
1207 }
1208
1209 httpAddrFreeList(addrlist);
1210
1211 /*
1212 * If we get here, then the job has been cancelled...
1213 */
1214
1215 return (CUPS_BACKEND_FAILED);
1216}
1217
1218
1219/*
1220 * 'lpd_timeout()' - Handle timeout alarms...
1221 */
1222
1223static void
1224lpd_timeout(int sig) /* I - Signal number */
1225{
1226 (void)sig;
1227
1228#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1229 signal(SIGALRM, lpd_timeout);
1230#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1231}
1232
1233
1234/*
1235 * 'lpd_write()' - Write a buffer of data to an LPD server.
1236 */
1237
1238static int /* O - Number of bytes written or -1 on error */
1239lpd_write(int lpd_fd, /* I - LPD socket */
1240 char *buffer, /* I - Buffer to write */
1241 int length) /* I - Number of bytes to write */
1242{
1243 int bytes, /* Number of bytes written */
1244 total; /* Total number of bytes written */
1245
1246
1247 if (abort_job)
1248 return (-1);
1249
1250 total = 0;
1251 while ((bytes = send(lpd_fd, buffer, length - total, 0)) >= 0)
1252 {
1253 total += bytes;
1254 buffer += bytes;
1255
1256 if (total == length)
1257 break;
1258 }
1259
1260 if (bytes < 0)
1261 return (-1);
1262 else
1263 return (length);
1264}
1265
1266
1267#ifndef HAVE_RRESVPORT_AF
1268/*
1269 * 'rresvport_af()' - A simple implementation of rresvport_af().
1270 */
1271
1272static int /* O - Socket or -1 on error */
1273rresvport_af(int *port, /* IO - Port number to bind to */
1274 int family) /* I - Address family */
1275{
1276 http_addr_t addr; /* Socket address */
1277 int fd; /* Socket file descriptor */
1278
1279
1280 /*
1281 * Try to create an IPv4 socket...
1282 */
1283
1284 if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
1285 return (-1);
1286
1287 /*
1288 * Initialize the address buffer...
1289 */
1290
1291 memset(&addr, 0, sizeof(addr));
1292 addr.addr.sa_family = family;
1293
1294 /*
1295 * Try to bind the socket to a reserved port...
1296 */
1297
1298 while (*port > 511)
1299 {
1300 /*
1301 * Set the port number...
1302 */
1303
1304# ifdef AF_INET6
1305 if (family == AF_INET6)
1306 addr.ipv6.sin6_port = htons(*port);
1307 else
1308# endif /* AF_INET6 */
1309 addr.ipv4.sin_port = htons(*port);
1310
1311 /*
1312 * Try binding the port to the socket; return if all is OK...
1313 */
1314
1315 if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
1316 return (fd);
1317
1318 /*
1319 * Stop if we have any error other than "address already in use"...
1320 */
1321
1322 if (errno != EADDRINUSE)
1323 {
1324# ifdef WIN32
1325 closesocket(fd);
1326# else
1327 close(fd);
1328# endif /* WIN32 */
1329
1330 return (-1);
1331 }
1332
1333 /*
1334 * Try the next port...
1335 */
1336
1337 (*port)--;
1338 }
1339
1340 /*
1341 * Wasn't able to bind to a reserved port, so close the socket and return
1342 * -1...
1343 */
1344
1345# ifdef WIN32
1346 closesocket(fd);
1347# else
1348 close(fd);
1349# endif /* WIN32 */
1350
1351 return (-1);
1352}
1353#endif /* !HAVE_RRESVPORT_AF */
1354
1355
1356/*
1357 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1358 */
1359
1360static void
1361sigterm_handler(int sig) /* I - Signal */
1362{
1363 (void)sig; /* remove compiler warnings... */
1364
1365 abort_job = 1;
1366}
1367
1368
1369/*
b19ccc9e 1370 * End of "$Id: lpd.c 7740 2008-07-14 23:58:05Z mike $".
ef416fc2 1371 */