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