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