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