]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/lpd.c
Now only send # bytes if a raw job is being sent.
[thirdparty/cups.git] / backend / lpd.c
CommitLineData
43e2fc22 1/*
decc1f36 2 * "$Id: lpd.c,v 1.4 1999/04/21 15:02:00 mike Exp $"
43e2fc22 3 *
e73c6c0a 4 * Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
43e2fc22 5 *
3a193f5e 6 * Copyright 1997-1999 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
17 * 44145 Airport View Drive, Suite 204
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 *
24 * Contents:
25 *
decc1f36 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.
e73c6c0a 29 */
30
31/*
32 * Include necessary headers.
33 */
34
35#include <cups/cups.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <stdarg.h>
39#include <cups/string.h>
40#include <errno.h>
41#include <sys/types.h>
42#include <sys/stat.h>
43
44#if defined(WIN32) || defined(__EMX__)
45# include <winsock.h>
46#else
47# include <sys/socket.h>
48# include <netinet/in.h>
49# include <arpa/inet.h>
50# include <netdb.h>
51#endif /* WIN32 || __EMX__ */
52
53extern int rresvport(int *port); /* Hello? No prototype for this... */
54
55
56/*
57 * Local functions...
58 */
59
60static int lpd_command(int lpd_fd, char *format, ...);
61static int lpd_queue(char *hostname, char *printer, char *filename,
62 char *user, int copies);
63
64
65/*
66 * 'main()' - Send a file to the printer or server.
43e2fc22 67 *
e73c6c0a 68 * Usage:
43e2fc22 69 *
e73c6c0a 70 * printer-uri job-id user title copies options [file]
43e2fc22 71 */
72
e73c6c0a 73int /* O - Exit status */
74main(int argc, /* I - Number of command-line arguments (6 or 7) */
75 char *argv[]) /* I - Command-line arguments */
76{
77 char method[255], /* Method in URI */
78 hostname[1024], /* Hostname */
79 username[255], /* Username info (not used) */
80 resource[1024], /* Resource info (printer name) */
81 filename[1024]; /* File to print */
82 int port; /* Port number (not used) */
83 int status; /* Status of LPD job */
84
85
86 if (argc < 6 || argc > 7)
87 {
88 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
89 argv[0]);
90 return (1);
91 }
92
93 /*
94 * If we have 7 arguments, print the file named on the command-line.
95 * Otherwise, copy stdin to a temporary file and print the temporary
96 * file.
97 */
98
99 if (argc == 6)
100 {
101 /*
102 * Copy stdin to a temporary file...
103 */
104
105 FILE *fp; /* Temporary file */
106 char buffer[8192]; /* Buffer for copying */
107 int bytes; /* Number of bytes read */
108
109
110 if ((fp = fopen(tmpnam(filename), "w")) == NULL)
111 {
decc1f36 112 perror("lpd: unable to create temporary file");
e73c6c0a 113 return (1);
114 }
115
116 while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
117 if (fwrite(buffer, 1, bytes, fp) < bytes)
118 {
decc1f36 119 perror("lpd: unable to write to temporary file");
e73c6c0a 120 fclose(fp);
121 unlink(filename);
122 return (1);
123 }
124
125 fclose(fp);
126 }
127 else
128 strcpy(filename, argv[6]);
129
130 /*
131 * Extract the hostname and printer name from the URI...
132 */
133
134 httpSeparate(argv[0], method, username, hostname, &port, resource);
135
136 /*
137 * Queue the job...
138 */
139
140 status = lpd_queue(hostname, resource + 1, filename,
141 argv[2] /* user */, atoi(argv[4]) /* copies */);
142
143 /*
144 * Remove the temporary file if necessary...
145 */
146
147 if (argc < 7)
148 unlink(filename);
149
150 /*
151 * Return the queue status...
152 */
153
154 return (status);
155}
156
157
43e2fc22 158/*
e73c6c0a 159 * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
43e2fc22 160 */
161
e73c6c0a 162static int /* O - Status of command */
163lpd_command(int fd, /* I - Socket connection to LPD host */
164 char *format, /* I - printf()-style format string */
165 ...) /* I - Additional args as necessary */
166{
167 va_list ap; /* Argument pointer */
168 char buf[1024]; /* Output buffer */
169 int bytes; /* Number of bytes to output */
170 char status; /* Status from command */
171
172
173 /*
174 * Format the string...
175 */
176
177 va_start(ap, format);
178 bytes = vsprintf(buf, format, ap);
179 va_end(ap);
180
181 fprintf(stderr, "lpd: lpd_command %02.2x %s", buf[0], buf + 1);
182
183 /*
184 * Send the command...
185 */
186
187 if (send(fd, buf, bytes, 0) < bytes)
188 return (-1);
189
190 /*
191 * Read back the status from the command and return it...
192 */
193
194 if (recv(fd, &status, 1, 0) < 1)
195 return (-1);
196
197 fprintf(stderr, "lpd: lpd_command returning %d\n", status);
198
199 return (status);
200}
201
202
203/*
204 * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
205 */
206
207static int /* O - Zero on success, non-zero on failure */
208lpd_queue(char *hostname, /* I - Host to connect to */
209 char *printer, /* I - Printer/queue name */
210 char *filename, /* I - File to print */
211 char *user, /* I - Requesting user */
212 int copies) /* I - Number of copies */
213{
214 FILE *fp; /* Job file */
215 char localhost[255]; /* Local host name */
216 int error; /* Error number */
217 struct stat filestats; /* File statistics */
218 int port; /* LPD connection port */
219 int fd; /* LPD socket */
220 char control[10240], /* LPD control 'file' */
221 *cptr; /* Pointer into control file string */
222 char status; /* Status byte from command */
223 struct sockaddr_in addr; /* Socket address */
224 struct hostent *hostaddr; /* Host address */
225 size_t nbytes, /* Number of bytes written */
226 tbytes; /* Total bytes written */
227 char buffer[8192]; /* Output buffer */
228
229
230 /*
231 * First try to reserve a port for this connection...
232 */
233
234 if ((hostaddr = gethostbyname(hostname)) == NULL)
235 {
236 fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s",
237 hostname, strerror(errno));
238 return (1);
239 }
240
241 fprintf(stderr, "INFO: Attempting to connect to host %s for printer %s\n",
242 hostname, printer);
243
244 memset(&addr, 0, sizeof(addr));
245 memcpy(&(addr.sin_addr), hostaddr->h_addr, hostaddr->h_length);
246 addr.sin_family = hostaddr->h_addrtype;
247 addr.sin_port = htons(515); /* LPD/printer service */
248
249 for (port = 732;;)
250 {
251 if ((fd = rresvport(&port)) < 0)
252 {
decc1f36 253 perror("ERROR: Unable to connect to printer");
e73c6c0a 254 return (1);
255 }
256
257 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
258 {
259 error = errno;
260 close(fd);
261 fd = -1;
262
263 if (error == ECONNREFUSED)
264 {
265 fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...",
266 hostname);
267 sleep(30);
268 }
269 else if (error == EADDRINUSE)
270 {
271 port --;
272 if (port < 721)
273 port = 732;
274 }
275 else
276 {
decc1f36 277 perror("ERROR: Unable to connect to printer");
e73c6c0a 278 return (1);
279 }
280 }
281 else
282 break;
283 }
284
285 /*
286 * Next, open the print file and figure out its size...
287 */
288
289 if (stat(filename, &filestats))
290 {
decc1f36 291 perror("lpd: unable to stat print file");
e73c6c0a 292 return (1);
293 }
294
295 if ((fp = fopen(filename, "rb")) == NULL)
296 {
decc1f36 297 perror("lpd: unable to open print file for reading");
e73c6c0a 298 return (1);
299 }
300
301 /*
302 * Send a job header to the printer, specifying no banner page and
303 * literal output...
304 */
305
306 lpd_command(fd, "\002%s\n", printer); /* Receive print job(s) */
307
308 gethostname(localhost, sizeof(localhost));
309 if (strchr(localhost, '.') != NULL)
310 *strchr(localhost, '.') = '\0';
311
312 sprintf(control, "H%s\nP%s\n", localhost, user);
313 cptr = control + strlen(control);
314
315 while (copies > 0)
316 {
317 sprintf(cptr, "ldfA%03.3d%s\n", getpid() % 1000, localhost);
318 cptr += strlen(cptr);
319 copies --;
320 }
321
322 sprintf(cptr, "UdfA%03.3d%s\nNdfA%03.3d%s\n",
323 getpid() % 1000, localhost,
324 getpid() % 1000, localhost);
325
326 fprintf(stderr, "lpd: Control file is:\n%s", control);
327
328 lpd_command(fd, "\002%d cfA%03.3d%s\n", strlen(control), getpid() % 1000,
329 localhost);
330
331 fprintf(stderr, "lpd: Sending control file (%d bytes)\n", strlen(control));
332
333 if (send(fd, control, strlen(control) + 1, 0) < (strlen(control) + 1))
334 {
decc1f36 335 perror("ERROR: Unable to write control file");
e73c6c0a 336 status = 1;
337 }
338 else if (read(fd, &status, 1) < 1 || status != 0)
339 fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n",
340 status);
341 else
342 {
343 /*
344 * Send the print file...
345 */
346
347 fputs("lpd: Control file sent successfully\n", stderr);
348
349 lpd_command(fd, "\003%d dfA%03.3d%s\n", filestats.st_size,
350 getpid() % 1000, localhost);
351
decc1f36 352 fprintf(stderr, "lpd: Sending data file (%u bytes)\n",
353 (unsigned)filestats.st_size);
e73c6c0a 354
355 tbytes = 0;
356 while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
357 {
358 fprintf(stderr, "INFO: Spooling LPR job, %u%% complete...\n",
decc1f36 359 (unsigned)(100 * tbytes / filestats.st_size));
e73c6c0a 360
361 if (send(fd, buffer, nbytes, 0) < nbytes)
362 {
decc1f36 363 perror("ERROR: Unable to send print file to printer");
e73c6c0a 364 break;
365 }
366 else
367 tbytes += nbytes;
368 }
369
370 send(fd, "", 1, 0);
371
372 if (tbytes < filestats.st_size)
373 status = 1;
374 else if (recv(fd, &status, 1, 0) < 1 || status != 0)
375 fprintf(stderr, "ERROR: Remote host did not accept data file (%d)\n",
376 status);
377 else
378 fputs("lpd: Data file sent successfully\n", stderr);
379 }
380
381 /*
382 * Close the socket connection and input file and return...
383 */
384
385 close(fd);
386 fclose(fp);
387
388 return (status);
389}
43e2fc22 390
391
392/*
decc1f36 393 * End of "$Id: lpd.c,v 1.4 1999/04/21 15:02:00 mike Exp $".
43e2fc22 394 */