]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/lpd.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / backend / lpd.c
CommitLineData
43e2fc22 1/*
2d417cb3 2 * "$Id: lpd.c,v 1.28.2.25 2003/10/09 19:13:48 mike Exp $"
43e2fc22 3 *
e73c6c0a 4 * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
43e2fc22 5 *
1d9595ab 6 * Copyright 1997-2003 by Easy Software Products, all rights reserved.
43e2fc22 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
8784b6a6 17 * 44141 Airport View Drive, Suite 204
43e2fc22 18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
dab1a4d8 24 * This file is subject to the Apple OS-Developed Software exception.
25 *
43e2fc22 26 * Contents:
27 *
55737cf0 28 * main() - Send a file to the printer or server.
29 * lpd_command() - Send an LPR command sequence and wait for a reply.
30 * lpd_queue() - Queue a file using the Line Printer Daemon protocol.
31 * lpd_timeout() - Handle timeout alarms...
32 * lpd_write() - Write a buffer of data to an LPD server.
33 * rresvport() - A simple implementation of rresvport().
34 * sigterm_handler() - Handle 'terminate' signals that stop the backend.
e73c6c0a 35 */
36
37/*
38 * Include necessary headers.
39 */
40
41#include <cups/cups.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <stdarg.h>
8056639c 45#include <ctype.h>
2d417cb3 46#include <cups/http-private.h>
e73c6c0a 47#include <cups/string.h>
48#include <errno.h>
49#include <sys/types.h>
50#include <sys/stat.h>
4ff40357 51#include <signal.h>
e73c6c0a 52
c3026ddc 53#ifdef WIN32
e73c6c0a 54# include <winsock.h>
55#else
56# include <sys/socket.h>
57# include <netinet/in.h>
58# include <arpa/inet.h>
59# include <netdb.h>
c3026ddc 60#endif /* WIN32 */
e73c6c0a 61
55d0f521 62
55737cf0 63/*
64 * Globals...
65 */
66
67static char tmpfilename[1024] = ""; /* Temporary spool file name */
68
69
f8529e1a 70/*
71 * The order for control and data files in LPD requests...
72 */
73
74#define ORDER_CONTROL_DATA 0
75#define ORDER_DATA_CONTROL 1
76
77
55d0f521 78/*
79 * It appears that rresvport() is never declared on most systems...
80 */
81
82extern int rresvport(int *port);
e73c6c0a 83
84
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,
91 const char *filename,
92 const char *user, const char *title, int copies,
04e01993 93 int banner, int format, int order, int reserve,
55737cf0 94 int manual_copies, int timeout);
25037b2b 95static void lpd_timeout(int sig);
f8529e1a 96static int lpd_write(int lpd_fd, char *buffer, int length);
55737cf0 97static void sigterm_handler(int sig);
e73c6c0a 98
99
100/*
101 * 'main()' - Send a file to the printer or server.
43e2fc22 102 *
e73c6c0a 103 * Usage:
43e2fc22 104 *
e73c6c0a 105 * printer-uri job-id user title copies options [file]
43e2fc22 106 */
107
55737cf0 108int /* O - Exit status */
109main(int argc, /* I - Number of command-line arguments (6 or 7) */
110 char *argv[]) /* I - Command-line arguments */
e73c6c0a 111{
55737cf0 112 char method[255], /* Method in URI */
113 hostname[1024], /* Hostname */
114 username[255], /* Username info (not used) */
115 resource[1024], /* Resource info (printer name) */
116 *options, /* Pointer to options */
117 name[255], /* Name of option */
118 value[255], /* Value of option */
119 *ptr, /* Pointer into name or value */
120 *filename, /* File to print */
121 title[256]; /* Title string */
122 int port; /* Port number (not used) */
123 int status; /* Status of LPD job */
124 int banner; /* Print banner page? */
125 int format; /* Print format */
126 int order; /* Order of control/data files */
127 int reserve; /* Reserve priviledged port? */
128 int sanitize_title; /* Sanitize title string? */
129 int manual_copies, /* Do manual copies? */
130 timeout, /* Timeout */
131 copies; /* Number of copies */
73c53f5d 132#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
55737cf0 133 struct sigaction action; /* Actions for POSIX signals */
73c53f5d 134#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
e73c6c0a 135
136
4b23f3b3 137 /*
138 * Make sure status messages are not buffered...
139 */
140
141 setbuf(stderr, NULL);
142
98904cd6 143 /*
55737cf0 144 * Ignore SIGPIPE and catch SIGTERM signals...
98904cd6 145 */
146
147#ifdef HAVE_SIGSET
148 sigset(SIGPIPE, SIG_IGN);
55737cf0 149 sigset(SIGTERM, sigterm_handler);
98904cd6 150#elif defined(HAVE_SIGACTION)
151 memset(&action, 0, sizeof(action));
152 action.sa_handler = SIG_IGN;
153 sigaction(SIGPIPE, &action, NULL);
55737cf0 154
155 sigemptyset(&action.sa_mask);
156 sigaddset(&action.sa_mask, SIGTERM);
157 action.sa_handler = sigterm_handler;
158 sigaction(SIGTERM, &action, NULL);
98904cd6 159#else
160 signal(SIGPIPE, SIG_IGN);
55737cf0 161 signal(SIGTERM, sigterm_handler);
98904cd6 162#endif /* HAVE_SIGSET */
163
4b23f3b3 164 /*
165 * Check command-line...
166 */
167
68edc300 168 if (argc == 1)
169 {
d4c438d4 170 puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\"");
68edc300 171 return (0);
172 }
173 else if (argc < 6 || argc > 7)
e73c6c0a 174 {
175 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
176 argv[0]);
177 return (1);
178 }
179
180 /*
181 * If we have 7 arguments, print the file named on the command-line.
182 * Otherwise, copy stdin to a temporary file and print the temporary
183 * file.
184 */
185
186 if (argc == 6)
187 {
188 /*
189 * Copy stdin to a temporary file...
190 */
191
1b5bf964 192 int fd; /* Temporary file */
e73c6c0a 193 char buffer[8192]; /* Buffer for copying */
194 int bytes; /* Number of bytes read */
195
196
55737cf0 197 if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0)
e73c6c0a 198 {
c8f9565c 199 perror("ERROR: unable to create temporary file");
e73c6c0a 200 return (1);
201 }
202
203 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
1b5bf964 204 if (write(fd, buffer, bytes) < bytes)
e73c6c0a 205 {
c8f9565c 206 perror("ERROR: unable to write to temporary file");
1b5bf964 207 close(fd);
55737cf0 208 unlink(tmpfilename);
e73c6c0a 209 return (1);
210 }
211
1b5bf964 212 close(fd);
55737cf0 213 filename = tmpfilename;
e73c6c0a 214 }
215 else
55737cf0 216 filename = argv[6];
e73c6c0a 217
218 /*
219 * Extract the hostname and printer name from the URI...
220 */
221
222 httpSeparate(argv[0], method, username, hostname, &port, resource);
223
72a039d0 224 /*
225 * See if there are any options...
226 */
227
55737cf0 228 banner = 0;
229 format = 'l';
230 order = ORDER_CONTROL_DATA;
231 reserve = 0;
232 manual_copies = 1;
233 timeout = 300;
234 sanitize_title = 1;
72a039d0 235
236 if ((options = strchr(resource, '?')) != NULL)
237 {
238 /*
239 * Yup, terminate the device name string and move to the first
240 * character of the options...
241 */
242
243 *options++ = '\0';
244
245 /*
246 * Parse options...
247 */
248
249 while (*options)
250 {
251 /*
252 * Get the name...
253 */
254
255 for (ptr = name; *options && *options != '=';)
256 *ptr++ = *options++;
257 *ptr = '\0';
258
259 if (*options == '=')
260 {
261 /*
262 * Get the value...
263 */
264
265 options ++;
266
267 for (ptr = value; *options && *options != '+';)
268 *ptr++ = *options++;
269 *ptr = '\0';
270
271 if (*options == '+')
272 options ++;
273 }
274 else
275 value[0] = '\0';
276
277 /*
278 * Process the option...
279 */
280
281 if (strcasecmp(name, "banner") == 0)
282 {
283 /*
284 * Set the banner...
285 */
286
287 banner = !value[0] ||
288 strcasecmp(value, "on") == 0 ||
289 strcasecmp(value, "yes") == 0 ||
290 strcasecmp(value, "true") == 0;
291 }
292 else if (strcasecmp(name, "format") == 0 && value[0])
293 {
294 /*
295 * Set output format...
296 */
297
298 if (strchr("cdfglnoprtv", value[0]) != NULL)
299 format = value[0];
300 else
301 fprintf(stderr, "ERROR: Unknown format character \"%c\"\n", value[0]);
302 }
f8529e1a 303 else if (strcasecmp(name, "order") == 0 && value[0])
304 {
305 /*
306 * Set control/data order...
307 */
308
309 if (strcasecmp(value, "control,data") == 0)
310 order = ORDER_CONTROL_DATA;
311 else if (strcasecmp(value, "data,control") == 0)
312 order = ORDER_DATA_CONTROL;
313 else
314 fprintf(stderr, "ERROR: Unknown file order \"%s\"\n", value);
315 }
9ba7fc54 316 else if (strcasecmp(name, "reserve") == 0)
317 {
318 /*
319 * Set port reservation mode...
320 */
321
322 reserve = !value[0] ||
323 strcasecmp(value, "on") == 0 ||
324 strcasecmp(value, "yes") == 0 ||
325 strcasecmp(value, "true") == 0;
326 }
04e01993 327 else if (strcasecmp(name, "manual_copies") == 0)
328 {
329 /*
55737cf0 330 * Set manual copies...
04e01993 331 */
332
333 manual_copies = !value[0] ||
334 strcasecmp(value, "on") == 0 ||
335 strcasecmp(value, "yes") == 0 ||
336 strcasecmp(value, "true") == 0;
337 }
55737cf0 338 else if (strcasecmp(name, "sanitize_title") == 0)
339 {
340 /*
341 * Set sanitize title...
342 */
343
344 sanitize_title = !value[0] ||
345 strcasecmp(value, "on") == 0 ||
346 strcasecmp(value, "yes") == 0 ||
347 strcasecmp(value, "true") == 0;
348 }
349 else if (strcasecmp(name, "timeout") == 0)
350 {
351 /*
352 * Set the timeout...
353 */
354
355 if (atoi(value) > 0)
356 timeout = atoi(value);
357 }
72a039d0 358 }
359 }
360
8056639c 361 /*
362 * Sanitize the document title...
363 */
364
def978d5 365 strlcpy(title, argv[3], sizeof(title));
8056639c 366
55737cf0 367 if (sanitize_title)
368 {
369 /*
370 * Sanitize the title string so that we don't cause problems on
371 * the remote end...
372 */
373
374 for (ptr = title; *ptr; ptr ++)
375 if (!isalnum(*ptr) && !isspace(*ptr))
376 *ptr = '_';
377 }
8056639c 378
e73c6c0a 379 /*
380 * Queue the job...
381 */
382
3f9cb6c6 383 if (argc > 6)
384 {
04e01993 385 if (manual_copies)
386 {
387 manual_copies = atoi(argv[4]);
388 copies = 1;
389 }
390 else
391 {
392 manual_copies = 1;
393 copies = atoi(argv[4]);
394 }
395
c50b7b12 396 status = lpd_queue(hostname, port, resource + 1, filename,
04e01993 397 argv[2] /* user */, title, copies,
55737cf0 398 banner, format, order, reserve, manual_copies, timeout);
3f9cb6c6 399
400 if (!status)
401 fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
402 }
403 else
c50b7b12 404 status = lpd_queue(hostname, port, resource + 1, filename,
9ba7fc54 405 argv[2] /* user */, title, 1,
55737cf0 406 banner, format, order, reserve, 1, timeout);
e73c6c0a 407
408 /*
409 * Remove the temporary file if necessary...
410 */
411
55737cf0 412 if (tmpfilename[0])
413 unlink(tmpfilename);
e73c6c0a 414
415 /*
416 * Return the queue status...
417 */
418
419 return (status);
420}
421
422
43e2fc22 423/*
e73c6c0a 424 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
43e2fc22 425 */
426
e73c6c0a 427static int /* O - Status of command */
428lpd_command(int fd, /* I - Socket connection to LPD host */
55737cf0 429 int timeout, /* I - Seconds to wait for a response */
e73c6c0a 430 char *format, /* I - printf()-style format string */
431 ...) /* I - Additional args as necessary */
432{
433 va_list ap; /* Argument pointer */
434 char buf[1024]; /* Output buffer */
435 int bytes; /* Number of bytes to output */
436 char status; /* Status from command */
437
438
439 /*
440 * Format the string...
441 */
442
443 va_start(ap, format);
6a536282 444 bytes = vsnprintf(buf, sizeof(buf), format, ap);
e73c6c0a 445 va_end(ap);
446
d21a7597 447 fprintf(stderr, "DEBUG: lpd_command %2.2x %s", buf[0], buf + 1);
e73c6c0a 448
449 /*
450 * Send the command...
451 */
452
85e96ec0 453 fprintf(stderr, "DEBUG: Sending command string (%d bytes)...\n", bytes);
454
f8529e1a 455 if (lpd_write(fd, buf, bytes) < bytes)
55737cf0 456 {
457 perror("ERROR: Unable to send LPD command");
e73c6c0a 458 return (-1);
55737cf0 459 }
e73c6c0a 460
461 /*
462 * Read back the status from the command and return it...
463 */
464
85e96ec0 465 fprintf(stderr, "DEBUG: Reading command status...\n");
466
55737cf0 467 alarm(timeout);
25037b2b 468
e73c6c0a 469 if (recv(fd, &status, 1, 0) < 1)
55737cf0 470 {
471 fprintf(stderr, "WARNING: Remote host did not respond with command "
472 "status byte after %d seconds!\n", timeout);
1aef57ed 473 status = errno;
55737cf0 474 }
e73c6c0a 475
25037b2b 476 alarm(0);
477
c8f9565c 478 fprintf(stderr, "DEBUG: lpd_command returning %d\n", status);
e73c6c0a 479
480 return (status);
481}
482
483
484/*
485 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
486 */
487
55737cf0 488static int /* O - Zero on success, non-zero on failure */
c50b7b12 489lpd_queue(const char *hostname, /* I - Host to connect to */
490 int port, /* I - Port to connect on */
491 const char *printer, /* I - Printer/queue name */
492 const char *filename, /* I - File to print */
493 const char *user, /* I - Requesting user */
494 const char *title, /* I - Job title */
495 int copies, /* I - Number of copies */
496 int banner, /* I - Print LPD banner? */
497 int format, /* I - Format specifier */
498 int order, /* I - Order of data/control files */
499 int reserve, /* I - Reserve ports? */
500 int manual_copies, /* I - Do copies by hand... */
501 int timeout) /* I - Timeout... */
e73c6c0a 502{
503 FILE *fp; /* Job file */
504 char localhost[255]; /* Local host name */
505 int error; /* Error number */
506 struct stat filestats; /* File statistics */
c50b7b12 507 int lport; /* LPD connection local port */
e73c6c0a 508 int fd; /* LPD socket */
509 char control[10240], /* LPD control 'file' */
510 *cptr; /* Pointer into control file string */
511 char status; /* Status byte from command */
512 struct sockaddr_in addr; /* Socket address */
513 struct hostent *hostaddr; /* Host address */
38dc9124 514 int copy; /* Copies written */
e73c6c0a 515 size_t nbytes, /* Number of bytes written */
516 tbytes; /* Total bytes written */
517 char buffer[8192]; /* Output buffer */
4ff40357 518#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
519 struct sigaction action; /* Actions for POSIX signals */
520#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
e73c6c0a 521
522
1aef57ed 523 /*
524 * Setup an alarm handler for timeouts...
525 */
526
527#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
528 sigset(SIGALRM, lpd_timeout);
529#elif defined(HAVE_SIGACTION)
530 memset(&action, 0, sizeof(action));
e73c6c0a 531
1aef57ed 532 sigemptyset(&action.sa_mask);
533 action.sa_handler = lpd_timeout;
534 sigaction(SIGALRM, &action, NULL);
535#else
536 signal(SIGALRM, lpd_timeout);
537#endif /* HAVE_SIGSET */
538
539 /*
540 * Loop forever trying to print the file...
541 */
542
543 for (;;) /* FOREVER */
e73c6c0a 544 {
25037b2b 545 /*
546 * First try to reserve a port for this connection...
547 */
e73c6c0a 548
25037b2b 549 if ((hostaddr = httpGetHostByName(hostname)) == NULL)
550 {
8314b40b 551 fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s\n",
7e3ba0af 552 hostname, hstrerror(h_errno));
25037b2b 553 return (1);
554 }
e73c6c0a 555
25037b2b 556 fprintf(stderr, "INFO: Attempting to connect to host %s for printer %s\n",
557 hostname, printer);
e73c6c0a 558
25037b2b 559 memset(&addr, 0, sizeof(addr));
560 memcpy(&(addr.sin_addr), hostaddr->h_addr, hostaddr->h_length);
561 addr.sin_family = hostaddr->h_addrtype;
c50b7b12 562 addr.sin_port = htons(port);
25037b2b 563
c50b7b12 564 for (lport = 732;;)
55d0f521 565 {
25037b2b 566 if (getuid() || !reserve)
567 {
568 /*
569 * Just create a regular socket...
570 */
55d0f521 571
25037b2b 572 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
573 {
574 perror("ERROR: Unable to create socket");
575 return (1);
576 }
1aef57ed 577
c50b7b12 578 lport = 0;
25037b2b 579 }
580 else
55d0f521 581 {
25037b2b 582 /*
583 * We're running as root and want to comply with RFC 1179. Reserve a
c50b7b12 584 * priviledged lport between 721 and 732...
25037b2b 585 */
586
c50b7b12 587 if ((fd = rresvport(&lport)) < 0)
25037b2b 588 {
589 perror("ERROR: Unable to reserve port");
590 sleep(30);
591 continue;
592 }
55d0f521 593 }
55d0f521 594
25037b2b 595 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
55d0f521 596 {
25037b2b 597 error = errno;
598 close(fd);
599 fd = -1;
600
601 if (error == ECONNREFUSED || error == EHOSTDOWN ||
602 error == EHOSTUNREACH)
603 {
c46f2cfe 604 fprintf(stderr, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n",
25037b2b 605 hostname);
606 sleep(30);
607 }
608 else if (error == EADDRINUSE)
609 {
610 port --;
611 if (port < 721)
612 port = 732;
613 }
614 else
615 {
616 perror("ERROR: Unable to connect to printer");
617 sleep(30);
618 }
55d0f521 619 }
25037b2b 620 else
621 break;
e73c6c0a 622 }
623
c50b7b12 624 fprintf(stderr, "INFO: Connected to %s...\n", hostname);
625 fprintf(stderr, "DEBUG: Connected on ports %d (local %d)...\n", port,
626 lport);
25037b2b 627
25037b2b 628 /*
629 * Next, open the print file and figure out its size...
630 */
e73c6c0a 631
25037b2b 632 if (stat(filename, &filestats))
633 {
634 perror("ERROR: unable to stat print file");
635 return (1);
636 }
e73c6c0a 637
25037b2b 638 filestats.st_size *= manual_copies;
04e01993 639
25037b2b 640 if ((fp = fopen(filename, "rb")) == NULL)
641 {
642 perror("ERROR: unable to open print file for reading");
643 return (1);
644 }
e73c6c0a 645
25037b2b 646 /*
647 * Send a job header to the printer, specifying no banner page and
648 * literal output...
649 */
e73c6c0a 650
55737cf0 651 if (lpd_command(fd, timeout, "\002%s\n",
652 printer)) /* Receive print job(s) */
653 return (1);
e73c6c0a 654
25037b2b 655 gethostname(localhost, sizeof(localhost));
656 localhost[31] = '\0'; /* RFC 1179, Section 7.2 - host name < 32 chars */
e73c6c0a 657
82ba0702 658 snprintf(control, sizeof(control), "H%s\nP%s\nJ%s\n", localhost, user,
659 title);
25037b2b 660 cptr = control + strlen(control);
e73c6c0a 661
25037b2b 662 if (banner)
663 {
82ba0702 664 snprintf(cptr, sizeof(control) - (cptr - control), "L%s\nC%s\n", user,
665 localhost);
25037b2b 666 cptr += strlen(cptr);
667 }
72a039d0 668
25037b2b 669 while (copies > 0)
670 {
671 snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%s\n", format,
672 getpid() % 1000, localhost);
673 cptr += strlen(cptr);
674 copies --;
675 }
e73c6c0a 676
25037b2b 677 snprintf(cptr, sizeof(control) - (cptr - control),
854d3bb2 678 "UdfA%03d%s\nN%s\n",
679 getpid() % 1000, localhost, title);
e73c6c0a 680
25037b2b 681 fprintf(stderr, "DEBUG: Control file is:\n%s", control);
e73c6c0a 682
25037b2b 683 if (order == ORDER_CONTROL_DATA)
684 {
55737cf0 685 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%s\n", strlen(control),
686 getpid() % 1000, localhost))
687 return (1);
f8529e1a 688
1aef57ed 689 fprintf(stderr, "INFO: Sending control file (%lu bytes)\n",
690 (unsigned long)strlen(control));
e73c6c0a 691
25037b2b 692 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
693 {
694 status = errno;
695 perror("ERROR: Unable to write control file");
696 }
697 else
698 {
55737cf0 699 alarm(timeout);
f8529e1a 700
25037b2b 701 if (read(fd, &status, 1) < 1)
55737cf0 702 {
703 fprintf(stderr, "WARNING: Remote host did not respond with control "
704 "status byte after %d seconds!\n", timeout);
25037b2b 705 status = errno;
55737cf0 706 }
e73c6c0a 707
25037b2b 708 alarm(0);
709 }
e73c6c0a 710
25037b2b 711 if (status != 0)
712 fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n",
713 status);
714 else
715 fputs("INFO: Control file sent successfully\n", stderr);
716 }
717 else
718 status = 0;
e73c6c0a 719
25037b2b 720 if (status == 0)
e73c6c0a 721 {
25037b2b 722 /*
723 * Send the print file...
724 */
e73c6c0a 725
55737cf0 726 if (lpd_command(fd, timeout, "\003%u dfA%03.3d%s\n",
727 (unsigned)filestats.st_size, getpid() % 1000,
728 localhost))
729 return (1);
25037b2b 730
731 fprintf(stderr, "INFO: Sending data file (%u bytes)\n",
732 (unsigned)filestats.st_size);
733
734 tbytes = 0;
38dc9124 735 for (copy = 0; copy < manual_copies; copy ++)
e73c6c0a 736 {
25037b2b 737 rewind(fp);
04e01993 738
25037b2b 739 while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
04e01993 740 {
25037b2b 741 fprintf(stderr, "INFO: Spooling LPR job, %u%% complete...\n",
742 (unsigned)(100.0f * tbytes / filestats.st_size));
743
744 if (lpd_write(fd, buffer, nbytes) < nbytes)
745 {
746 perror("ERROR: Unable to send print file to printer");
747 break;
748 }
749 else
750 tbytes += nbytes;
04e01993 751 }
e73c6c0a 752 }
04e01993 753
25037b2b 754 if (tbytes < filestats.st_size)
755 status = errno;
756 else if (lpd_write(fd, "", 1) < 1)
55737cf0 757 {
758 perror("ERROR: Unable to send trailing nul to printer");
25037b2b 759 status = errno;
55737cf0 760 }
25037b2b 761 else
762 {
55737cf0 763 /*
764 * Read the status byte from the printer; if we can't read the byte
765 * back now, we should set status to "errno", however at this point
766 * we know the printer got the whole file and we don't necessarily
767 * want to requeue it over and over...
768 */
769
770 alarm(timeout);
25037b2b 771
772 if (recv(fd, &status, 1, 0) < 1)
55737cf0 773 {
774 fprintf(stderr, "WARNING: Remote host did not respond with data "
775 "status byte after %d seconds!\n", timeout);
776 status = 0;
777 }
25037b2b 778
779 alarm(0);
780 }
781
782 if (status != 0)
783 fprintf(stderr, "ERROR: Remote host did not accept data file (%d)\n",
784 status);
785 else
786 fputs("INFO: Data file sent successfully\n", stderr);
e73c6c0a 787 }
788
25037b2b 789 if (status == 0 && order == ORDER_DATA_CONTROL)
790 {
55737cf0 791 if (lpd_command(fd, timeout, "\002%d cfA%03.3d%s\n", strlen(control),
792 getpid() % 1000, localhost))
793 return (1);
f8529e1a 794
1aef57ed 795 fprintf(stderr, "INFO: Sending control file (%lu bytes)\n",
796 (unsigned long)strlen(control));
e73c6c0a 797
25037b2b 798 if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
799 {
800 status = errno;
801 perror("ERROR: Unable to write control file");
802 }
803 else
804 {
55737cf0 805 alarm(timeout);
f8529e1a 806
55737cf0 807 if (read(fd, &status, 1) < 1)
808 {
809 fprintf(stderr, "WARNING: Remote host did not respond with control "
810 "status byte after %d seconds!\n", timeout);
25037b2b 811 status = errno;
55737cf0 812 }
25037b2b 813
814 alarm(0);
815 }
816
817 if (status != 0)
818 fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n",
819 status);
820 else
821 fputs("INFO: Control file sent successfully\n", stderr);
f8529e1a 822 }
f8529e1a 823
25037b2b 824 /*
825 * Close the socket connection and input file...
826 */
827
828 close(fd);
829 fclose(fp);
830
831 if (status == 0)
1aef57ed 832 return (0);
f8529e1a 833
1aef57ed 834 /*
55737cf0 835 * Waiting for a retry...
1aef57ed 836 */
e73c6c0a 837
1aef57ed 838 sleep(30);
839 }
25037b2b 840}
841
842
843/*
844 * 'lpd_timeout()' - Handle timeout alarms...
845 */
846
847static void
55737cf0 848lpd_timeout(int sig) /* I - Signal number */
25037b2b 849{
850 (void)sig;
851
852#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
853 signal(SIGALRM, lpd_timeout);
854#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
e73c6c0a 855}
43e2fc22 856
857
858/*
f8529e1a 859 * 'lpd_write()' - Write a buffer of data to an LPD server.
860 */
861
55737cf0 862static int /* O - Number of bytes written or -1 on error */
863lpd_write(int lpd_fd, /* I - LPD socket */
864 char *buffer, /* I - Buffer to write */
865 int length) /* I - Number of bytes to write */
f8529e1a 866{
55737cf0 867 int bytes, /* Number of bytes written */
868 total; /* Total number of bytes written */
f8529e1a 869
870
871 total = 0;
872 while ((bytes = send(lpd_fd, buffer, length - total, 0)) >= 0)
873 {
874 total += bytes;
875 buffer += bytes;
876
877 if (total == length)
878 break;
879 }
880
881 if (bytes < 0)
882 return (-1);
883 else
884 return (length);
885}
886
887
c3026ddc 888#ifndef HAVE_RRESVPORT
f8529e1a 889/*
c3026ddc 890 * 'rresvport()' - A simple implementation of rresvport().
891 */
892
55737cf0 893int /* O - Socket or -1 on error */
894rresvport(int *port) /* IO - Port number to bind to */
c3026ddc 895{
55737cf0 896 struct sockaddr_in addr; /* Socket address */
897 int fd; /* Socket file descriptor */
c3026ddc 898
899
900 /*
901 * Try to create an IPv4 socket...
902 */
903
904 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
905 return (-1);
906
907 /*
908 * Initialize the address buffer...
909 */
910
911 memset(&addr, 0, sizeof(addr));
912
913 addr.sin_family = AF_INET;
914 addr.sin_addr.s_addr = INADDR_ANY;
915
916 /*
917 * Try to bind the socket to a reserved port; unlike the standard
918 * BSD rresvport(), we limit the port number to 721 through 732
919 * (instead of 512 to 1023) since RFC 1179 defines the local port
920 * number between 721 and 732...
921 */
922
923 while (*port > 720)
924 {
925 /*
926 * Set the port number...
927 */
928
929 addr.sin_port = htons(*port);
930
931 /*
932 * Try binding the port to the socket; return if all is OK...
933 */
934
935 if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
936 return (fd);
937
938 /*
939 * Stop if we have any error other than "address already in use"...
940 */
941
942 if (errno != EADDRINUSE)
943 {
944# ifdef WIN32
945 closesocket(fd);
946# else
947 close(fd);
948# endif /* WIN32 */
949
950 return (-1);
951 }
952
953 /*
954 * Try the next port...
955 */
956
957 (*port)--;
958 }
959
960 /*
961 * Wasn't able to bind to a reserved port, so close the socket and return
962 * -1...
963 */
964
965# ifdef WIN32
966 closesocket(fd);
967# else
968 close(fd);
969# endif /* WIN32 */
970
971 return (-1);
972}
973#endif /* !HAVE_RRESVPORT */
974
55737cf0 975
976/*
977 * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
978 */
979
980static void
981sigterm_handler(int sig) /* I - Signal */
982{
983 (void)sig; /* remove compiler warnings... */
984
985 /*
986 * Remove the temporary file if necessary...
987 */
988
989 if (tmpfilename[0])
990 unlink(tmpfilename);
991
992 exit(1);
993}
994
995
c3026ddc 996/*
2d417cb3 997 * End of "$Id: lpd.c,v 1.28.2.25 2003/10/09 19:13:48 mike Exp $".
43e2fc22 998 */