]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/lpd.c
Merge changes from CUPS 1.4svn-r8394.
[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 *
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{
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") ||
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
437 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
438 if (write(fd, buffer, bytes) < bytes)
439 {
080811b1 440 _cupsLangPrintError(_("ERROR: Unable to write to temporary file"));
f42414bf 441 close(fd);
442 unlink(tmpfilename);
443 return (CUPS_BACKEND_FAILED);
444 }
f42414bf 445 }
446 else if (argc == 6)
447 {
448 /*
449 * Stream from stdin...
450 */
451
452 filename = NULL;
453 fd = 0;
454 }
455 else
456 {
457 filename = argv[6];
458 fd = open(filename, O_RDONLY);
459
460 if (fd == -1)
461 {
db1f069b
MS
462 _cupsLangPrintf(stderr, _("ERROR: Unable to open print file %s: %s\n"),
463 filename, strerror(errno));
f42414bf 464 return (CUPS_BACKEND_FAILED);
465 }
466 }
467
ef416fc2 468 /*
469 * Sanitize the document title...
470 */
471
472 strlcpy(title, argv[3], sizeof(title));
473
474 if (sanitize_title)
475 {
476 /*
477 * Sanitize the title string so that we don't cause problems on
478 * the remote end...
479 */
480
db1f069b
MS
481 char *ptr;
482
ef416fc2 483 for (ptr = title; *ptr; ptr ++)
484 if (!isalnum(*ptr & 255) && !isspace(*ptr & 255))
485 *ptr = '_';
486 }
487
488 /*
489 * Queue the job...
490 */
491
492 if (argc > 6)
493 {
494 if (manual_copies)
495 {
496 manual_copies = atoi(argv[4]);
497 copies = 1;
498 }
499 else
500 {
501 manual_copies = 1;
502 copies = atoi(argv[4]);
503 }
504
f42414bf 505 status = lpd_queue(hostname, port, resource + 1, fd, mode,
ef416fc2 506 username, title, copies,
fa73b229 507 banner, format, order, reserve, manual_copies,
508 timeout, contimeout);
ef416fc2 509
510 if (!status)
511 fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
512 }
513 else
f42414bf 514 status = lpd_queue(hostname, port, resource + 1, fd, mode,
ef416fc2 515 username, title, 1,
fa73b229 516 banner, format, order, reserve, 1,
517 timeout, contimeout);
ef416fc2 518
519 /*
520 * Remove the temporary file if necessary...
521 */
522
523 if (tmpfilename[0])
524 unlink(tmpfilename);
525
f42414bf 526 if (fd)
527 close(fd);
528
ef416fc2 529 /*
530 * Return the queue status...
531 */
532
533 return (status);
534}
535
536
537/*
538 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
539 */
540
541static int /* O - Status of command */
542lpd_command(int fd, /* I - Socket connection to LPD host */
543 int timeout, /* I - Seconds to wait for a response */
544 char *format, /* I - printf()-style format string */
545 ...) /* I - Additional args as necessary */
546{
547 va_list ap; /* Argument pointer */
548 char buf[1024]; /* Output buffer */
549 int bytes; /* Number of bytes to output */
550 char status; /* Status from command */
551
552
553 /*
554 * Don't try to send commands if the job has been cancelled...
555 */
556
557 if (abort_job)
558 return (-1);
559
560 /*
561 * Format the string...
562 */
563
564 va_start(ap, format);
565 bytes = vsnprintf(buf, sizeof(buf), format, ap);
566 va_end(ap);
567
568 fprintf(stderr, "DEBUG: lpd_command %2.2x %s", buf[0], buf + 1);
569
570 /*
571 * Send the command...
572 */
573
574 fprintf(stderr, "DEBUG: Sending command string (%d bytes)...\n", bytes);
575
576 if (lpd_write(fd, buf, bytes) < bytes)
577 {
080811b1 578 _cupsLangPrintError(_("ERROR: Unable to send LPD command"));
ef416fc2 579 return (-1);
580 }
581
582 /*
583 * Read back the status from the command and return it...
584 */
585
c0e1af83 586 fputs("DEBUG: Reading command status...\n", stderr);
ef416fc2 587
588 alarm(timeout);
589
590 if (recv(fd, &status, 1, 0) < 1)
591 {
db1f069b
MS
592 _cupsLangPrintf(stderr,
593 _("WARNING: Remote host did not respond with command "
594 "status byte after %d seconds!\n"), timeout);
ef416fc2 595 status = errno;
596 }
597
598 alarm(0);
599
600 fprintf(stderr, "DEBUG: lpd_command returning %d\n", status);
601
602 return (status);
603}
604
605
606/*
607 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
608 */
609
610static int /* O - Zero on success, non-zero on failure */
611lpd_queue(const char *hostname, /* I - Host to connect to */
612 int port, /* I - Port to connect on */
613 const char *printer, /* I - Printer/queue name */
f42414bf 614 int print_fd, /* I - File to print */
615 int mode, /* I - Print mode */
ef416fc2 616 const char *user, /* I - Requesting user */
617 const char *title, /* I - Job title */
618 int copies, /* I - Number of copies */
619 int banner, /* I - Print LPD banner? */
620 int format, /* I - Format specifier */
621 int order, /* I - Order of data/control files */
622 int reserve, /* I - Reserve ports? */
623 int manual_copies, /* I - Do copies by hand... */
fa73b229 624 int timeout, /* I - Timeout... */
625 int contimeout) /* I - Connection timeout */
ef416fc2 626{
ef416fc2 627 char localhost[255]; /* Local host name */
628 int error; /* Error number */
629 struct stat filestats; /* File statistics */
630 int lport; /* LPD connection local port */
631 int fd; /* LPD socket */
632 char control[10240], /* LPD control 'file' */
633 *cptr; /* Pointer into control file string */
634 char status; /* Status byte from command */
635 char portname[255]; /* Port name */
c0e1af83 636 int delay; /* Delay for retries... */
26d47ec6 637 char addrname[256]; /* Address name */
ef416fc2 638 http_addrlist_t *addrlist, /* Address list */
639 *addr; /* Socket address */
426c6a59
MS
640 int snmp_fd, /* SNMP socket */
641 have_supplies; /* Printer supports supply levels? */
ef416fc2 642 int copy; /* Copies written */
fa73b229 643 time_t start_time; /* Time of first connect */
fa73b229 644 int recoverable; /* Recoverable error shown? */
ef416fc2 645 size_t nbytes; /* Number of bytes written */
646 off_t tbytes; /* Total bytes written */
a74454a7 647 char buffer[32768]; /* Output buffer */
ef416fc2 648#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
649 struct sigaction action; /* Actions for POSIX signals */
650#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
651
652
653 /*
654 * Setup an alarm handler for timeouts...
655 */
656
657#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
658 sigset(SIGALRM, lpd_timeout);
659#elif defined(HAVE_SIGACTION)
660 memset(&action, 0, sizeof(action));
661
662 sigemptyset(&action.sa_mask);
663 action.sa_handler = lpd_timeout;
664 sigaction(SIGALRM, &action, NULL);
665#else
666 signal(SIGALRM, lpd_timeout);
667#endif /* HAVE_SIGSET */
668
669 /*
670 * Find the printer...
671 */
672
673 sprintf(portname, "%d", port);
674
675 if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
676 {
db1f069b
MS
677 _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"),
678 hostname);
ef416fc2 679 return (CUPS_BACKEND_STOP);
680 }
681
fa73b229 682 /*
c0e1af83 683 * Remember when we started trying to connect to the printer...
fa73b229 684 */
685
fa73b229 686 recoverable = 0;
fa73b229 687 start_time = time(NULL);
688
ef416fc2 689 /*
690 * Loop forever trying to print the file...
691 */
692
693 while (!abort_job)
694 {
695 /*
696 * First try to reserve a port for this connection...
697 */
698
757d2cad 699 fputs("STATE: +connecting-to-device\n", stderr);
8b450588
MS
700 fprintf(stderr, "DEBUG: Connecting to %s:%d for printer %s\n",
701 hostname, port, printer);
702 _cupsLangPuts(stderr, _("INFO: Connecting to printer...\n"));
ef416fc2 703
c0e1af83 704 for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist,
705 delay = 5;;
ef416fc2 706 addr = addr->next)
707 {
708 /*
709 * Stop if this job has been cancelled...
710 */
711
712 if (abort_job)
713 {
714 httpAddrFreeList(addrlist);
715
716 return (CUPS_BACKEND_FAILED);
717 }
718
719 /*
720 * Choose the next priviledged port...
721 */
722
723 if (!addr)
724 addr = addrlist;
725
726 lport --;
727
728 if (lport < 721 && reserve == RESERVE_RFC1179)
729 lport = 731;
730 else if (lport < 1)
731 lport = 1023;
732
733#ifdef HAVE_GETEUID
734 if (geteuid() || !reserve)
735#else
736 if (getuid() || !reserve)
737#endif /* HAVE_GETEUID */
738 {
739 /*
740 * Just create a regular socket...
741 */
742
743 if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
744 {
080811b1 745 _cupsLangPrintError(_("ERROR: Unable to create socket"));
ef416fc2 746 sleep(1);
747
748 continue;
749 }
750
751 lport = 0;
752 }
753 else
754 {
755 /*
756 * We're running as root and want to comply with RFC 1179. Reserve a
757 * priviledged lport between 721 and 731...
758 */
759
760 if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0)
761 {
080811b1 762 _cupsLangPrintError(_("ERROR: Unable to reserve port"));
ef416fc2 763 sleep(1);
764
765 continue;
766 }
767 }
768
769 /*
770 * Connect to the printer or server...
771 */
772
773 if (abort_job)
774 {
775 httpAddrFreeList(addrlist);
776
777 close(fd);
778
779 return (CUPS_BACKEND_FAILED);
780 }
781
782 if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr))))
783 break;
784
785 error = errno;
786 close(fd);
787 fd = -1;
788
789 if (addr->next)
790 continue;
791
792 if (getenv("CLASS") != NULL)
793 {
794 /*
795 * If the CLASS environment variable is set, the job was submitted
796 * to a class and not to a specific queue. In this case, we want
797 * to abort immediately so that the job can be requeued on the next
798 * available printer in the class.
799 */
800
db1f069b
MS
801 _cupsLangPuts(stderr,
802 _("INFO: Unable to contact printer, queuing on next "
803 "printer in class...\n"));
ef416fc2 804
805 httpAddrFreeList(addrlist);
806
807 /*
808 * Sleep 5 seconds to keep the job from requeuing too rapidly...
809 */
810
811 sleep(5);
812
813 return (CUPS_BACKEND_FAILED);
814 }
815
816 if (error == ECONNREFUSED || error == EHOSTDOWN ||
817 error == EHOSTUNREACH)
818 {
fa73b229 819 if (contimeout && (time(NULL) - start_time) > contimeout)
820 {
db1f069b 821 _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n"));
fa73b229 822 return (CUPS_BACKEND_FAILED);
823 }
824
fa73b229 825 recoverable = 1;
c0e1af83 826
db1f069b
MS
827 _cupsLangPrintf(stderr,
828 _("WARNING: recoverable: Network host \'%s\' is busy; "
829 "will retry in %d seconds...\n"), hostname, delay);
c0e1af83 830
831 sleep(delay);
832
833 if (delay < 30)
834 delay += 5;
ef416fc2 835 }
836 else if (error == EADDRINUSE)
837 {
838 /*
839 * Try on another port...
840 */
841
842 sleep(1);
843 }
844 else
845 {
fa73b229 846 recoverable = 1;
c0e1af83 847
848 fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno));
db1f069b
MS
849 _cupsLangPuts(stderr,
850 _("ERROR: recoverable: Unable to connect to printer; "
851 "will retry in 30 seconds...\n"));
c0e1af83 852 sleep(30);
ef416fc2 853 }
854 }
855
fa73b229 856 if (recoverable)
857 {
858 /*
859 * If we've shown a recoverable error make sure the printer proxies
860 * have a chance to see the recovered message. Not pretty but
861 * necessary for now...
862 */
863
864 fputs("INFO: recovered: \n", stderr);
865 sleep(5);
866 }
fa73b229 867
757d2cad 868 fputs("STATE: -connecting-to-device\n", stderr);
8b450588 869 _cupsLangPuts(stderr, _("INFO: Connected to printer...\n"));
26d47ec6 870
871#ifdef AF_INET6
872 if (addr->addr.addr.sa_family == AF_INET6)
873 fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6) (local port %d)...\n",
c0e1af83 874 httpAddrString(&addr->addr, addrname, sizeof(addrname)),
875 ntohs(addr->addr.ipv6.sin6_port), lport);
26d47ec6 876 else
877#endif /* AF_INET6 */
878 if (addr->addr.addr.sa_family == AF_INET)
879 fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4) (local port %d)...\n",
c0e1af83 880 httpAddrString(&addr->addr, addrname, sizeof(addrname)),
881 ntohs(addr->addr.ipv4.sin_port), lport);
ef416fc2 882
7a14d768
MS
883 /*
884 * See if the printer supports SNMP...
885 */
886
887 if ((snmp_fd = _cupsSNMPOpen(addr->addr.addr.sa_family)) >= 0)
426c6a59
MS
888 have_supplies = !backendSNMPSupplies(snmp_fd, &(addr->addr), NULL, NULL);
889 else
890 have_supplies = 0;
7a14d768
MS
891
892 /*
893 * Check for side-channel requests...
894 */
895
896 backendCheckSideChannel(snmp_fd, &(addr->addr));
897
ef416fc2 898 /*
899 * Next, open the print file and figure out its size...
900 */
901
f42414bf 902 if (print_fd)
ef416fc2 903 {
c0e1af83 904 /*
905 * Use the size from the print file...
906 */
907
f42414bf 908 if (fstat(print_fd, &filestats))
909 {
910 httpAddrFreeList(addrlist);
911 close(fd);
ef416fc2 912
080811b1 913 _cupsLangPrintError(_("ERROR: unable to stat print file"));
f42414bf 914 return (CUPS_BACKEND_FAILED);
915 }
ef416fc2 916
f42414bf 917 filestats.st_size *= manual_copies;
ef416fc2 918 }
f42414bf 919 else
c0e1af83 920 {
921 /*
922 * Use a "very large value" for the size so that the printer will
923 * keep printing until we close the connection...
924 */
925
f42414bf 926#ifdef _LARGEFILE_SOURCE
927 filestats.st_size = (size_t)(999999999999.0);
928#else
929 filestats.st_size = 2147483647;
930#endif /* _LARGEFILE_SOURCE */
c0e1af83 931 }
ef416fc2 932
933 /*
934 * Send a job header to the printer, specifying no banner page and
935 * literal output...
936 */
937
938 if (lpd_command(fd, timeout, "\002%s\n",
939 printer)) /* Receive print job(s) */
940 {
941 httpAddrFreeList(addrlist);
942 close(fd);
943 return (CUPS_BACKEND_FAILED);
944 }
945
757d2cad 946 httpGetHostname(NULL, localhost, sizeof(localhost));
ef416fc2 947
948 snprintf(control, sizeof(control),
949 "H%.31s\n" /* RFC 1179, Section 7.2 - host name <= 31 chars */
950 "P%.31s\n" /* RFC 1179, Section 7.2 - user name <= 31 chars */
951 "J%.99s\n", /* RFC 1179, Section 7.2 - job name <= 99 chars */
952 localhost, user, title);
953 cptr = control + strlen(control);
954
955 if (banner)
956 {
957 snprintf(cptr, sizeof(control) - (cptr - control),
958 "C%.31s\n" /* RFC 1179, Section 7.2 - class name <= 31 chars */
959 "L%s\n",
960 localhost, user);
961 cptr += strlen(cptr);
962 }
963
964 while (copies > 0)
965 {
966 snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n",
967 format, (int)getpid() % 1000, localhost);
968 cptr += strlen(cptr);
969 copies --;
970 }
971
972 snprintf(cptr, sizeof(control) - (cptr - control),
973 "UdfA%03d%.15s\n"
974 "N%.131s\n", /* RFC 1179, Section 7.2 - sourcefile name <= 131 chars */
975 (int)getpid() % 1000, localhost, title);
976
977 fprintf(stderr, "DEBUG: Control file is:\n%s", control);
978
979 if (order == ORDER_CONTROL_DATA)
980 {
7a14d768
MS
981 /*
982 * Check for side-channel requests...
983 */
984
985 backendCheckSideChannel(snmp_fd, &(addr->addr));
986
987 /*
988 * Send the control file...
989 */
990
ef416fc2 991 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
992 (int)getpid() % 1000, localhost))
993 {
994 httpAddrFreeList(addrlist);
995 close(fd);
996
997 return (CUPS_BACKEND_FAILED);
998 }
999
db1f069b
MS
1000 _cupsLangPrintf(stderr, _("INFO: Sending control file (%u bytes)\n"),
1001 (unsigned)strlen(control));
ef416fc2 1002
1003 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
1004 {
1005 status = errno;
080811b1 1006 _cupsLangPrintError(_("ERROR: Unable to write control file"));
ef416fc2 1007 }
1008 else
1009 {
1010 alarm(timeout);
1011
1012 if (read(fd, &status, 1) < 1)
1013 {
db1f069b
MS
1014 _cupsLangPrintf(stderr,
1015 _("WARNING: Remote host did not respond with control "
1016 "status byte after %d seconds!\n"), timeout);
ef416fc2 1017 status = errno;
1018 }
1019
1020 alarm(0);
1021 }
1022
1023 if (status != 0)
db1f069b
MS
1024 _cupsLangPrintf(stderr,
1025 _("ERROR: Remote host did not accept control file "
1026 "(%d)\n"), status);
ef416fc2 1027 else
db1f069b 1028 _cupsLangPuts(stderr, _("INFO: Control file sent successfully\n"));
ef416fc2 1029 }
1030 else
1031 status = 0;
1032
1033 if (status == 0)
1034 {
7a14d768
MS
1035 /*
1036 * Check for side-channel requests...
1037 */
1038
1039 backendCheckSideChannel(snmp_fd, &(addr->addr));
1040
ef416fc2 1041 /*
1042 * Send the print file...
1043 */
1044
1045 if (lpd_command(fd, timeout, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
1046 CUPS_LLCAST filestats.st_size, (int)getpid() % 1000,
1047 localhost))
1048 {
1049 httpAddrFreeList(addrlist);
1050 close(fd);
1051
1052 return (CUPS_BACKEND_FAILED);
1053 }
1054
db1f069b 1055 _cupsLangPrintf(stderr,
c0e1af83 1056#ifdef HAVE_LONG_LONG
db1f069b 1057 _("INFO: Sending data file (%lld bytes)\n"),
c0e1af83 1058#else
db1f069b 1059 _("INFO: Sending data file (%ld bytes)\n"),
c0e1af83 1060#endif /* HAVE_LONG_LONG */
db1f069b 1061 CUPS_LLCAST filestats.st_size);
ef416fc2 1062
1063 tbytes = 0;
1064 for (copy = 0; copy < manual_copies; copy ++)
1065 {
f42414bf 1066 lseek(print_fd, 0, SEEK_SET);
ef416fc2 1067
f42414bf 1068 while ((nbytes = read(print_fd, buffer, sizeof(buffer))) > 0)
ef416fc2 1069 {
db1f069b
MS
1070 _cupsLangPrintf(stderr,
1071 _("INFO: Spooling LPR job, %.0f%% complete...\n"),
1072 100.0 * tbytes / filestats.st_size);
ef416fc2 1073
1074 if (lpd_write(fd, buffer, nbytes) < nbytes)
1075 {
080811b1 1076 _cupsLangPrintError(_("ERROR: Unable to send print file to printer"));
ef416fc2 1077 break;
1078 }
1079 else
1080 tbytes += nbytes;
1081 }
1082 }
1083
f42414bf 1084 if (mode == MODE_STANDARD)
ef416fc2 1085 {
f42414bf 1086 if (tbytes < filestats.st_size)
1087 status = errno;
1088 else if (lpd_write(fd, "", 1) < 1)
1089 {
080811b1 1090 _cupsLangPrintError(_("ERROR: Unable to send trailing nul to printer"));
f42414bf 1091 status = errno;
1092 }
1093 else
1094 {
1095 /*
1096 * Read the status byte from the printer; if we can't read the byte
1097 * back now, we should set status to "errno", however at this point
1098 * we know the printer got the whole file and we don't necessarily
1099 * want to requeue it over and over...
1100 */
ef416fc2 1101
f42414bf 1102 alarm(timeout);
ef416fc2 1103
f42414bf 1104 if (recv(fd, &status, 1, 0) < 1)
1105 {
db1f069b
MS
1106 _cupsLangPrintf(stderr,
1107 _("WARNING: Remote host did not respond with data "
1108 "status byte after %d seconds!\n"), timeout);
f42414bf 1109 status = 0;
1110 }
ef416fc2 1111
f42414bf 1112 alarm(0);
1113 }
ef416fc2 1114 }
f42414bf 1115 else
1116 status = 0;
ef416fc2 1117
1118 if (status != 0)
db1f069b
MS
1119 _cupsLangPrintf(stderr,
1120 _("ERROR: Remote host did not accept data file (%d)\n"),
1121 status);
ef416fc2 1122 else
db1f069b 1123 _cupsLangPuts(stderr, _("INFO: Data file sent successfully\n"));
ef416fc2 1124 }
1125
1126 if (status == 0 && order == ORDER_DATA_CONTROL)
1127 {
7a14d768
MS
1128 /*
1129 * Check for side-channel requests...
1130 */
1131
1132 backendCheckSideChannel(snmp_fd, &(addr->addr));
1133
1134 /*
1135 * Send control file...
1136 */
1137
ef416fc2 1138 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
1139 (int)getpid() % 1000, localhost))
1140 {
1141 httpAddrFreeList(addrlist);
1142 close(fd);
1143
1144 return (CUPS_BACKEND_FAILED);
1145 }
1146
db1f069b
MS
1147 _cupsLangPrintf(stderr, _("INFO: Sending control file (%lu bytes)\n"),
1148 (unsigned long)strlen(control));
ef416fc2 1149
1150 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
1151 {
1152 status = errno;
080811b1 1153 _cupsLangPrintError(_("ERROR: Unable to write control file"));
ef416fc2 1154 }
1155 else
1156 {
1157 alarm(timeout);
1158
1159 if (read(fd, &status, 1) < 1)
1160 {
db1f069b
MS
1161 _cupsLangPrintf(stderr,
1162 _("WARNING: Remote host did not respond with control "
1163 "status byte after %d seconds!\n"), timeout);
ef416fc2 1164 status = errno;
1165 }
1166
1167 alarm(0);
1168 }
1169
1170 if (status != 0)
db1f069b
MS
1171 _cupsLangPrintf(stderr,
1172 _("ERROR: Remote host did not accept control file "
1173 "(%d)\n"), status);
ef416fc2 1174 else
db1f069b 1175 _cupsLangPuts(stderr, _("INFO: Control file sent successfully\n"));
ef416fc2 1176 }
1177
7a14d768 1178 /*
52f6f666 1179 * Collect the final supply levels as needed...
7a14d768
MS
1180 */
1181
426c6a59 1182 if (have_supplies)
52f6f666 1183 backendSNMPSupplies(snmp_fd, &(addr->addr), NULL, NULL);
7a14d768 1184
ef416fc2 1185 /*
1186 * Close the socket connection and input file...
1187 */
1188
1189 close(fd);
ef416fc2 1190
1191 if (status == 0)
1192 {
1193 httpAddrFreeList(addrlist);
1194
1195 return (CUPS_BACKEND_OK);
1196 }
1197
1198 /*
1199 * Waiting for a retry...
1200 */
1201
1202 sleep(30);
1203 }
1204
1205 httpAddrFreeList(addrlist);
1206
1207 /*
1208 * If we get here, then the job has been cancelled...
1209 */
1210
1211 return (CUPS_BACKEND_FAILED);
1212}
1213
1214
1215/*
1216 * 'lpd_timeout()' - Handle timeout alarms...
1217 */
1218
1219static void
1220lpd_timeout(int sig) /* I - Signal number */
1221{
1222 (void)sig;
1223
1224#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1225 signal(SIGALRM, lpd_timeout);
1226#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1227}
1228
1229
1230/*
1231 * 'lpd_write()' - Write a buffer of data to an LPD server.
1232 */
1233
1234static int /* O - Number of bytes written or -1 on error */
1235lpd_write(int lpd_fd, /* I - LPD socket */
1236 char *buffer, /* I - Buffer to write */
1237 int length) /* I - Number of bytes to write */
1238{
1239 int bytes, /* Number of bytes written */
1240 total; /* Total number of bytes written */
1241
1242
1243 if (abort_job)
1244 return (-1);
1245
1246 total = 0;
1247 while ((bytes = send(lpd_fd, buffer, length - total, 0)) >= 0)
1248 {
1249 total += bytes;
1250 buffer += bytes;
1251
1252 if (total == length)
1253 break;
1254 }
1255
1256 if (bytes < 0)
1257 return (-1);
1258 else
1259 return (length);
1260}
1261
1262
1263#ifndef HAVE_RRESVPORT_AF
1264/*
1265 * 'rresvport_af()' - A simple implementation of rresvport_af().
1266 */
1267
1268static int /* O - Socket or -1 on error */
1269rresvport_af(int *port, /* IO - Port number to bind to */
1270 int family) /* I - Address family */
1271{
1272 http_addr_t addr; /* Socket address */
1273 int fd; /* Socket file descriptor */
1274
1275
1276 /*
1277 * Try to create an IPv4 socket...
1278 */
1279
1280 if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
1281 return (-1);
1282
1283 /*
1284 * Initialize the address buffer...
1285 */
1286
1287 memset(&addr, 0, sizeof(addr));
1288 addr.addr.sa_family = family;
1289
1290 /*
1291 * Try to bind the socket to a reserved port...
1292 */
1293
1294 while (*port > 511)
1295 {
1296 /*
1297 * Set the port number...
1298 */
1299
1300# ifdef AF_INET6
1301 if (family == AF_INET6)
1302 addr.ipv6.sin6_port = htons(*port);
1303 else
1304# endif /* AF_INET6 */
1305 addr.ipv4.sin_port = htons(*port);
1306
1307 /*
1308 * Try binding the port to the socket; return if all is OK...
1309 */
1310
1311 if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
1312 return (fd);
1313
1314 /*
1315 * Stop if we have any error other than "address already in use"...
1316 */
1317
1318 if (errno != EADDRINUSE)
1319 {
1320# ifdef WIN32
1321 closesocket(fd);
1322# else
1323 close(fd);
1324# endif /* WIN32 */
1325
1326 return (-1);
1327 }
1328
1329 /*
1330 * Try the next port...
1331 */
1332
1333 (*port)--;
1334 }
1335
1336 /*
1337 * Wasn't able to bind to a reserved port, so close the socket and return
1338 * -1...
1339 */
1340
1341# ifdef WIN32
1342 closesocket(fd);
1343# else
1344 close(fd);
1345# endif /* WIN32 */
1346
1347 return (-1);
1348}
1349#endif /* !HAVE_RRESVPORT_AF */
1350
1351
1352/*
1353 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1354 */
1355
1356static void
1357sigterm_handler(int sig) /* I - Signal */
1358{
1359 (void)sig; /* remove compiler warnings... */
1360
1361 abort_job = 1;
1362}
1363
1364
1365/*
b19ccc9e 1366 * End of "$Id: lpd.c 7740 2008-07-14 23:58:05Z mike $".
ef416fc2 1367 */