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