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