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