]>
git.ipfire.org Git - thirdparty/cups.git/blob - backend/lpd.c
2 * "$Id: lpd.c,v 1.28.2.17 2002/11/27 15:15:14 mike Exp $"
4 * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2002 by Easy Software Products, all rights reserved.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
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.
36 * Include necessary headers.
39 #include <cups/cups.h>
44 #include <cups/string.h>
46 #include <sys/types.h>
53 # include <sys/socket.h>
54 # include <netinet/in.h>
55 # include <arpa/inet.h>
61 * The order for control and data files in LPD requests...
64 #define ORDER_CONTROL_DATA 0
65 #define ORDER_DATA_CONTROL 1
69 * It appears that rresvport() is never declared on most systems...
72 extern int rresvport(int *port
);
79 static int lpd_command(int lpd_fd
, char *format
, ...);
80 static int lpd_queue(char *hostname
, char *printer
, char *filename
,
81 int fromstdin
, char *user
, char *title
, int copies
,
82 int banner
, int format
, int order
, int reserve
,
84 static void lpd_timeout(int sig
);
85 static int lpd_write(int lpd_fd
, char *buffer
, int length
);
89 * 'main()' - Send a file to the printer or server.
93 * printer-uri job-id user title copies options [file]
96 int /* O - Exit status */
97 main(int argc
, /* I - Number of command-line arguments (6 or 7) */
98 char *argv
[]) /* I - Command-line arguments */
100 char method
[255], /* Method in URI */
101 hostname
[1024], /* Hostname */
102 username
[255], /* Username info (not used) */
103 resource
[1024], /* Resource info (printer name) */
104 *options
, /* Pointer to options */
105 name
[255], /* Name of option */
106 value
[255], /* Value of option */
107 *ptr
, /* Pointer into name or value */
108 filename
[1024], /* File to print */
109 title
[256]; /* Title string */
110 int port
; /* Port number (not used) */
111 int status
; /* Status of LPD job */
112 int banner
; /* Print banner page? */
113 int format
; /* Print format */
114 int order
; /* Order of control/data files */
115 int reserve
; /* Reserve priviledged port? */
116 int manual_copies
, /* Do manual copies? */
117 copies
; /* Number of copies */
118 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
119 struct sigaction action
;
120 /* Actions for POSIX signals */
121 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
125 * Make sure status messages are not buffered...
128 setbuf(stderr
, NULL
);
131 * Ignore SIGPIPE signals...
135 sigset(SIGPIPE
, SIG_IGN
);
136 #elif defined(HAVE_SIGACTION)
137 memset(&action
, 0, sizeof(action
));
138 action
.sa_handler
= SIG_IGN
;
139 sigaction(SIGPIPE
, &action
, NULL
);
141 signal(SIGPIPE
, SIG_IGN
);
142 #endif /* HAVE_SIGSET */
145 * Check command-line...
150 puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\"");
153 else if (argc
< 6 || argc
> 7)
155 fprintf(stderr
, "Usage: %s job-id user title copies options [file]\n",
161 * If we have 7 arguments, print the file named on the command-line.
162 * Otherwise, copy stdin to a temporary file and print the temporary
169 * Copy stdin to a temporary file...
172 int fd
; /* Temporary file */
173 char buffer
[8192]; /* Buffer for copying */
174 int bytes
; /* Number of bytes read */
177 if ((fd
= cupsTempFd(filename
, sizeof(filename
))) < 0)
179 perror("ERROR: unable to create temporary file");
183 while ((bytes
= fread(buffer
, 1, sizeof(buffer
), stdin
)) > 0)
184 if (write(fd
, buffer
, bytes
) < bytes
)
186 perror("ERROR: unable to write to temporary file");
195 strlcpy(filename
, argv
[6], sizeof(filename
));
198 * Extract the hostname and printer name from the URI...
201 httpSeparate(argv
[0], method
, username
, hostname
, &port
, resource
);
204 * See if there are any options...
209 order
= ORDER_CONTROL_DATA
;
213 if ((options
= strchr(resource
, '?')) != NULL
)
216 * Yup, terminate the device name string and move to the first
217 * character of the options...
232 for (ptr
= name
; *options
&& *options
!= '=';)
244 for (ptr
= value
; *options
&& *options
!= '+';)
255 * Process the option...
258 if (strcasecmp(name
, "banner") == 0)
264 banner
= !value
[0] ||
265 strcasecmp(value
, "on") == 0 ||
266 strcasecmp(value
, "yes") == 0 ||
267 strcasecmp(value
, "true") == 0;
269 else if (strcasecmp(name
, "format") == 0 && value
[0])
272 * Set output format...
275 if (strchr("cdfglnoprtv", value
[0]) != NULL
)
278 fprintf(stderr
, "ERROR: Unknown format character \"%c\"\n", value
[0]);
280 else if (strcasecmp(name
, "order") == 0 && value
[0])
283 * Set control/data order...
286 if (strcasecmp(value
, "control,data") == 0)
287 order
= ORDER_CONTROL_DATA
;
288 else if (strcasecmp(value
, "data,control") == 0)
289 order
= ORDER_DATA_CONTROL
;
291 fprintf(stderr
, "ERROR: Unknown file order \"%s\"\n", value
);
293 else if (strcasecmp(name
, "reserve") == 0)
296 * Set port reservation mode...
299 reserve
= !value
[0] ||
300 strcasecmp(value
, "on") == 0 ||
301 strcasecmp(value
, "yes") == 0 ||
302 strcasecmp(value
, "true") == 0;
304 else if (strcasecmp(name
, "manual_copies") == 0)
307 * Set port reservation mode...
310 manual_copies
= !value
[0] ||
311 strcasecmp(value
, "on") == 0 ||
312 strcasecmp(value
, "yes") == 0 ||
313 strcasecmp(value
, "true") == 0;
319 * Sanitize the document title...
322 strlcpy(title
, argv
[3], sizeof(title
));
324 for (ptr
= title
; *ptr
; ptr
++)
325 if (!isalnum(*ptr
) && !isspace(*ptr
))
336 manual_copies
= atoi(argv
[4]);
342 copies
= atoi(argv
[4]);
345 status
= lpd_queue(hostname
, resource
+ 1, filename
, 0,
346 argv
[2] /* user */, title
, copies
,
347 banner
, format
, order
, reserve
, manual_copies
);
350 fprintf(stderr
, "PAGE: 1 %d\n", atoi(argv
[4]));
353 status
= lpd_queue(hostname
, resource
+ 1, filename
, 1,
354 argv
[2] /* user */, title
, 1,
355 banner
, format
, order
, reserve
, 1);
358 * Remove the temporary file if necessary...
365 * Return the queue status...
373 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
376 static int /* O - Status of command */
377 lpd_command(int fd
, /* I - Socket connection to LPD host */
378 char *format
, /* I - printf()-style format string */
379 ...) /* I - Additional args as necessary */
381 va_list ap
; /* Argument pointer */
382 char buf
[1024]; /* Output buffer */
383 int bytes
; /* Number of bytes to output */
384 char status
; /* Status from command */
388 * Format the string...
391 va_start(ap
, format
);
392 bytes
= vsnprintf(buf
, sizeof(buf
), format
, ap
);
395 fprintf(stderr
, "DEBUG: lpd_command %2.2x %s", buf
[0], buf
+ 1);
398 * Send the command...
401 fprintf(stderr
, "DEBUG: Sending command string (%d bytes)...\n", bytes
);
405 if (lpd_write(fd
, buf
, bytes
) < bytes
)
409 * Read back the status from the command and return it...
412 fprintf(stderr
, "DEBUG: Reading command status...\n");
416 if (recv(fd
, &status
, 1, 0) < 1)
421 fprintf(stderr
, "DEBUG: lpd_command returning %d\n", status
);
428 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
431 static int /* O - Zero on success, non-zero on failure */
432 lpd_queue(char *hostname
, /* I - Host to connect to */
433 char *printer
, /* I - Printer/queue name */
434 char *filename
, /* I - File to print */
435 int fromstdin
, /* I - Printing from stdin? */
436 char *user
, /* I - Requesting user */
437 char *title
, /* I - Job title */
438 int copies
, /* I - Number of copies */
439 int banner
, /* I - Print LPD banner? */
440 int format
, /* I - Format specifier */
441 int order
, /* I - Order of data/control files */
442 int reserve
, /* I - Reserve ports? */
443 int manual_copies
) /* I - Do copies by hand... */
445 FILE *fp
; /* Job file */
446 char localhost
[255]; /* Local host name */
447 int error
; /* Error number */
448 struct stat filestats
; /* File statistics */
449 int port
; /* LPD connection port */
450 int fd
; /* LPD socket */
451 char control
[10240], /* LPD control 'file' */
452 *cptr
; /* Pointer into control file string */
453 char status
; /* Status byte from command */
454 struct sockaddr_in addr
; /* Socket address */
455 struct hostent
*hostaddr
; /* Host address */
456 int copy
; /* Copies written */
457 size_t nbytes
, /* Number of bytes written */
458 tbytes
; /* Total bytes written */
459 char buffer
[8192]; /* Output buffer */
460 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
461 struct sigaction action
; /* Actions for POSIX signals */
462 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
466 * Setup an alarm handler for timeouts...
469 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
470 sigset(SIGALRM
, lpd_timeout
);
471 #elif defined(HAVE_SIGACTION)
472 memset(&action
, 0, sizeof(action
));
474 sigemptyset(&action
.sa_mask
);
475 action
.sa_handler
= lpd_timeout
;
476 sigaction(SIGALRM
, &action
, NULL
);
478 signal(SIGALRM
, lpd_timeout
);
479 #endif /* HAVE_SIGSET */
482 * Loop forever trying to print the file...
485 for (;;) /* FOREVER */
488 * First try to reserve a port for this connection...
491 if ((hostaddr
= httpGetHostByName(hostname
)) == NULL
)
493 fprintf(stderr
, "ERROR: Unable to locate printer \'%s\' - %s\n",
494 hostname
, strerror(errno
));
498 fprintf(stderr
, "INFO: Attempting to connect to host %s for printer %s\n",
501 memset(&addr
, 0, sizeof(addr
));
502 memcpy(&(addr
.sin_addr
), hostaddr
->h_addr
, hostaddr
->h_length
);
503 addr
.sin_family
= hostaddr
->h_addrtype
;
504 addr
.sin_port
= htons(515); /* LPD/printer service */
508 if (getuid() || !reserve
)
511 * Just create a regular socket...
514 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0)
516 perror("ERROR: Unable to create socket");
525 * We're running as root and want to comply with RFC 1179. Reserve a
526 * priviledged port between 721 and 732...
529 if ((fd
= rresvport(&port
)) < 0)
531 perror("ERROR: Unable to reserve port");
537 if (connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
543 if (error
== ECONNREFUSED
|| error
== EHOSTDOWN
||
544 error
== EHOSTUNREACH
)
546 fprintf(stderr
, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n",
550 else if (error
== EADDRINUSE
)
558 perror("ERROR: Unable to connect to printer");
566 fprintf(stderr
, "INFO: Connected from port %d...\n", port
);
569 * Now that we are "connected" to the port, ignore SIGTERM so that we
570 * can finish out any page data the driver sends (e.g. to eject the
571 * current page... Only ignore SIGTERM if we are printing data from
572 * stdin (otherwise you can't cancel raw jobs...)
577 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
578 sigset(SIGTERM
, SIG_IGN
);
579 #elif defined(HAVE_SIGACTION)
580 memset(&action
, 0, sizeof(action
));
582 sigemptyset(&action
.sa_mask
);
583 action
.sa_handler
= SIG_IGN
;
584 sigaction(SIGTERM
, &action
, NULL
);
586 signal(SIGTERM
, SIG_IGN
);
587 #endif /* HAVE_SIGSET */
591 * Next, open the print file and figure out its size...
594 if (stat(filename
, &filestats
))
596 perror("ERROR: unable to stat print file");
600 filestats
.st_size
*= manual_copies
;
602 if ((fp
= fopen(filename
, "rb")) == NULL
)
604 perror("ERROR: unable to open print file for reading");
609 * Send a job header to the printer, specifying no banner page and
613 lpd_command(fd
, "\002%s\n", printer
); /* Receive print job(s) */
615 gethostname(localhost
, sizeof(localhost
));
616 localhost
[31] = '\0'; /* RFC 1179, Section 7.2 - host name < 32 chars */
618 snprintf(control
, sizeof(control
), "H%s\nP%s\nJ%s\n", localhost
, user
, title
);
619 cptr
= control
+ strlen(control
);
623 snprintf(cptr
, sizeof(control
) - (cptr
- control
), "L%s\n", user
);
624 cptr
+= strlen(cptr
);
629 snprintf(cptr
, sizeof(control
) - (cptr
- control
), "%cdfA%03d%s\n", format
,
630 getpid() % 1000, localhost
);
631 cptr
+= strlen(cptr
);
635 snprintf(cptr
, sizeof(control
) - (cptr
- control
),
637 getpid() % 1000, localhost
, title
);
639 fprintf(stderr
, "DEBUG: Control file is:\n%s", control
);
641 if (order
== ORDER_CONTROL_DATA
)
643 lpd_command(fd
, "\002%d cfA%03.3d%s\n", strlen(control
), getpid() % 1000,
646 fprintf(stderr
, "INFO: Sending control file (%lu bytes)\n",
647 (unsigned long)strlen(control
));
651 if (lpd_write(fd
, control
, strlen(control
) + 1) < (strlen(control
) + 1))
654 perror("ERROR: Unable to write control file");
660 if (read(fd
, &status
, 1) < 1)
667 fprintf(stderr
, "ERROR: Remote host did not accept control file (%d)\n",
670 fputs("INFO: Control file sent successfully\n", stderr
);
678 * Send the print file...
681 lpd_command(fd
, "\003%u dfA%03.3d%s\n", (unsigned)filestats
.st_size
,
682 getpid() % 1000, localhost
);
684 fprintf(stderr
, "INFO: Sending data file (%u bytes)\n",
685 (unsigned)filestats
.st_size
);
688 for (copy
= 0; copy
< manual_copies
; copy
++)
692 while ((nbytes
= fread(buffer
, 1, sizeof(buffer
), fp
)) > 0)
694 fprintf(stderr
, "INFO: Spooling LPR job, %u%% complete...\n",
695 (unsigned)(100.0f
* tbytes
/ filestats
.st_size
));
697 if (lpd_write(fd
, buffer
, nbytes
) < nbytes
)
699 perror("ERROR: Unable to send print file to printer");
707 if (tbytes
< filestats
.st_size
)
709 else if (lpd_write(fd
, "", 1) < 1)
715 if (recv(fd
, &status
, 1, 0) < 1)
722 fprintf(stderr
, "ERROR: Remote host did not accept data file (%d)\n",
725 fputs("INFO: Data file sent successfully\n", stderr
);
728 if (status
== 0 && order
== ORDER_DATA_CONTROL
)
730 lpd_command(fd
, "\002%d cfA%03.3d%s\n", strlen(control
), getpid() % 1000,
733 fprintf(stderr
, "INFO: Sending control file (%lu bytes)\n",
734 (unsigned long)strlen(control
));
738 if (lpd_write(fd
, control
, strlen(control
) + 1) < (strlen(control
) + 1))
741 perror("ERROR: Unable to write control file");
747 if (read(fd
, &status
, 1) < 1)
754 fprintf(stderr
, "ERROR: Remote host did not accept control file (%d)\n",
757 fputs("INFO: Control file sent successfully\n", stderr
);
761 * Close the socket connection and input file...
771 * Restore the SIGTERM handler if we are waiting for a retry...
776 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
777 sigset(SIGTERM
, SIG_DFL
);
778 #elif defined(HAVE_SIGACTION)
779 memset(&action
, 0, sizeof(action
));
781 sigemptyset(&action
.sa_mask
);
782 action
.sa_handler
= SIG_DFL
;
783 sigaction(SIGTERM
, &action
, NULL
);
785 signal(SIGTERM
, SIG_DFL
);
786 #endif /* HAVE_SIGSET */
795 * 'lpd_timeout()' - Handle timeout alarms...
799 lpd_timeout(int sig
) /* I - Signal number */
803 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
804 signal(SIGALRM
, lpd_timeout
);
805 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
810 * 'lpd_write()' - Write a buffer of data to an LPD server.
813 static int /* O - Number of bytes written or -1 on error */
814 lpd_write(int lpd_fd
, /* I - LPD socket */
815 char *buffer
, /* I - Buffer to write */
816 int length
) /* I - Number of bytes to write */
818 int bytes
, /* Number of bytes written */
819 total
; /* Total number of bytes written */
823 while ((bytes
= send(lpd_fd
, buffer
, length
- total
, 0)) >= 0)
839 #ifndef HAVE_RRESVPORT
841 * 'rresvport()' - A simple implementation of rresvport().
844 int /* O - Socket or -1 on error */
845 rresvport(int *port
) /* IO - Port number to bind to */
847 struct sockaddr_in addr
; /* Socket address */
848 int fd
; /* Socket file descriptor */
852 * Try to create an IPv4 socket...
855 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0)
859 * Initialize the address buffer...
862 memset(&addr
, 0, sizeof(addr
));
864 addr
.sin_family
= AF_INET
;
865 addr
.sin_addr
.s_addr
= INADDR_ANY
;
868 * Try to bind the socket to a reserved port; unlike the standard
869 * BSD rresvport(), we limit the port number to 721 through 732
870 * (instead of 512 to 1023) since RFC 1179 defines the local port
871 * number between 721 and 732...
877 * Set the port number...
880 addr
.sin_port
= htons(*port
);
883 * Try binding the port to the socket; return if all is OK...
886 if (!bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
)))
890 * Stop if we have any error other than "address already in use"...
893 if (errno
!= EADDRINUSE
)
905 * Try the next port...
912 * Wasn't able to bind to a reserved port, so close the socket and return
924 #endif /* !HAVE_RRESVPORT */
927 * End of "$Id: lpd.c,v 1.28.2.17 2002/11/27 15:15:14 mike Exp $".