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