]>
git.ipfire.org Git - thirdparty/cups.git/blob - backend/lpd.c
4 * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2001 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
26 * main() - Send a file to the printer or server.
27 * lpd_command() - Send an LPR command sequence and wait for a reply.
28 * lpd_queue() - Queue a file using the Line Printer Daemon protocol.
29 * lpd_write() - Write a buffer of data to an LPD server.
33 * Include necessary headers.
36 #include <cups/cups.h>
41 #include <cups/string.h>
43 #include <sys/types.h>
47 #if defined(WIN32) || defined(__EMX__)
50 # include <sys/socket.h>
51 # include <netinet/in.h>
52 # include <arpa/inet.h>
54 #endif /* WIN32 || __EMX__ */
58 * The order for control and data files in LPD requests...
61 #define ORDER_CONTROL_DATA 0
62 #define ORDER_DATA_CONTROL 1
66 * It appears that rresvport() is never declared on most systems...
69 extern int rresvport(int *port
);
76 static int lpd_command(int lpd_fd
, char *format
, ...);
77 static int lpd_queue(char *hostname
, char *printer
, char *filename
,
78 int fromstdin
, char *user
, char *title
, int copies
,
79 int banner
, int format
, int order
);
80 static int lpd_write(int lpd_fd
, char *buffer
, int length
);
84 * 'main()' - Send a file to the printer or server.
88 * printer-uri job-id user title copies options [file]
91 int /* O - Exit status */
92 main(int argc
, /* I - Number of command-line arguments (6 or 7) */
93 char *argv
[]) /* I - Command-line arguments */
95 char method
[255], /* Method in URI */
96 hostname
[1024], /* Hostname */
97 username
[255], /* Username info (not used) */
98 resource
[1024], /* Resource info (printer name) */
99 *options
, /* Pointer to options */
100 name
[255], /* Name of option */
101 value
[255], /* Value of option */
102 *ptr
, /* Pointer into name or value */
103 filename
[1024], /* File to print */
104 title
[256]; /* Title string */
105 int port
; /* Port number (not used) */
106 int status
; /* Status of LPD job */
107 int banner
; /* Print banner page? */
108 int format
; /* Print format */
109 int order
; /* Order of control/data files */
113 * Make sure status messages are not buffered...
116 setbuf(stderr
, NULL
);
119 * Check command-line...
124 puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\"");
127 else if (argc
< 6 || argc
> 7)
129 fprintf(stderr
, "Usage: %s job-id user title copies options [file]\n",
135 * If we have 7 arguments, print the file named on the command-line.
136 * Otherwise, copy stdin to a temporary file and print the temporary
143 * Copy stdin to a temporary file...
146 int fd
; /* Temporary file */
147 char buffer
[8192]; /* Buffer for copying */
148 int bytes
; /* Number of bytes read */
151 if ((fd
= cupsTempFd(filename
, sizeof(filename
))) < 0)
153 perror("ERROR: unable to create temporary file");
157 while ((bytes
= fread(buffer
, 1, sizeof(buffer
), stdin
)) > 0)
158 if (write(fd
, buffer
, bytes
) < bytes
)
160 perror("ERROR: unable to write to temporary file");
170 strncpy(filename
, argv
[6], sizeof(filename
) - 1);
171 filename
[sizeof(filename
) - 1] = '\0';
175 * Extract the hostname and printer name from the URI...
178 httpSeparate(argv
[0], method
, username
, hostname
, &port
, resource
);
181 * See if there are any options...
186 order
= ORDER_CONTROL_DATA
;
188 if ((options
= strchr(resource
, '?')) != NULL
)
191 * Yup, terminate the device name string and move to the first
192 * character of the options...
207 for (ptr
= name
; *options
&& *options
!= '=';)
219 for (ptr
= value
; *options
&& *options
!= '+';)
230 * Process the option...
233 if (strcasecmp(name
, "banner") == 0)
239 banner
= !value
[0] ||
240 strcasecmp(value
, "on") == 0 ||
241 strcasecmp(value
, "yes") == 0 ||
242 strcasecmp(value
, "true") == 0;
244 else if (strcasecmp(name
, "format") == 0 && value
[0])
247 * Set output format...
250 if (strchr("cdfglnoprtv", value
[0]) != NULL
)
253 fprintf(stderr
, "ERROR: Unknown format character \"%c\"\n", value
[0]);
255 else if (strcasecmp(name
, "order") == 0 && value
[0])
258 * Set control/data order...
261 if (strcasecmp(value
, "control,data") == 0)
262 order
= ORDER_CONTROL_DATA
;
263 else if (strcasecmp(value
, "data,control") == 0)
264 order
= ORDER_DATA_CONTROL
;
266 fprintf(stderr
, "ERROR: Unknown file order \"%s\"\n", value
);
272 * Sanitize the document title...
275 strncpy(title
, argv
[3], sizeof(title
) - 1);
276 title
[sizeof(title
) - 1] = '\0';
278 for (ptr
= title
; *ptr
; ptr
++)
279 if (!isalnum(*ptr
) && !isspace(*ptr
))
288 status
= lpd_queue(hostname
, resource
+ 1, filename
, 0,
289 argv
[2] /* user */, title
, atoi(argv
[4]) /* copies */,
290 banner
, format
, order
);
293 fprintf(stderr
, "PAGE: 1 %d\n", atoi(argv
[4]));
296 status
= lpd_queue(hostname
, resource
+ 1, filename
, 1,
297 argv
[2] /* user */, title
, 1, banner
, format
, order
);
300 * Remove the temporary file if necessary...
307 * Return the queue status...
315 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
318 static int /* O - Status of command */
319 lpd_command(int fd
, /* I - Socket connection to LPD host */
320 char *format
, /* I - printf()-style format string */
321 ...) /* I - Additional args as necessary */
323 va_list ap
; /* Argument pointer */
324 char buf
[1024]; /* Output buffer */
325 int bytes
; /* Number of bytes to output */
326 char status
; /* Status from command */
330 * Format the string...
333 va_start(ap
, format
);
334 bytes
= vsnprintf(buf
, sizeof(buf
), format
, ap
);
337 fprintf(stderr
, "DEBUG: lpd_command %2.2x %s", buf
[0], buf
+ 1);
340 * Send the command...
343 fprintf(stderr
, "DEBUG: Sending command string (%d bytes)...\n", bytes
);
345 if (lpd_write(fd
, buf
, bytes
) < bytes
)
349 * Read back the status from the command and return it...
352 fprintf(stderr
, "DEBUG: Reading command status...\n");
354 if (recv(fd
, &status
, 1, 0) < 1)
357 fprintf(stderr
, "DEBUG: lpd_command returning %d\n", status
);
364 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
367 static int /* O - Zero on success, non-zero on failure */
368 lpd_queue(char *hostname
, /* I - Host to connect to */
369 char *printer
, /* I - Printer/queue name */
370 char *filename
, /* I - File to print */
371 int fromstdin
, /* I - Printing from stdin? */
372 char *user
, /* I - Requesting user */
373 char *title
, /* I - Job title */
374 int copies
, /* I - Number of copies */
375 int banner
, /* I - Print LPD banner? */
376 int format
, /* I - Format specifier */
377 int order
) /* I - Order of data/control files */
379 FILE *fp
; /* Job file */
380 char localhost
[255]; /* Local host name */
381 int error
; /* Error number */
382 struct stat filestats
; /* File statistics */
383 int port
; /* LPD connection port */
384 int fd
; /* LPD socket */
385 char control
[10240], /* LPD control 'file' */
386 *cptr
; /* Pointer into control file string */
387 char status
; /* Status byte from command */
388 struct sockaddr_in addr
; /* Socket address */
389 struct hostent
*hostaddr
; /* Host address */
390 size_t nbytes
, /* Number of bytes written */
391 tbytes
; /* Total bytes written */
392 char buffer
[8192]; /* Output buffer */
393 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
394 struct sigaction action
; /* Actions for POSIX signals */
395 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
399 * First try to reserve a port for this connection...
402 if ((hostaddr
= gethostbyname(hostname
)) == NULL
)
404 fprintf(stderr
, "ERROR: Unable to locate printer \'%s\' - %s",
405 hostname
, strerror(errno
));
409 fprintf(stderr
, "INFO: Attempting to connect to host %s for printer %s\n",
412 memset(&addr
, 0, sizeof(addr
));
413 memcpy(&(addr
.sin_addr
), hostaddr
->h_addr
, hostaddr
->h_length
);
414 addr
.sin_family
= hostaddr
->h_addrtype
;
415 addr
.sin_port
= htons(515); /* LPD/printer service */
422 * We're running as a normal user, so just create a regular socket...
425 if ((fd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0)
427 perror("ERROR: Unable to create socket");
434 * We're running as root, so comply with RFC 1179 and reserve a
435 * priviledged port between 721 and 732...
438 if ((fd
= rresvport(&port
)) < 0)
440 perror("ERROR: Unable to reserve port");
446 if (connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
452 if (error
== ECONNREFUSED
)
454 fprintf(stderr
, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...",
458 else if (error
== EADDRINUSE
)
466 perror("ERROR: Unable to connect to printer");
474 fprintf(stderr
, "INFO: Connected from port %d...\n", port
);
477 * Now that we are "connected" to the port, ignore SIGTERM so that we
478 * can finish out any page data the driver sends (e.g. to eject the
479 * current page... Only ignore SIGTERM if we are printing data from
480 * stdin (otherwise you can't cancel raw jobs...)
485 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
486 sigset(SIGTERM
, SIG_IGN
);
487 #elif defined(HAVE_SIGACTION)
488 memset(&action
, 0, sizeof(action
));
490 sigemptyset(&action
.sa_mask
);
491 action
.sa_handler
= SIG_IGN
;
492 sigaction(SIGTERM
, &action
, NULL
);
494 signal(SIGTERM
, SIG_IGN
);
495 #endif /* HAVE_SIGSET */
499 * Next, open the print file and figure out its size...
502 if (stat(filename
, &filestats
))
504 perror("ERROR: unable to stat print file");
508 if ((fp
= fopen(filename
, "rb")) == NULL
)
510 perror("ERROR: unable to open print file for reading");
515 * Send a job header to the printer, specifying no banner page and
519 lpd_command(fd
, "\002%s\n", printer
); /* Receive print job(s) */
521 gethostname(localhost
, sizeof(localhost
));
522 localhost
[31] = '\0'; /* RFC 1179, Section 7.2 - host name < 32 chars */
524 snprintf(control
, sizeof(control
), "H%s\nP%s\nJ%s\n", localhost
, user
, title
);
525 cptr
= control
+ strlen(control
);
529 snprintf(cptr
, sizeof(control
) - (cptr
- control
), "L%s\n", user
);
530 cptr
+= strlen(cptr
);
535 snprintf(cptr
, sizeof(control
) - (cptr
- control
), "%cdfA%03d%s\n", format
,
536 getpid() % 1000, localhost
);
537 cptr
+= strlen(cptr
);
541 snprintf(cptr
, sizeof(control
) - (cptr
- control
),
542 "UdfA%03d%s\nNdfA%03d%s\n",
543 getpid() % 1000, localhost
,
544 getpid() % 1000, localhost
);
546 fprintf(stderr
, "DEBUG: Control file is:\n%s", control
);
548 if (order
== ORDER_CONTROL_DATA
)
550 lpd_command(fd
, "\002%d cfA%03.3d%s\n", strlen(control
), getpid() % 1000,
553 fprintf(stderr
, "INFO: Sending control file (%d bytes)\n", strlen(control
));
555 if (lpd_write(fd
, control
, strlen(control
) + 1) < (strlen(control
) + 1))
558 perror("ERROR: Unable to write control file");
560 else if (read(fd
, &status
, 1) < 1)
564 fprintf(stderr
, "ERROR: Remote host did not accept control file (%d)\n",
567 fputs("INFO: Control file sent successfully\n", stderr
);
575 * Send the print file...
578 lpd_command(fd
, "\003%u dfA%03.3d%s\n", (unsigned)filestats
.st_size
,
579 getpid() % 1000, localhost
);
581 fprintf(stderr
, "INFO: Sending data file (%u bytes)\n",
582 (unsigned)filestats
.st_size
);
585 while ((nbytes
= fread(buffer
, 1, sizeof(buffer
), fp
)) > 0)
587 fprintf(stderr
, "INFO: Spooling LPR job, %u%% complete...\n",
588 (unsigned)(100.0f
* tbytes
/ filestats
.st_size
));
590 if (lpd_write(fd
, buffer
, nbytes
) < nbytes
)
592 perror("ERROR: Unable to send print file to printer");
599 if (tbytes
< filestats
.st_size
)
601 else if (lpd_write(fd
, "", 1) < 1)
603 else if (recv(fd
, &status
, 1, 0) < 1)
607 fprintf(stderr
, "ERROR: Remote host did not accept data file (%d)\n",
610 fputs("INFO: Data file sent successfully\n", stderr
);
613 if (status
== 0 && order
== ORDER_DATA_CONTROL
)
615 lpd_command(fd
, "\002%d cfA%03.3d%s\n", strlen(control
), getpid() % 1000,
618 fprintf(stderr
, "INFO: Sending control file (%d bytes)\n", strlen(control
));
620 if (lpd_write(fd
, control
, strlen(control
) + 1) < (strlen(control
) + 1))
623 perror("ERROR: Unable to write control file");
625 else if (read(fd
, &status
, 1) < 1)
629 fprintf(stderr
, "ERROR: Remote host did not accept control file (%d)\n",
632 fputs("INFO: Control file sent successfully\n", stderr
);
636 * Close the socket connection and input file and return...
647 * 'lpd_write()' - Write a buffer of data to an LPD server.
650 static int /* O - Number of bytes written or -1 on error */
651 lpd_write(int lpd_fd
, /* I - LPD socket */
652 char *buffer
, /* I - Buffer to write */
653 int length
) /* I - Number of bytes to write */
655 int bytes
, /* Number of bytes written */
656 total
; /* Total number of bytes written */
660 while ((bytes
= send(lpd_fd
, buffer
, length
- total
, 0)) >= 0)