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