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