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