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