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