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