1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <signal.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <sys/param.h>
10
11 #define REDIALTIMEOUT 15
12 #ifdef PLAN9
13 #include <Plan9libnet.h>
14 #endif
15
16 enum {
17 TIMEOUT = 30*60,
18 SBSIZE = 8192,
19 };
20
21 char tmpfilename[L_tmpnam+1];
22 unsigned char sendbuf[SBSIZE];
23
24 int alarmstate = 0;
25 int debugflag = 0;
26 int killflag = 0;
27 int statflag = 0;
28
29 void
cleanup(void)30 cleanup(void)
31 {
32 unlink(tmpfilename);
33 }
34
35 void
debug(char * str)36 debug(char *str)
37 {
38 if (debugflag)
39 fprintf(stderr, "%s", str);
40 }
41
42 void
alarmhandler(int sig)43 alarmhandler(int sig)
44 {
45 fprintf(stderr, "timeout occurred, check printer.\n");
46 exit(2);
47 }
48
49 /* send a message after each WARNPC percent of data sent */
50 #define WARNPC 5
51
52 int
copyfile(int in,int out,long tosend)53 copyfile(int in, int out, long tosend)
54 {
55 int n;
56 int sent = 0;
57 int percent = 0;
58
59 if (debugflag)
60 fprintf(stderr, "lpdsend: copyfile(%d,%d,%ld)\n",
61 in, out, tosend);
62 while ((n=read(in, sendbuf, SBSIZE)) > 0) {
63 if (debugflag)
64 fprintf(stderr, "lpdsend: copyfile read %d bytes from %d\n",
65 n, in);
66 alarm(TIMEOUT);
67 alarmstate = 1;
68 if (write(out, sendbuf, n) != n) {
69 alarm(0);
70 fprintf(stderr, "write to fd %d failed\n", out);
71 return(0);
72 }
73 alarm(0);
74 if (debugflag)
75 fprintf(stderr, "lpdsend: copyfile wrote %d bytes to %d\n",
76 n, out);
77 sent += n;
78 if (tosend && sent*100/tosend >= percent+WARNPC) {
79 percent += WARNPC;
80 fprintf(stderr, ": %5.2f%% sent\n", sent*100.0/tosend);
81 }
82 }
83 if (debugflag)
84 fprintf(stderr, "lpdsend: copyfile read %d bytes from %d\n",
85 n, in);
86 return(!n);
87 }
88
89 char strbuf[120];
90 char hostname[MAXHOSTNAMELEN], *username, *printername, *killarg;
91 char *inputname;
92 char filetype = 'o'; /* 'o' is for PostScript */
93 int seqno = 0;
94 char *seqfilename;
95
96 void
killjob(int printerfd)97 killjob(int printerfd)
98 {
99 int strlength;
100
101 if (printername==0) {
102 fprintf(stderr, "no printer name\n");
103 exit(1);
104 }
105 if (username==0) {
106 fprintf(stderr, "no user name given\n");
107 exit(1);
108 }
109 if (killarg==0) {
110 fprintf(stderr, "no job to kill\n");
111 exit(1);
112 }
113 sprintf(strbuf, "%c%s %s %s\n", '\5', printername, username, killarg);
114 strlength = strlen(strbuf);
115 if (write(printerfd, strbuf, strlength) != strlength) {
116 fprintf(stderr, "write(printer) error\n");
117 exit(1);
118 }
119 copyfile(printerfd, 2, 0L);
120 }
121
122 void
checkqueue(int printerfd)123 checkqueue(int printerfd)
124 {
125 int n, strlength;
126 unsigned char sendbuf[1];
127
128 sprintf(strbuf, "%c%s\n", '\4', printername);
129 strlength = strlen(strbuf);
130 if (write(printerfd, strbuf, strlength) != strlength) {
131 fprintf(stderr, "write(printer) error\n");
132 exit(1);
133 }
134 copyfile(printerfd, 2, 0L);
135 /*
136 while ((n=read(printerfd, sendbuf, 1)) > 0) {
137 write(2, sendbuf, n);
138 }
139 */
140 }
141
142 void
getack(int printerfd,int as)143 getack(int printerfd, int as)
144 {
145 char resp;
146 int rv;
147
148 alarm(TIMEOUT);
149 alarmstate = as;
150 if ((rv = read(printerfd, &resp, 1)) != 1 || resp != '\0') {
151 fprintf(stderr, "getack failed: read returned %d, "
152 "read value (if any) %d, alarmstate=%d\n",
153 rv, resp, alarmstate);
154 exit(1);
155 }
156 alarm(0);
157 }
158
159 /* send control file */
160 void
sendctrl(int printerfd)161 sendctrl(int printerfd)
162 {
163 char cntrlstrbuf[256];
164 int strlength, cntrlen;
165
166 sprintf(cntrlstrbuf, "H%s\nP%s\n%cdfA%3.3d%s\n", hostname, username, filetype, seqno, hostname);
167 cntrlen = strlen(cntrlstrbuf);
168 sprintf(strbuf, "%c%d cfA%3.3d%s\n", '\2', cntrlen, seqno, hostname);
169 strlength = strlen(strbuf);
170 if (write(printerfd, strbuf, strlength) != strlength) {
171 fprintf(stderr, "write(printer) error\n");
172 exit(1);
173 }
174 getack(printerfd, 3);
175 if (write(printerfd, cntrlstrbuf, cntrlen) != cntrlen) {
176 fprintf(stderr, "write(printer) error\n");
177 exit(1);
178 }
179 if (write(printerfd, "\0", 1) != 1) {
180 fprintf(stderr, "write(printer) error\n");
181 exit(1);
182 }
183 getack(printerfd, 4);
184 }
185
186 /* send data file */
187 void
senddata(int inputfd,int printerfd,long size)188 senddata(int inputfd, int printerfd, long size)
189 {
190 int strlength;
191
192 sprintf(strbuf, "%c%d dfA%3.3d%s\n", '\3', size, seqno, hostname);
193 strlength = strlen(strbuf);
194 if (write(printerfd, strbuf, strlength) != strlength) {
195 fprintf(stderr, "write(printer) error\n");
196 exit(1);
197 }
198 getack(printerfd, 5);
199 if (!copyfile(inputfd, printerfd, size)) {
200 fprintf(stderr, "failed to send file to printer\n");
201 exit(1);
202 }
203 if (write(printerfd, "\0", 1) != 1) {
204 fprintf(stderr, "write(printer) error\n");
205 exit(1);
206 }
207 fprintf(stderr, "%d bytes sent, status: waiting for end of job\n", size);
208 getack(printerfd, 6);
209 }
210
211 void
sendjob(int inputfd,int printerfd)212 sendjob(int inputfd, int printerfd)
213 {
214 struct stat statbuf;
215 int strlength;
216
217 if (fstat(inputfd, &statbuf) < 0) {
218 fprintf(stderr, "fstat(%s) failed\n", inputname);
219 exit(1);
220 }
221 sprintf(strbuf, "%c%s\n", '\2', printername);
222 strlength = strlen(strbuf);
223 if (write(printerfd, strbuf, strlength) != strlength) {
224 fprintf(stderr, "write(printer) error\n");
225 exit(1);
226 }
227 getack(printerfd, 2);
228 debug("send data\n");
229 senddata(inputfd, printerfd, statbuf.st_size);
230 debug("send control info\n");
231 sendctrl(printerfd);
232 fprintf(stderr, "%ld bytes sent, status: end of job\n", statbuf.st_size);
233 }
234
235 /*
236 * make an address, add the defaults
237 */
238 char *
netmkaddr(char * linear,char * defnet,char * defsrv)239 netmkaddr(char *linear, char *defnet, char *defsrv)
240 {
241 static char addr[512];
242 char *cp;
243
244 /*
245 * dump network name
246 */
247 cp = strchr(linear, '!');
248 if(cp == 0){
249 if(defnet==0){
250 if(defsrv)
251 snprintf(addr, sizeof addr, "net!%s!%s", linear, defsrv);
252 else
253 snprintf(addr, sizeof addr, "net!%s", linear);
254 }
255 else {
256 if(defsrv)
257 snprintf(addr, sizeof addr, "%s!%s!%s", defnet, linear, defsrv);
258 else
259 snprintf(addr, sizeof addr, "%s!%s", defnet, linear);
260 }
261 return addr;
262 }
263
264 /*
265 * if there is already a service, use it
266 */
267 cp = strchr(cp+1, '!');
268 if(cp)
269 return linear;
270
271 /*
272 * add default service
273 */
274 if(defsrv == 0)
275 return linear;
276 sprintf(addr, "%s!%s", linear, defsrv);
277
278 return addr;
279 }
280
281 void
main(int argc,char * argv[])282 main(int argc, char *argv[])
283 {
284 int c, usgflg = 0, inputfd, printerfd, sendport;
285 char *desthostname, *hnend;
286 char portstr[4];
287
288 if (signal(SIGALRM, alarmhandler) == SIG_ERR) {
289 fprintf(stderr, "failed to set alarm handler\n");
290 exit(1);
291 }
292 while ((c = getopt(argc, argv, "Dd:k:qs:t:H:P:")) != -1)
293 switch (c) {
294 case 'D':
295 debugflag = 1;
296 debug("debugging on\n");
297 break;
298 case 'd':
299 printername = optarg;
300 break;
301 case 'k':
302 if (statflag) {
303 fprintf(stderr, "cannot have both -k and -q flags\n");
304 exit(1);
305 }
306 killflag = 1;
307 killarg = optarg;
308 break;
309 case 'q':
310 if (killflag) {
311 fprintf(stderr, "cannot have both -q and -k flags\n");
312 exit(1);
313 }
314 statflag = 1;
315 break;
316 case 's':
317 seqno = strtol(optarg, NULL, 10);
318 if (seqno < 0 || seqno > 999)
319 seqno = 0;
320 break;
321 case 't':
322 switch (filetype) {
323 case 'c':
324 case 'd':
325 case 'f':
326 case 'g':
327 case 'l':
328 case 'n':
329 case 'o':
330 case 'p':
331 case 'r':
332 case 't':
333 case 'v':
334 case 'z':
335 filetype = optarg[0];
336 break;
337 default:
338 usgflg++;
339 break;
340 }
341 break;
342 case 'H':
343 strncpy(hostname, optarg, MAXHOSTNAMELEN);
344 break;
345 case 'P':
346 username = optarg;
347 break;
348 default:
349 case '?':
350 fprintf(stderr, "unknown option %c\n", c);
351 usgflg++;
352 }
353 if (argc < 2) usgflg++;
354 if (optind < argc) {
355 desthostname = argv[optind++];
356 } else
357 usgflg++;
358 if (usgflg) {
359 fprintf(stderr, "usage: to send a job - %s -d printer -H hostname -P username [-s seqno] [-t[cdfgklnoprtvz]] desthost [filename]\n", argv[0]);
360 fprintf(stderr, " to check status - %s -d printer -q desthost\n", argv[0]);
361 fprintf(stderr, " to kill a job - %s -d printer -P username -k jobname desthost\n", argv[0]);
362 exit(1);
363 }
364
365 /* make sure the file to send is here and ready
366 * otherwise the TCP connection times out.
367 */
368 if (!statflag && !killflag) {
369 if (optind < argc) {
370 inputname = argv[optind++];
371 debug("open("); debug(inputname); debug(")\n");
372 inputfd = open(inputname, O_RDONLY);
373 if (inputfd < 0) {
374 fprintf(stderr, "open(%s) failed\n", inputname);
375 exit(1);
376 }
377 } else {
378 inputname = "stdin";
379 tmpnam(tmpfilename);
380 debug("using stdin\n");
381 if ((inputfd = open(tmpfilename, O_RDWR|O_CREAT, 0600)) < 0) {
382 fprintf(stderr, "open(%s) failed\n", tmpfilename);
383 exit(1);
384 }
385 atexit(cleanup);
386 debug("copy input to temp file ");
387 debug(tmpfilename);
388 debug("\n");
389 if (!copyfile(0, inputfd, 0L)) {
390 fprintf(stderr, "failed to copy file to temporary file\n");
391 exit(1);
392 }
393 if (lseek(inputfd, 0L, 0) < 0) {
394 fprintf(stderr, "failed to seek back to the beginning of the temporary file\n");
395 exit(1);
396 }
397 }
398 }
399
400 sprintf(strbuf, "%s", netmkaddr(desthostname, "tcp", "printer"));
401 fprintf(stderr, "connecting to %s\n", strbuf);
402 for (sendport=721; sendport<=731; sendport++) {
403 sprintf(portstr, "%3.3d", sendport);
404 fprintf(stderr, " trying from port %s...", portstr);
405 debug(" dial("); debug(strbuf); debug(", "); debug(portstr); debug(", 0, 0) ...");
406 printerfd = dial(strbuf, portstr, 0, 0);
407 if (printerfd >= 0) {
408 fprintf(stderr, "connected\n");
409 break;
410 }
411 fprintf(stderr, "failed\n");
412 sleep(REDIALTIMEOUT);
413 }
414 if (printerfd < 0) {
415 fprintf(stderr, "Cannot open a valid port!\n");
416 fprintf(stderr, "- All source ports [721-731] may be busy.\n");
417 fprintf(stderr, "- Is recipient ready and online?\n");
418 fprintf(stderr, "- If all else fails, cycle the power!\n");
419 exit(1);
420 }
421 /* hostname[8] = '\0'; */
422 #ifndef PLAN9
423 if (gethostname(hostname, sizeof(hostname)) < 0) {
424 perror("gethostname");
425 exit(1);
426 }
427 #endif
428 /* if ((hnend = strchr(hostname, '.')) != NULL)
429 *hnend = '\0';
430 */
431 if (statflag) {
432 checkqueue(printerfd);
433 } else if (killflag) {
434 killjob(printerfd);
435 } else {
436 sendjob(inputfd, printerfd);
437 }
438 exit(0);
439 }
440