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