xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 26048)
121739Sdist /*
2*26048Sminshall  * Copyright (c) 1985 Regents of the University of California.
321739Sdist  * All rights reserved.  The Berkeley software License Agreement
421739Sdist  * specifies the terms and conditions for redistribution.
521739Sdist  */
621739Sdist 
710296Ssam #ifndef lint
8*26048Sminshall static char sccsid[] = "@(#)ftp.c	5.6 (Berkeley) 02/03/86";
921739Sdist #endif not lint
1010296Ssam 
11*26048Sminshall #include "ftp_var.h"
12*26048Sminshall 
1310296Ssam #include <sys/stat.h>
1410296Ssam #include <sys/ioctl.h>
1510296Ssam #include <sys/socket.h>
1613614Ssam #include <sys/time.h>
1710296Ssam 
1810296Ssam #include <netinet/in.h>
1912397Ssam #include <arpa/ftp.h>
20*26048Sminshall #include <arpa/telnet.h>
2110296Ssam 
2210296Ssam #include <stdio.h>
2310296Ssam #include <signal.h>
2410296Ssam #include <errno.h>
2510296Ssam #include <netdb.h>
26*26048Sminshall #include <fcntl.h>
27*26048Sminshall #include <pwd.h>
2810296Ssam 
2910296Ssam struct	sockaddr_in hisctladdr;
3010296Ssam struct	sockaddr_in data_addr;
3110296Ssam int	data = -1;
32*26048Sminshall int     telflag = 0;
33*26048Sminshall int	abrtflag = 0;
34*26048Sminshall int	ptflag = 0;
3510296Ssam int	connected;
3610296Ssam struct	sockaddr_in myctladdr;
3710296Ssam 
3810296Ssam FILE	*cin, *cout;
3910296Ssam FILE	*dataconn();
4010296Ssam 
4125904Skarels char *
4210296Ssam hookup(host, port)
4310296Ssam 	char *host;
4410296Ssam 	int port;
4510296Ssam {
4625904Skarels 	register struct hostent *hp = 0;
47*26048Sminshall 	int s,len,oldverbose;
4825904Skarels 	static char hostnamebuf[80];
49*26048Sminshall 	char msg[2];
5010296Ssam 
5110296Ssam 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
5225904Skarels 	hisctladdr.sin_addr.s_addr = inet_addr(host);
5325904Skarels 	if (hisctladdr.sin_addr.s_addr != -1) {
5425904Skarels 		hisctladdr.sin_family = AF_INET;
5525904Skarels 		(void) strcpy(hostnamebuf, host);
56*26048Sminshall 	}
57*26048Sminshall 	else {
5825100Sbloom 		hp = gethostbyname(host);
5925904Skarels 		if (hp == NULL) {
6025904Skarels 			printf("%s: unknown host\n", host);
61*26048Sminshall 			code = -1;
62*26048Sminshall 			return((char *) 0);
6325904Skarels 		}
6425904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
6525904Skarels 		bcopy(hp->h_addr_list[0],
6625904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
6725904Skarels 		(void) strcpy(hostnamebuf, hp->h_name);
6810296Ssam 	}
6925904Skarels 	hostname = hostnamebuf;
7025904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
7110296Ssam 	if (s < 0) {
7210296Ssam 		perror("ftp: socket");
73*26048Sminshall 		code = -1;
7410296Ssam 		return (0);
7510296Ssam 	}
7610296Ssam 	hisctladdr.sin_port = port;
7725904Skarels 	while (connect(s, (caddr_t)&hisctladdr, sizeof (hisctladdr)) < 0) {
7825904Skarels 		if (hp && hp->h_addr_list[1]) {
7925904Skarels 			int oerrno = errno;
8025904Skarels 
8125904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
8225904Skarels 				inet_ntoa(hisctladdr.sin_addr));
8325904Skarels 			errno = oerrno;
8425904Skarels 			perror(0);
8525904Skarels 			hp->h_addr_list++;
8625904Skarels 			bcopy(hp->h_addr_list[0],
87*26048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
8825904Skarels 			fprintf(stderr, "Trying %s...\n",
8925904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9025904Skarels 			continue;
9125904Skarels 		}
9210296Ssam 		perror("ftp: connect");
93*26048Sminshall 		code = -1;
9410296Ssam 		goto bad;
9510296Ssam 	}
9611627Ssam 	len = sizeof (myctladdr);
9711627Ssam 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
9811627Ssam 		perror("ftp: getsockname");
99*26048Sminshall 		code = -1;
10010296Ssam 		goto bad;
10110296Ssam 	}
10210296Ssam 	cin = fdopen(s, "r");
10310296Ssam 	cout = fdopen(s, "w");
10411219Ssam 	if (cin == NULL || cout == NULL) {
10510296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
10610296Ssam 		if (cin)
10710296Ssam 			fclose(cin);
10810296Ssam 		if (cout)
10910296Ssam 			fclose(cout);
110*26048Sminshall 		code = -1;
11110296Ssam 		goto bad;
11210296Ssam 	}
11310296Ssam 	if (verbose)
114*26048Sminshall 		printf("Connected to %s.\n", hp->h_name);
115*26048Sminshall 	if (getreply(0) != 2) { 	/* read startup message from server */
116*26048Sminshall 		if (cin)
117*26048Sminshall 			fclose(cin);
118*26048Sminshall 		if (cout)
119*26048Sminshall 			fclose(cout);
120*26048Sminshall 		code = -1;
121*26048Sminshall 		goto bad;
122*26048Sminshall 	}
123*26048Sminshall 
124*26048Sminshall /* test to see if server command parser understands TELNET SYNC command */
125*26048Sminshall 
126*26048Sminshall 	fprintf(cout,"%c%c",IAC,NOP);
127*26048Sminshall 	(void) fflush(cout);
128*26048Sminshall 	*msg = IAC;
129*26048Sminshall 	*(msg+1) = DM;
130*26048Sminshall 	if (send(s,msg,2,MSG_OOB) != 2) {
131*26048Sminshall 		perror("sync");
132*26048Sminshall 	}
133*26048Sminshall 	oldverbose = verbose;
134*26048Sminshall 	if (!debug) {
135*26048Sminshall 		verbose = -1;
136*26048Sminshall 	}
137*26048Sminshall 	if (command("NOOP") == COMPLETE) {
138*26048Sminshall 		telflag = 1;
139*26048Sminshall 	}
140*26048Sminshall 	else {
141*26048Sminshall 		telflag = 0;
142*26048Sminshall 	}
143*26048Sminshall 	verbose = oldverbose;
14425904Skarels 	return (hostname);
14510296Ssam bad:
14610296Ssam 	close(s);
14725904Skarels 	return ((char *)0);
14810296Ssam }
14910296Ssam 
15025904Skarels login(host)
15125904Skarels 	char *host;
15210296Ssam {
153*26048Sminshall 	char tmp[80];
154*26048Sminshall 	char *user, *pass, *acct, *getlogin(), *getpass();
155*26048Sminshall 	int n, aflag = 0;
15610296Ssam 
157*26048Sminshall 	user = pass = acct = 0;
158*26048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
159*26048Sminshall 		disconnect();
160*26048Sminshall 		code = -1;
161*26048Sminshall 		return(0);
162*26048Sminshall 	}
163*26048Sminshall 	if (user == NULL) {
164*26048Sminshall 		char *myname = getlogin();
165*26048Sminshall 
166*26048Sminshall 		if (myname == NULL) {
167*26048Sminshall 			struct passwd *pp = getpwuid(getuid());
168*26048Sminshall 
169*26048Sminshall 			if (pp != NULL) {
170*26048Sminshall 				myname = pp->pw_name;
171*26048Sminshall 			}
172*26048Sminshall 		}
173*26048Sminshall 		printf("Name (%s:%s): ", host, myname);
174*26048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
175*26048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
176*26048Sminshall 		if (*tmp == '\0') {
177*26048Sminshall 			user = myname;
178*26048Sminshall 		}
179*26048Sminshall 		else {
180*26048Sminshall 			user = tmp;
181*26048Sminshall 		}
182*26048Sminshall 	}
18310296Ssam 	n = command("USER %s", user);
184*26048Sminshall 	if (n == CONTINUE) {
185*26048Sminshall 		if (pass == NULL) {
186*26048Sminshall 			pass = getpass("Password:");
187*26048Sminshall 		}
18810296Ssam 		n = command("PASS %s", pass);
189*26048Sminshall 	}
19010296Ssam 	if (n == CONTINUE) {
191*26048Sminshall 		aflag++;
192*26048Sminshall 		acct = getpass("Account:");
19310296Ssam 		n = command("ACCT %s", acct);
19410296Ssam 	}
19510296Ssam 	if (n != COMPLETE) {
19610296Ssam 		fprintf(stderr, "Login failed.\n");
19710296Ssam 		return (0);
19810296Ssam 	}
199*26048Sminshall 	if (!aflag && acct != NULL) {
200*26048Sminshall 		(void) command("ACCT %s", acct);
201*26048Sminshall 	}
202*26048Sminshall 	if (proxy) {
203*26048Sminshall 		return(1);
204*26048Sminshall 	}
205*26048Sminshall 	for (n = 0; n < macnum; ++n) {
206*26048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
207*26048Sminshall 			strcpy(line, "$init");
208*26048Sminshall 			makeargv();
209*26048Sminshall 			domacro(margc, margv);
210*26048Sminshall 			break;
211*26048Sminshall 		}
212*26048Sminshall 	}
21310296Ssam 	return (1);
21410296Ssam }
21510296Ssam 
216*26048Sminshall cmdabort()
217*26048Sminshall {
218*26048Sminshall 	extern jmp_buf ptabort;
219*26048Sminshall 
220*26048Sminshall 	printf("\n");
221*26048Sminshall 	(void) fflush(stdout);
222*26048Sminshall 	abrtflag++;
223*26048Sminshall 	if (ptflag) {
224*26048Sminshall 		longjmp(ptabort,1);
225*26048Sminshall 	}
226*26048Sminshall }
227*26048Sminshall 
22810296Ssam /*VARARGS 1*/
22910296Ssam command(fmt, args)
23010296Ssam 	char *fmt;
23110296Ssam {
232*26048Sminshall 	int r, (*oldintr)(), cmdabort();
23310296Ssam 
234*26048Sminshall 	abrtflag = 0;
23510296Ssam 	if (debug) {
23610296Ssam 		printf("---> ");
23710296Ssam 		_doprnt(fmt, &args, stdout);
23810296Ssam 		printf("\n");
23910296Ssam 		(void) fflush(stdout);
24010296Ssam 	}
24111219Ssam 	if (cout == NULL) {
24211219Ssam 		perror ("No control connection for command");
243*26048Sminshall 		code = -1;
24411219Ssam 		return (0);
24511219Ssam 	}
246*26048Sminshall 	oldintr = signal(SIGINT,cmdabort);
24710296Ssam 	_doprnt(fmt, &args, cout);
24810296Ssam 	fprintf(cout, "\r\n");
24910296Ssam 	(void) fflush(cout);
250*26048Sminshall 	cpend = 1;
251*26048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
252*26048Sminshall 	if (abrtflag && oldintr != SIG_IGN) {
253*26048Sminshall 		(*oldintr)();
254*26048Sminshall 	}
255*26048Sminshall 	(void) signal(SIGINT, oldintr);
256*26048Sminshall 	return(r);
25710296Ssam }
25810296Ssam 
25910296Ssam #include <ctype.h>
26010296Ssam 
26110296Ssam getreply(expecteof)
26210296Ssam 	int expecteof;
26310296Ssam {
26411219Ssam 	register int c, n;
265*26048Sminshall 	register int dig;
266*26048Sminshall 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
267*26048Sminshall 	int pflag = 0;
268*26048Sminshall 	char *pt = pasv;
26910296Ssam 
270*26048Sminshall 	oldintr = signal(SIGINT,cmdabort);
27110296Ssam 	for (;;) {
27210296Ssam 		dig = n = code = 0;
27310296Ssam 		while ((c = getc(cin)) != '\n') {
27410296Ssam 			dig++;
27510296Ssam 			if (c == EOF) {
276*26048Sminshall 				if (expecteof) {
277*26048Sminshall 					(void) signal(SIGINT,oldintr);
278*26048Sminshall 					code = 221;
27910296Ssam 					return (0);
280*26048Sminshall 				}
28110296Ssam 				lostpeer();
282*26048Sminshall 				if (verbose) {
283*26048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
284*26048Sminshall 					(void) fflush(stdout);
285*26048Sminshall 					code = 421;
286*26048Sminshall 					return(4);
287*26048Sminshall 				}
28810296Ssam 			}
289*26048Sminshall 			if (c != '\r' && (verbose > 0 ||
290*26048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
291*26048Sminshall 				if ( proxflag &&
292*26048Sminshall 				   (dig == 1 || dig == 5 && verbose == 0)) {
293*26048Sminshall 					printf("%s:",hostname);
294*26048Sminshall 				}
29510296Ssam 				putchar(c);
296*26048Sminshall 			}
29710296Ssam 			if (dig < 4 && isdigit(c))
29810296Ssam 				code = code * 10 + (c - '0');
299*26048Sminshall 			if (!pflag && code == 227) {
300*26048Sminshall 				pflag = 1;
301*26048Sminshall 			}
302*26048Sminshall 			if (dig > 4 && pflag == 1 && isdigit(c)) {
303*26048Sminshall 				pflag = 2;
304*26048Sminshall 			}
305*26048Sminshall 			if (pflag == 2) {
306*26048Sminshall 				if (c != '\r' && c != ')') {
307*26048Sminshall 					*pt++ = c;
308*26048Sminshall 				}
309*26048Sminshall 				else {
310*26048Sminshall 					*pt = '\0';
311*26048Sminshall 					pflag = 3;
312*26048Sminshall 				}
313*26048Sminshall 			}
314*26048Sminshall 			if (dig == 4 && c == '-') {
315*26048Sminshall 				if (continuation) {
316*26048Sminshall 					code = 0;
317*26048Sminshall 				}
31810296Ssam 				continuation++;
319*26048Sminshall 			}
32010296Ssam 			if (n == 0)
32110296Ssam 				n = c;
32210296Ssam 		}
323*26048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
32410296Ssam 			putchar(c);
32511346Ssam 			(void) fflush (stdout);
32611346Ssam 		}
32710296Ssam 		if (continuation && code != originalcode) {
32810296Ssam 			if (originalcode == 0)
32910296Ssam 				originalcode = code;
33010296Ssam 			continue;
33110296Ssam 		}
332*26048Sminshall 		if (n != '1') {
333*26048Sminshall 			cpend = 0;
334*26048Sminshall 		}
335*26048Sminshall 		(void) signal(SIGINT,oldintr);
336*26048Sminshall 		if (code == 421 || originalcode == 421) {
337*26048Sminshall 			lostpeer();
338*26048Sminshall 		}
339*26048Sminshall 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) {
340*26048Sminshall 			(*oldintr)();
341*26048Sminshall 		}
34225907Smckusick 		return (n - '0');
34310296Ssam 	}
34410296Ssam }
34510296Ssam 
346*26048Sminshall empty(mask, sec)
347*26048Sminshall 	long mask;
348*26048Sminshall 	int sec;
349*26048Sminshall {
350*26048Sminshall 	struct timeval t;
351*26048Sminshall 
352*26048Sminshall 	t.tv_sec = (long) sec;
353*26048Sminshall 	t.tv_usec = 0;
354*26048Sminshall 	if (select(20, &mask, 0, 0, &t) < 0) {
355*26048Sminshall 		return(-1);
356*26048Sminshall 	}
357*26048Sminshall 	return (mask);
358*26048Sminshall }
359*26048Sminshall 
36010296Ssam jmp_buf	sendabort;
36110296Ssam 
36210296Ssam abortsend()
36310296Ssam {
36410296Ssam 
365*26048Sminshall 	mflag = 0;
366*26048Sminshall 	abrtflag = 0;
367*26048Sminshall 	printf("\nsend aborted\n");
368*26048Sminshall 	(void) fflush(stdout);
36910296Ssam 	longjmp(sendabort, 1);
37010296Ssam }
37110296Ssam 
37210296Ssam sendrequest(cmd, local, remote)
37310296Ssam 	char *cmd, *local, *remote;
37410296Ssam {
375*26048Sminshall 	FILE *fin, *dout = 0, *popen();
376*26048Sminshall 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
377*26048Sminshall 	int abortsend();
37811219Ssam 	char buf[BUFSIZ];
37911651Ssam 	long bytes = 0, hashbytes = sizeof (buf);
38011346Ssam 	register int c, d;
38110296Ssam 	struct stat st;
38210296Ssam 	struct timeval start, stop;
38310296Ssam 
384*26048Sminshall 	if (proxy) {
385*26048Sminshall 		proxtrans(cmd, local, remote);
386*26048Sminshall 		return;
387*26048Sminshall 	}
38810296Ssam 	closefunc = NULL;
389*26048Sminshall 	oldintr = NULL;
390*26048Sminshall 	oldintp = NULL;
391*26048Sminshall 	if (setjmp(sendabort)) {
392*26048Sminshall 		while (cpend) {
393*26048Sminshall 			(void) getreply(0);
394*26048Sminshall 		}
395*26048Sminshall 		if (data >= 0) {
396*26048Sminshall 			(void) close(data);
397*26048Sminshall 			data = -1;
398*26048Sminshall 		}
399*26048Sminshall 		if (oldintr) {
400*26048Sminshall 			(void) signal(SIGINT,oldintr);
401*26048Sminshall 		}
402*26048Sminshall 		if (oldintp) {
403*26048Sminshall 			(void) signal(SIGPIPE,oldintp);
404*26048Sminshall 		}
405*26048Sminshall 		code = -1;
406*26048Sminshall 		return;
407*26048Sminshall 	}
40810296Ssam 	oldintr = signal(SIGINT, abortsend);
40910296Ssam 	if (strcmp(local, "-") == 0)
41010296Ssam 		fin = stdin;
41110296Ssam 	else if (*local == '|') {
412*26048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
413*26048Sminshall 		fin = popen(local + 1, "r");
41410296Ssam 		if (fin == NULL) {
415*26048Sminshall 			perror(local + 1);
416*26048Sminshall 			(void) signal(SIGINT, oldintr);
417*26048Sminshall 			(void) signal(SIGPIPE, oldintp);
418*26048Sminshall 			code = -1;
419*26048Sminshall 			return;
42010296Ssam 		}
42110296Ssam 		closefunc = pclose;
42210296Ssam 	} else {
42310296Ssam 		fin = fopen(local, "r");
42410296Ssam 		if (fin == NULL) {
42510296Ssam 			perror(local);
426*26048Sminshall 			(void) signal(SIGINT, oldintr);
427*26048Sminshall 			code = -1;
428*26048Sminshall 			return;
42910296Ssam 		}
43010296Ssam 		closefunc = fclose;
43110296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
43210296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
43317949Sralph 			fprintf(stderr, "%s: not a plain file.\n", local);
434*26048Sminshall 			(void) signal(SIGINT, oldintr);
435*26048Sminshall 			code = -1;
436*26048Sminshall 			return;
43710296Ssam 		}
43810296Ssam 	}
439*26048Sminshall 	if (initconn()) {
440*26048Sminshall 		(void) signal(SIGINT, oldintr);
441*26048Sminshall 		if (oldintp) {
442*26048Sminshall 			(void) signal(SIGPIPE, oldintp);
443*26048Sminshall 		}
444*26048Sminshall 		code = -1;
445*26048Sminshall 		return;
446*26048Sminshall 	}
447*26048Sminshall 	if (setjmp(sendabort)) {
448*26048Sminshall 		goto abort;
449*26048Sminshall 	}
45010296Ssam 	if (remote) {
451*26048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
452*26048Sminshall 			(void) signal(SIGINT, oldintr);
453*26048Sminshall 			if (oldintp) {
454*26048Sminshall 				(void) signal(SIGPIPE, oldintp);
455*26048Sminshall 			}
456*26048Sminshall 			return;
457*26048Sminshall 		}
45810296Ssam 	} else
459*26048Sminshall 		if (command("%s", cmd) != PRELIM) {
460*26048Sminshall 			(void) signal(SIGINT, oldintr);
461*26048Sminshall 			if (oldintp) {
462*26048Sminshall 				(void) signal(SIGPIPE, oldintp);
463*26048Sminshall 			}
464*26048Sminshall 			return;
465*26048Sminshall 		}
46610296Ssam 	dout = dataconn("w");
467*26048Sminshall 	if (dout == NULL) {
468*26048Sminshall 		goto abort;
469*26048Sminshall 	}
47010296Ssam 	gettimeofday(&start, (struct timezone *)0);
47111219Ssam 	switch (type) {
47211219Ssam 
47311219Ssam 	case TYPE_I:
47411219Ssam 	case TYPE_L:
47511346Ssam 		errno = d = 0;
47611219Ssam 		while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) {
47711346Ssam 			if ((d = write(fileno (dout), buf, c)) < 0)
47811219Ssam 				break;
47911219Ssam 			bytes += c;
48011651Ssam 			if (hash) {
48111651Ssam 				putchar('#');
48211651Ssam 				fflush(stdout);
48311651Ssam 			}
48411219Ssam 		}
48513213Ssam 		if (hash && bytes > 0) {
48611651Ssam 			putchar('\n');
48711651Ssam 			fflush(stdout);
48811651Ssam 		}
48911219Ssam 		if (c < 0)
49011219Ssam 			perror(local);
49111346Ssam 		if (d < 0)
49211219Ssam 			perror("netout");
49311219Ssam 		break;
49411219Ssam 
49511219Ssam 	case TYPE_A:
49611219Ssam 		while ((c = getc(fin)) != EOF) {
49711219Ssam 			if (c == '\n') {
49811651Ssam 				while (hash && (bytes >= hashbytes)) {
49911651Ssam 					putchar('#');
50011651Ssam 					fflush(stdout);
50111651Ssam 					hashbytes += sizeof (buf);
50211651Ssam 				}
50311219Ssam 				if (ferror(dout))
50411219Ssam 					break;
50511219Ssam 				putc('\r', dout);
50611219Ssam 				bytes++;
50711219Ssam 			}
50811219Ssam 			putc(c, dout);
50911219Ssam 			bytes++;
510*26048Sminshall 	/*		if (c == '\r') {			  	*/
511*26048Sminshall 	/*			putc('\0', dout);  /* this violates rfc */
512*26048Sminshall 	/*			bytes++;				*/
513*26048Sminshall 	/*		}                          			*/
51411219Ssam 		}
51511651Ssam 		if (hash) {
51613213Ssam 			if (bytes < hashbytes)
51713213Ssam 				putchar('#');
51811651Ssam 			putchar('\n');
51911651Ssam 			fflush(stdout);
52011651Ssam 		}
52111219Ssam 		if (ferror(fin))
52211219Ssam 			perror(local);
52311346Ssam 		if (ferror(dout))
52411219Ssam 			perror("netout");
52511219Ssam 		break;
52610296Ssam 	}
52710296Ssam 	gettimeofday(&stop, (struct timezone *)0);
52810296Ssam 	if (closefunc != NULL)
529*26048Sminshall 		(*closefunc)(fin);
53010296Ssam 	(void) fclose(dout);
531*26048Sminshall 	(void) getreply(0);
532*26048Sminshall 	(void) signal(SIGINT, oldintr);
53310296Ssam 	if (bytes > 0 && verbose)
534*26048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
53510296Ssam 	return;
536*26048Sminshall abort:
537*26048Sminshall 	gettimeofday(&stop, (struct timezone *)0);
538*26048Sminshall 	(void) signal(SIGINT, oldintr);
539*26048Sminshall 	if (oldintp) {
540*26048Sminshall 		(void) signal(SIGPIPE, oldintp);
541*26048Sminshall 	}
542*26048Sminshall 	if (!cpend) {
543*26048Sminshall 		code = -1;
544*26048Sminshall 		return;
545*26048Sminshall 	}
546*26048Sminshall 	if (data >= 0) {
547*26048Sminshall 		(void) close(data);
548*26048Sminshall 		data = -1;
549*26048Sminshall 	}
550*26048Sminshall 	if (dout) {
551*26048Sminshall 		(void) fclose(dout);
552*26048Sminshall 	}
553*26048Sminshall 	(void) getreply(0);
554*26048Sminshall 	code = -1;
55510296Ssam 	if (closefunc != NULL && fin != NULL)
556*26048Sminshall 		(*closefunc)(fin);
557*26048Sminshall 	if (bytes > 0 && verbose)
558*26048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
55910296Ssam }
56010296Ssam 
56110296Ssam jmp_buf	recvabort;
56210296Ssam 
56310296Ssam abortrecv()
56410296Ssam {
56510296Ssam 
566*26048Sminshall 	mflag = 0;
567*26048Sminshall 	abrtflag = 0;
568*26048Sminshall 	printf("\n");
569*26048Sminshall 	(void) fflush(stdout);
57010296Ssam 	longjmp(recvabort, 1);
57110296Ssam }
57210296Ssam 
57311651Ssam recvrequest(cmd, local, remote, mode)
57411651Ssam 	char *cmd, *local, *remote, *mode;
57510296Ssam {
576*26048Sminshall 	FILE *fout, *din = 0, *popen();
577*26048Sminshall 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
578*26048Sminshall 	int abortrecv(), oldverbose, oldtype = 0, tcrflag;
579*26048Sminshall 	char buf[BUFSIZ], *gunique();
580*26048Sminshall 	long bytes = 0, hashbytes = sizeof (buf), mask;
58111346Ssam 	register int c, d;
58210296Ssam 	struct timeval start, stop;
58310296Ssam 
584*26048Sminshall 	if (proxy && strcmp(cmd,"RETR") == 0) {
585*26048Sminshall 		proxtrans(cmd, local, remote);
586*26048Sminshall 		return;
587*26048Sminshall 	}
58810296Ssam 	closefunc = NULL;
589*26048Sminshall 	oldintr = NULL;
590*26048Sminshall 	oldintp = NULL;
591*26048Sminshall 	tcrflag = !crflag && !strcmp(cmd, "RETR");
592*26048Sminshall 	if (setjmp(recvabort)) {
593*26048Sminshall 		while (cpend) {
594*26048Sminshall 			(void) getreply(0);
595*26048Sminshall 		}
596*26048Sminshall 		if (data >= 0) {
597*26048Sminshall 			(void) close(data);
598*26048Sminshall 			data = -1;
599*26048Sminshall 		}
600*26048Sminshall 		if (oldintr) {
601*26048Sminshall 			(void) signal(SIGINT, oldintr);
602*26048Sminshall 		}
603*26048Sminshall 		code = -1;
604*26048Sminshall 		return;
605*26048Sminshall 	}
60610296Ssam 	oldintr = signal(SIGINT, abortrecv);
607*26048Sminshall 	if (strcmp(local, "-") && *local != '|') {
60810296Ssam 		if (access(local, 2) < 0) {
609*26048Sminshall 			char *dir = rindex(local, '/');
61010296Ssam 
611*26048Sminshall 			if (errno != ENOENT && errno != EACCES) {
61210296Ssam 				perror(local);
613*26048Sminshall 				(void) signal(SIGINT, oldintr);
614*26048Sminshall 				code = -1;
615*26048Sminshall 				return;
61610296Ssam 			}
617*26048Sminshall 			if (dir != NULL)
618*26048Sminshall 				*dir = 0;
619*26048Sminshall 			d = access(dir ? local : ".", 2);
620*26048Sminshall 			if (dir != NULL)
621*26048Sminshall 				*dir = '/';
622*26048Sminshall 			if (d < 0) {
623*26048Sminshall 				perror(local);
624*26048Sminshall 				(void) signal(SIGINT, oldintr);
625*26048Sminshall 				code = -1;
626*26048Sminshall 				return;
627*26048Sminshall 			}
628*26048Sminshall 			if (!runique && errno == EACCES &&
629*26048Sminshall 			    chmod(local,0600) < 0) {
630*26048Sminshall 				perror(local);
631*26048Sminshall 				(void) signal(SIGINT, oldintr);
632*26048Sminshall 				code = -1;
633*26048Sminshall 				return;
634*26048Sminshall 			}
635*26048Sminshall 			if (runique && errno == EACCES &&
636*26048Sminshall 			   (local = gunique(local)) == NULL) {
637*26048Sminshall 				(void) signal(SIGINT, oldintr);
638*26048Sminshall 				code = -1;
639*26048Sminshall 				return;
640*26048Sminshall 			}
64110296Ssam 		}
642*26048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
643*26048Sminshall 			(void) signal(SIGINT, oldintr);
644*26048Sminshall 			code = -1;
645*26048Sminshall 			return;
646*26048Sminshall 		}
647*26048Sminshall 	}
648*26048Sminshall 	if (initconn()) {
649*26048Sminshall 		(void) signal(SIGINT, oldintr);
650*26048Sminshall 		code = -1;
651*26048Sminshall 		return;
652*26048Sminshall 	}
653*26048Sminshall 	if (setjmp(recvabort)) {
654*26048Sminshall 		goto abort;
655*26048Sminshall 	}
656*26048Sminshall 	if (strcmp(cmd, "RETR") && type != TYPE_A) {
657*26048Sminshall 		oldtype = type;
658*26048Sminshall 		oldverbose = verbose;
659*26048Sminshall 		if (!debug) {
660*26048Sminshall 			verbose = 0;
661*26048Sminshall 		}
662*26048Sminshall 		setascii();
663*26048Sminshall 		verbose = oldverbose;
664*26048Sminshall 	}
66510296Ssam 	if (remote) {
666*26048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
667*26048Sminshall 			(void) signal(SIGINT, oldintr);
668*26048Sminshall 			if (oldtype) {
669*26048Sminshall 				if (!debug) {
670*26048Sminshall 					verbose = 0;
671*26048Sminshall 				}
672*26048Sminshall 				switch (oldtype) {
673*26048Sminshall 					case TYPE_I:
674*26048Sminshall 						setbinary();
675*26048Sminshall 						break;
676*26048Sminshall 					case TYPE_E:
677*26048Sminshall 						setebcdic();
678*26048Sminshall 						break;
679*26048Sminshall 					case TYPE_L:
680*26048Sminshall 						settenex();
681*26048Sminshall 						break;
682*26048Sminshall 				}
683*26048Sminshall 				verbose = oldverbose;
684*26048Sminshall 			}
685*26048Sminshall 			return;
686*26048Sminshall 		}
687*26048Sminshall 	} else {
688*26048Sminshall 		if (command("%s", cmd) != PRELIM) {
689*26048Sminshall 			(void) signal(SIGINT, oldintr);
690*26048Sminshall 			if (oldtype) {
691*26048Sminshall 				if (!debug) {
692*26048Sminshall 					verbose = 0;
693*26048Sminshall 				}
694*26048Sminshall 				switch (oldtype) {
695*26048Sminshall 					case TYPE_I:
696*26048Sminshall 						setbinary();
697*26048Sminshall 						break;
698*26048Sminshall 					case TYPE_E:
699*26048Sminshall 						setebcdic();
700*26048Sminshall 						break;
701*26048Sminshall 					case TYPE_L:
702*26048Sminshall 						settenex();
703*26048Sminshall 						break;
704*26048Sminshall 				}
705*26048Sminshall 				verbose = oldverbose;
706*26048Sminshall 			}
707*26048Sminshall 			return;
708*26048Sminshall 		}
709*26048Sminshall 	}
710*26048Sminshall 	din = dataconn("r");
711*26048Sminshall 	if (din == NULL)
712*26048Sminshall 		goto abort;
713*26048Sminshall 	if (strcmp(local, "-") == 0) {
71410296Ssam 		fout = stdout;
715*26048Sminshall 	}
71610296Ssam 	else if (*local == '|') {
717*26048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
718*26048Sminshall 		fout = popen(local + 1, "w");
719*26048Sminshall 		if (fout == NULL) {
720*26048Sminshall 			perror(local+1);
721*26048Sminshall 			goto abort;
722*26048Sminshall 		}
72310296Ssam 		closefunc = pclose;
724*26048Sminshall 	}
725*26048Sminshall 	else {
72611651Ssam 		fout = fopen(local, mode);
727*26048Sminshall 		if (fout == NULL) {
728*26048Sminshall 			perror(local);
729*26048Sminshall 			goto abort;
730*26048Sminshall 		}
73110296Ssam 		closefunc = fclose;
73210296Ssam 	}
73310296Ssam 	gettimeofday(&start, (struct timezone *)0);
73411219Ssam 	switch (type) {
73511219Ssam 
73611219Ssam 	case TYPE_I:
73711219Ssam 	case TYPE_L:
73811346Ssam 		errno = d = 0;
73911219Ssam 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0) {
74011346Ssam 			if ((d = write(fileno(fout), buf, c)) < 0)
74111219Ssam 				break;
74211219Ssam 			bytes += c;
74311651Ssam 			if (hash) {
74411651Ssam 				putchar('#');
74511651Ssam 				fflush(stdout);
74611651Ssam 			}
74711219Ssam 		}
74813213Ssam 		if (hash && bytes > 0) {
74911651Ssam 			putchar('\n');
75011651Ssam 			fflush(stdout);
75111651Ssam 		}
75211219Ssam 		if (c < 0)
75311219Ssam 			perror("netin");
75411346Ssam 		if (d < 0)
75510296Ssam 			perror(local);
75611219Ssam 		break;
75711219Ssam 
75811219Ssam 	case TYPE_A:
75911219Ssam 		while ((c = getc(din)) != EOF) {
76011219Ssam 			if (c == '\r') {
76111651Ssam 				while (hash && (bytes >= hashbytes)) {
76211651Ssam 					putchar('#');
76311651Ssam 					fflush(stdout);
76411651Ssam 					hashbytes += sizeof (buf);
76511651Ssam 				}
76610296Ssam 				bytes++;
767*26048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
76811219Ssam 					if (ferror (fout))
76911219Ssam 						break;
77011219Ssam 					putc ('\r', fout);
77111219Ssam 				}
772*26048Sminshall 				/*if (c == '\0') {
77311219Ssam 					bytes++;
77411219Ssam 					continue;
775*26048Sminshall 				}*/
77611219Ssam 			}
77711219Ssam 			putc (c, fout);
77811219Ssam 			bytes++;
77910296Ssam 		}
78011651Ssam 		if (hash) {
78113213Ssam 			if (bytes < hashbytes)
78213213Ssam 				putchar('#');
78311651Ssam 			putchar('\n');
78411651Ssam 			fflush(stdout);
78511651Ssam 		}
78611219Ssam 		if (ferror (din))
78711219Ssam 			perror ("netin");
78811219Ssam 		if (ferror (fout))
78911219Ssam 			perror (local);
79011219Ssam 		break;
79110296Ssam 	}
792*26048Sminshall 	if (closefunc != NULL) {
793*26048Sminshall 		(*closefunc)(fout);
794*26048Sminshall 	}
795*26048Sminshall 	signal(SIGINT, oldintr);
796*26048Sminshall 	if (oldintp) {
797*26048Sminshall 		(void) signal(SIGPIPE, oldintp);
798*26048Sminshall 	}
79910296Ssam 	gettimeofday(&stop, (struct timezone *)0);
80010296Ssam 	(void) fclose(din);
801*26048Sminshall 	(void) getreply(0);
802*26048Sminshall 	if (bytes > 0 && verbose)
803*26048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
804*26048Sminshall 	if (oldtype) {
805*26048Sminshall 		if (!debug) {
806*26048Sminshall 			verbose = 0;
807*26048Sminshall 		}
808*26048Sminshall 		switch (oldtype) {
809*26048Sminshall 			case TYPE_I:
810*26048Sminshall 				setbinary();
811*26048Sminshall 				break;
812*26048Sminshall 			case TYPE_E:
813*26048Sminshall 				setebcdic();
814*26048Sminshall 				break;
815*26048Sminshall 			case TYPE_L:
816*26048Sminshall 				settenex();
817*26048Sminshall 				break;
818*26048Sminshall 		}
819*26048Sminshall 		verbose = oldverbose;
820*26048Sminshall 	}
821*26048Sminshall 	return;
822*26048Sminshall abort:
823*26048Sminshall 
824*26048Sminshall /* if server command parser understands TELNET commands, abort using */
825*26048Sminshall /* recommended IP,SYNC sequence                                      */
826*26048Sminshall 
827*26048Sminshall 	gettimeofday(&stop, (struct timezone *)0);
828*26048Sminshall 	if (oldintp) {
829*26048Sminshall 		(void) signal(SIGPIPE, oldintr);
830*26048Sminshall 	}
831*26048Sminshall 	(void) signal(SIGINT,SIG_IGN);
832*26048Sminshall 	if (oldtype) {
833*26048Sminshall 		if (!debug) {
834*26048Sminshall 			verbose = 0;
835*26048Sminshall 		}
836*26048Sminshall 		switch (oldtype) {
837*26048Sminshall 			case TYPE_I:
838*26048Sminshall 				setbinary();
839*26048Sminshall 				break;
840*26048Sminshall 			case TYPE_E:
841*26048Sminshall 				setebcdic();
842*26048Sminshall 				break;
843*26048Sminshall 			case TYPE_L:
844*26048Sminshall 				settenex();
845*26048Sminshall 				break;
846*26048Sminshall 		}
847*26048Sminshall 		verbose = oldverbose;
848*26048Sminshall 	}
849*26048Sminshall 	if (!cpend) {
850*26048Sminshall 		code = -1;
851*26048Sminshall 		(void) signal(SIGINT,oldintr);
852*26048Sminshall 		return;
853*26048Sminshall 	}
854*26048Sminshall 	if (telflag) {
855*26048Sminshall 		char msg[2];
856*26048Sminshall 
857*26048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
858*26048Sminshall 		(void) fflush(cout);
859*26048Sminshall 		*msg = IAC;
860*26048Sminshall 		*(msg+1) = DM;
861*26048Sminshall 		if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
862*26048Sminshall 			perror("abort");
863*26048Sminshall 		}
864*26048Sminshall 	}
865*26048Sminshall 	fprintf(cout,"ABOR\r\n");
866*26048Sminshall 	(void) fflush(cout);
867*26048Sminshall 	mask = (1 << fileno(cin)) | (din ? (1 << fileno(din)) : 0);
868*26048Sminshall 	if ((mask = empty(mask,10)) < 0) {
869*26048Sminshall 		perror("abort");
870*26048Sminshall 		code = -1;
871*26048Sminshall 		lostpeer();
872*26048Sminshall 	}
873*26048Sminshall 	if (din && mask & (1 << fileno(din))) {
874*26048Sminshall 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0);
875*26048Sminshall 	}
876*26048Sminshall 	if ((c = getreply(0)) == ERROR) { /* needed for nic style abort */
877*26048Sminshall 		if (data >= 0) {
878*26048Sminshall 			close(data);
879*26048Sminshall 			data = -1;
880*26048Sminshall 		}
88125907Smckusick 		(void) getreply(0);
88225907Smckusick 	}
883*26048Sminshall 	(void) getreply(0);
884*26048Sminshall 	code = -1;
885*26048Sminshall 	if (data >= 0) {
886*26048Sminshall 		(void) close(data);
887*26048Sminshall 		data = -1;
888*26048Sminshall 	}
889*26048Sminshall 	if (closefunc != NULL && fout != NULL) {
890*26048Sminshall 		(*closefunc)(fout);
891*26048Sminshall 	}
892*26048Sminshall 	if (din) {
893*26048Sminshall 		(void) fclose(din);
894*26048Sminshall 	}
89510296Ssam 	if (bytes > 0 && verbose)
896*26048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
897*26048Sminshall 	(void) signal(SIGINT,oldintr);
89810296Ssam }
89910296Ssam 
90010296Ssam /*
90110296Ssam  * Need to start a listen on the data channel
90210296Ssam  * before we send the command, otherwise the
90310296Ssam  * server's connect may fail.
90410296Ssam  */
90511651Ssam static int sendport = -1;
90611651Ssam 
90710296Ssam initconn()
90810296Ssam {
90910296Ssam 	register char *p, *a;
910*26048Sminshall 	int result, len, tmpno = 0;
91117450Slepreau 	int on = 1;
91210296Ssam 
91311651Ssam noport:
91410296Ssam 	data_addr = myctladdr;
91511651Ssam 	if (sendport)
91611651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
91711651Ssam 	if (data != -1)
91811651Ssam 		(void) close (data);
91918287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
92010296Ssam 	if (data < 0) {
92110296Ssam 		perror("ftp: socket");
922*26048Sminshall 		if (tmpno) {
923*26048Sminshall 			sendport = 1;
924*26048Sminshall 		}
92510296Ssam 		return (1);
92610296Ssam 	}
92712397Ssam 	if (!sendport)
92817450Slepreau 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) {
929*26048Sminshall 			perror("ftp: setsockopt (resuse address)");
93012397Ssam 			goto bad;
93112397Ssam 		}
93210296Ssam 	if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) {
93310296Ssam 		perror("ftp: bind");
93410296Ssam 		goto bad;
93510296Ssam 	}
93610296Ssam 	if (options & SO_DEBUG &&
93717450Slepreau 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
93810296Ssam 		perror("ftp: setsockopt (ignored)");
93911627Ssam 	len = sizeof (data_addr);
94011627Ssam 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
94111627Ssam 		perror("ftp: getsockname");
94210296Ssam 		goto bad;
94310296Ssam 	}
94410296Ssam 	if (listen(data, 1) < 0) {
94510296Ssam 		perror("ftp: listen");
946*26048Sminshall 
94710296Ssam 	}
94811651Ssam 	if (sendport) {
94911651Ssam 		a = (char *)&data_addr.sin_addr;
95011651Ssam 		p = (char *)&data_addr.sin_port;
95110296Ssam #define	UC(b)	(((int)b)&0xff)
95211651Ssam 		result =
95311651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
95411651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
95511651Ssam 		      UC(p[0]), UC(p[1]));
95611651Ssam 		if (result == ERROR && sendport == -1) {
95711651Ssam 			sendport = 0;
958*26048Sminshall 			tmpno = 1;
95911651Ssam 			goto noport;
96011651Ssam 		}
96111651Ssam 		return (result != COMPLETE);
96211651Ssam 	}
963*26048Sminshall 	if (tmpno) {
964*26048Sminshall 		sendport = 1;
965*26048Sminshall 	}
96611651Ssam 	return (0);
96710296Ssam bad:
96810296Ssam 	(void) close(data), data = -1;
969*26048Sminshall 	if (tmpno) {
970*26048Sminshall 		sendport = 1;
971*26048Sminshall 	}
97210296Ssam 	return (1);
97310296Ssam }
97410296Ssam 
97510296Ssam FILE *
97610296Ssam dataconn(mode)
97710296Ssam 	char *mode;
97810296Ssam {
97910296Ssam 	struct sockaddr_in from;
98010296Ssam 	int s, fromlen = sizeof (from);
98110296Ssam 
98210296Ssam 	s = accept(data, &from, &fromlen, 0);
98310296Ssam 	if (s < 0) {
98410296Ssam 		perror("ftp: accept");
98510296Ssam 		(void) close(data), data = -1;
98610296Ssam 		return (NULL);
98710296Ssam 	}
98810296Ssam 	(void) close(data);
98910296Ssam 	data = s;
99010296Ssam 	return (fdopen(data, mode));
99110296Ssam }
99210296Ssam 
993*26048Sminshall ptransfer(direction, bytes, t0, t1, local, remote)
994*26048Sminshall 	char *direction, *local, *remote;
99511651Ssam 	long bytes;
99610296Ssam 	struct timeval *t0, *t1;
99710296Ssam {
99810296Ssam 	struct timeval td;
99916437Sleres 	float s, bs;
100010296Ssam 
100110296Ssam 	tvsub(&td, t1, t0);
100216437Sleres 	s = td.tv_sec + (td.tv_usec / 1000000.);
100310296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
100416437Sleres 	bs = bytes / nz(s);
1005*26048Sminshall 	if (local && *local != '-') {
1006*26048Sminshall 		printf("local: %s ", local);
1007*26048Sminshall 	}
1008*26048Sminshall 	if (remote) {
1009*26048Sminshall 		printf("remote: %s\n", remote);
1010*26048Sminshall 	}
101116437Sleres 	printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
101216437Sleres 		bytes, direction, s, bs / 1024.);
101310296Ssam }
101410296Ssam 
101510296Ssam tvadd(tsum, t0)
101610296Ssam 	struct timeval *tsum, *t0;
101710296Ssam {
101810296Ssam 
101910296Ssam 	tsum->tv_sec += t0->tv_sec;
102010296Ssam 	tsum->tv_usec += t0->tv_usec;
102110296Ssam 	if (tsum->tv_usec > 1000000)
102210296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
102310296Ssam }
102410296Ssam 
102510296Ssam tvsub(tdiff, t1, t0)
102610296Ssam 	struct timeval *tdiff, *t1, *t0;
102710296Ssam {
102810296Ssam 
102910296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
103010296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
103110296Ssam 	if (tdiff->tv_usec < 0)
103210296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
103310296Ssam }
1034*26048Sminshall 
1035*26048Sminshall psabort()
1036*26048Sminshall {
1037*26048Sminshall 	extern int abrtflag;
1038*26048Sminshall 
1039*26048Sminshall 	abrtflag++;
1040*26048Sminshall }
1041*26048Sminshall 
1042*26048Sminshall pswitch(flag)
1043*26048Sminshall 	int flag;
1044*26048Sminshall {
1045*26048Sminshall 	extern int proxy, abrtflag;
1046*26048Sminshall 	int (*oldintr)();
1047*26048Sminshall 	static struct comvars {
1048*26048Sminshall 		int connect;
1049*26048Sminshall 		char name[32];
1050*26048Sminshall 		struct sockaddr_in mctl;
1051*26048Sminshall 		struct sockaddr_in hctl;
1052*26048Sminshall 		FILE *in;
1053*26048Sminshall 		FILE *out;
1054*26048Sminshall 		int tflag;
1055*26048Sminshall 		int tpe;
1056*26048Sminshall 		int cpnd;
1057*26048Sminshall 		int sunqe;
1058*26048Sminshall 		int runqe;
1059*26048Sminshall 		int mcse;
1060*26048Sminshall 		int ntflg;
1061*26048Sminshall 		char nti[17];
1062*26048Sminshall 		char nto[17];
1063*26048Sminshall 		int mapflg;
1064*26048Sminshall 		char mi[MAXPATHLEN];
1065*26048Sminshall 		char mo[MAXPATHLEN];
1066*26048Sminshall 		} proxstruct, tmpstruct;
1067*26048Sminshall 	struct comvars *ip, *op;
1068*26048Sminshall 
1069*26048Sminshall 	abrtflag = 0;
1070*26048Sminshall 	oldintr = signal(SIGINT, psabort);
1071*26048Sminshall 	if (flag) {
1072*26048Sminshall 		if (proxy) {
1073*26048Sminshall 			return;
1074*26048Sminshall 		}
1075*26048Sminshall 		ip = &tmpstruct;
1076*26048Sminshall 		op = &proxstruct;
1077*26048Sminshall 		proxy++;
1078*26048Sminshall 	}
1079*26048Sminshall 	else {
1080*26048Sminshall 		if (!proxy) {
1081*26048Sminshall 			return;
1082*26048Sminshall 		}
1083*26048Sminshall 		ip = &proxstruct;
1084*26048Sminshall 		op = &tmpstruct;
1085*26048Sminshall 		proxy = 0;
1086*26048Sminshall 	}
1087*26048Sminshall 	ip->connect = connected;
1088*26048Sminshall 	connected = op->connect;
1089*26048Sminshall 	strncpy(ip->name, hostname, 31);
1090*26048Sminshall 	(ip->name)[strlen(ip->name)] = '\0';
1091*26048Sminshall 	hostname = op->name;
1092*26048Sminshall 	ip->hctl = hisctladdr;
1093*26048Sminshall 	hisctladdr = op->hctl;
1094*26048Sminshall 	ip->mctl = myctladdr;
1095*26048Sminshall 	myctladdr = op->mctl;
1096*26048Sminshall 	ip->in = cin;
1097*26048Sminshall 	cin = op->in;
1098*26048Sminshall 	ip->out = cout;
1099*26048Sminshall 	cout = op->out;
1100*26048Sminshall 	ip->tflag = telflag;
1101*26048Sminshall 	telflag = op->tflag;
1102*26048Sminshall 	ip->tpe = type;
1103*26048Sminshall 	type = op->tpe;
1104*26048Sminshall 	if (!type) {
1105*26048Sminshall 		type = 1;
1106*26048Sminshall 	}
1107*26048Sminshall 	ip->cpnd = cpend;
1108*26048Sminshall 	cpend = op->cpnd;
1109*26048Sminshall 	ip->sunqe = sunique;
1110*26048Sminshall 	sunique = op->sunqe;
1111*26048Sminshall 	ip->runqe = runique;
1112*26048Sminshall 	runique = op->runqe;
1113*26048Sminshall 	ip->mcse = mcase;
1114*26048Sminshall 	mcase = op->mcse;
1115*26048Sminshall 	ip->ntflg = ntflag;
1116*26048Sminshall 	ntflag = op->ntflg;
1117*26048Sminshall 	strncpy(ip->nti, ntin, 16);
1118*26048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
1119*26048Sminshall 	strcpy(ntin, op->nti);
1120*26048Sminshall 	strncpy(ip->nto, ntout, 16);
1121*26048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
1122*26048Sminshall 	strcpy(ntout, op->nto);
1123*26048Sminshall 	ip->mapflg = mapflag;
1124*26048Sminshall 	mapflag = op->mapflg;
1125*26048Sminshall 	strncpy(ip->mi, mapin, MAXPATHLEN - 1);
1126*26048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
1127*26048Sminshall 	strcpy(mapin, op->mi);
1128*26048Sminshall 	strncpy(ip->mo, mapout, MAXPATHLEN - 1);
1129*26048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
1130*26048Sminshall 	strcpy(mapout, op->mo);
1131*26048Sminshall 	(void) signal(SIGINT, oldintr);
1132*26048Sminshall 	if (abrtflag) {
1133*26048Sminshall 		abrtflag = 0;
1134*26048Sminshall 		(*oldintr)();
1135*26048Sminshall 		}
1136*26048Sminshall }
1137*26048Sminshall 
1138*26048Sminshall jmp_buf ptabort;
1139*26048Sminshall int ptabflg;
1140*26048Sminshall 
1141*26048Sminshall abortpt()
1142*26048Sminshall {
1143*26048Sminshall 	printf("\n");
1144*26048Sminshall 	fflush(stdout);
1145*26048Sminshall 	ptabflg++;
1146*26048Sminshall 	mflag = 0;
1147*26048Sminshall 	abrtflag = 0;
1148*26048Sminshall 	longjmp(ptabort, 1);
1149*26048Sminshall }
1150*26048Sminshall 
1151*26048Sminshall proxtrans(cmd, local, remote)
1152*26048Sminshall 	char *cmd, *local, *remote;
1153*26048Sminshall {
1154*26048Sminshall 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0;
1155*26048Sminshall 	extern jmp_buf ptabort;
1156*26048Sminshall 	char *cmd2;
1157*26048Sminshall 	long mask;
1158*26048Sminshall 
1159*26048Sminshall 	if (strcmp(cmd, "RETR")) {
1160*26048Sminshall 		cmd2 = "RETR";
1161*26048Sminshall 	}
1162*26048Sminshall 	else {
1163*26048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
1164*26048Sminshall 	}
1165*26048Sminshall 	if (command("PASV") != COMPLETE) {
1166*26048Sminshall 		printf("proxy server does not support third part transfers.\n");
1167*26048Sminshall 		return;
1168*26048Sminshall 	}
1169*26048Sminshall 	tmptype = type;
1170*26048Sminshall 	pswitch(0);
1171*26048Sminshall 	if (!connected) {
1172*26048Sminshall 		printf("No primary connection\n");
1173*26048Sminshall 		pswitch(1);
1174*26048Sminshall 		code = -1;
1175*26048Sminshall 		return;
1176*26048Sminshall 	}
1177*26048Sminshall 	if (type != tmptype) {
1178*26048Sminshall 		oldtype = type;
1179*26048Sminshall 		switch (tmptype) {
1180*26048Sminshall 			case TYPE_A:
1181*26048Sminshall 				setascii();
1182*26048Sminshall 				break;
1183*26048Sminshall 			case TYPE_I:
1184*26048Sminshall 				setbinary();
1185*26048Sminshall 				break;
1186*26048Sminshall 			case TYPE_E:
1187*26048Sminshall 				setebcdic();
1188*26048Sminshall 				break;
1189*26048Sminshall 			case TYPE_L:
1190*26048Sminshall 				settenex();
1191*26048Sminshall 				break;
1192*26048Sminshall 		}
1193*26048Sminshall 	}
1194*26048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
1195*26048Sminshall 		switch (oldtype) {
1196*26048Sminshall 			case 0:
1197*26048Sminshall 				break;
1198*26048Sminshall 			case TYPE_A:
1199*26048Sminshall 				setascii();
1200*26048Sminshall 				break;
1201*26048Sminshall 			case TYPE_I:
1202*26048Sminshall 				setbinary();
1203*26048Sminshall 				break;
1204*26048Sminshall 			case TYPE_E:
1205*26048Sminshall 				setebcdic();
1206*26048Sminshall 				break;
1207*26048Sminshall 			case TYPE_L:
1208*26048Sminshall 				settenex();
1209*26048Sminshall 				break;
1210*26048Sminshall 		}
1211*26048Sminshall 		pswitch(1);
1212*26048Sminshall 		return;
1213*26048Sminshall 	}
1214*26048Sminshall 	if (setjmp(ptabort)) {
1215*26048Sminshall 		goto abort;
1216*26048Sminshall 	}
1217*26048Sminshall 	oldintr = signal(SIGINT, abortpt);
1218*26048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
1219*26048Sminshall 		(void) signal(SIGINT, oldintr);
1220*26048Sminshall 		switch (oldtype) {
1221*26048Sminshall 			case 0:
1222*26048Sminshall 				break;
1223*26048Sminshall 			case TYPE_A:
1224*26048Sminshall 				setascii();
1225*26048Sminshall 				break;
1226*26048Sminshall 			case TYPE_I:
1227*26048Sminshall 				setbinary();
1228*26048Sminshall 				break;
1229*26048Sminshall 			case TYPE_E:
1230*26048Sminshall 				setebcdic();
1231*26048Sminshall 				break;
1232*26048Sminshall 			case TYPE_L:
1233*26048Sminshall 				settenex();
1234*26048Sminshall 				break;
1235*26048Sminshall 		}
1236*26048Sminshall 		pswitch(1);
1237*26048Sminshall 		return;
1238*26048Sminshall 	}
1239*26048Sminshall 	sleep(2);
1240*26048Sminshall 	pswitch(1);
1241*26048Sminshall 	secndflag++;
1242*26048Sminshall 	if (command("%s %s", cmd2, local) != PRELIM) {
1243*26048Sminshall 		goto abort;
1244*26048Sminshall 	}
1245*26048Sminshall 	ptflag++;
1246*26048Sminshall 	(void) getreply(0);
1247*26048Sminshall 	pswitch(0);
1248*26048Sminshall 	(void) getreply(0);
1249*26048Sminshall 	(void) signal(SIGINT, oldintr);
1250*26048Sminshall 	switch (oldtype) {
1251*26048Sminshall 		case 0:
1252*26048Sminshall 			break;
1253*26048Sminshall 		case TYPE_A:
1254*26048Sminshall 			setascii();
1255*26048Sminshall 			break;
1256*26048Sminshall 		case TYPE_I:
1257*26048Sminshall 			setbinary();
1258*26048Sminshall 			break;
1259*26048Sminshall 		case TYPE_E:
1260*26048Sminshall 			setebcdic();
1261*26048Sminshall 			break;
1262*26048Sminshall 		case TYPE_L:
1263*26048Sminshall 			settenex();
1264*26048Sminshall 			break;
1265*26048Sminshall 	}
1266*26048Sminshall 	pswitch(1);
1267*26048Sminshall 	ptflag = 0;
1268*26048Sminshall 	printf("local: %s remote: %s\n", local, remote);
1269*26048Sminshall 	return;
1270*26048Sminshall abort:
1271*26048Sminshall 	(void) signal(SIGINT, SIG_IGN);
1272*26048Sminshall 	ptflag = 0;
1273*26048Sminshall 	if (strcmp(cmd, "RETR") && !proxy) {
1274*26048Sminshall 		pswitch(1);
1275*26048Sminshall 	}
1276*26048Sminshall 	else if (!strcmp(cmd, "RETR") && proxy) {
1277*26048Sminshall 		pswitch(0);
1278*26048Sminshall 	}
1279*26048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
1280*26048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
1281*26048Sminshall 			pswitch(0);
1282*26048Sminshall 			switch (oldtype) {
1283*26048Sminshall 				case 0:
1284*26048Sminshall 					break;
1285*26048Sminshall 				case TYPE_A:
1286*26048Sminshall 					setascii();
1287*26048Sminshall 					break;
1288*26048Sminshall 				case TYPE_I:
1289*26048Sminshall 					setbinary();
1290*26048Sminshall 					break;
1291*26048Sminshall 				case TYPE_E:
1292*26048Sminshall 					setebcdic();
1293*26048Sminshall 					break;
1294*26048Sminshall 				case TYPE_L:
1295*26048Sminshall 					settenex();
1296*26048Sminshall 					break;
1297*26048Sminshall 			}
1298*26048Sminshall 			if (cpend && telflag) {
1299*26048Sminshall 				char msg[2];
1300*26048Sminshall 
1301*26048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
1302*26048Sminshall 				(void) fflush(cout);
1303*26048Sminshall 				*msg = IAC;
1304*26048Sminshall 				*(msg+1) = DM;
1305*26048Sminshall 				if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
1306*26048Sminshall 					perror("abort");
1307*26048Sminshall 				}
1308*26048Sminshall 			}
1309*26048Sminshall 			if (cpend) {
1310*26048Sminshall 				fprintf(cout,"ABOR\r\n");
1311*26048Sminshall 				(void) fflush(cout);
1312*26048Sminshall 				mask = 1 << fileno(cin);
1313*26048Sminshall 				if ((mask = empty(mask,10)) < 0) {
1314*26048Sminshall 					perror("abort");
1315*26048Sminshall 					if (ptabflg) {
1316*26048Sminshall 						code = -1;
1317*26048Sminshall 					}
1318*26048Sminshall 					lostpeer();
1319*26048Sminshall 				}
1320*26048Sminshall 				(void) getreply(0);
1321*26048Sminshall 				(void) getreply(0);
1322*26048Sminshall 			}
1323*26048Sminshall 		}
1324*26048Sminshall 		pswitch(1);
1325*26048Sminshall 		if (ptabflg) {
1326*26048Sminshall 			code = -1;
1327*26048Sminshall 		}
1328*26048Sminshall 		(void) signal(SIGINT, oldintr);
1329*26048Sminshall 		return;
1330*26048Sminshall 	}
1331*26048Sminshall 	if (cpend && telflag) {
1332*26048Sminshall 		char msg[2];
1333*26048Sminshall 
1334*26048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
1335*26048Sminshall 		(void) fflush(cout);
1336*26048Sminshall 		*msg = IAC;
1337*26048Sminshall 		*(msg+1) = DM;
1338*26048Sminshall 		if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
1339*26048Sminshall 			perror("abort");
1340*26048Sminshall 		}
1341*26048Sminshall 	}
1342*26048Sminshall 	if (cpend) {
1343*26048Sminshall 		fprintf(cout,"ABOR\r\n");
1344*26048Sminshall 		(void) fflush(cout);
1345*26048Sminshall 		mask = 1 << fileno(cin);
1346*26048Sminshall 		if ((mask = empty(mask,10)) < 0) {
1347*26048Sminshall 			perror("abort");
1348*26048Sminshall 			if (ptabflg) {
1349*26048Sminshall 				code = -1;
1350*26048Sminshall 			}
1351*26048Sminshall 			lostpeer();
1352*26048Sminshall 		}
1353*26048Sminshall 		(void) getreply(0);
1354*26048Sminshall 		(void) getreply(0);
1355*26048Sminshall 	}
1356*26048Sminshall 	pswitch(!proxy);
1357*26048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
1358*26048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
1359*26048Sminshall 			pswitch(0);
1360*26048Sminshall 			switch (oldtype) {
1361*26048Sminshall 				case 0:
1362*26048Sminshall 					break;
1363*26048Sminshall 				case TYPE_A:
1364*26048Sminshall 					setascii();
1365*26048Sminshall 					break;
1366*26048Sminshall 				case TYPE_I:
1367*26048Sminshall 					setbinary();
1368*26048Sminshall 					break;
1369*26048Sminshall 				case TYPE_E:
1370*26048Sminshall 					setebcdic();
1371*26048Sminshall 					break;
1372*26048Sminshall 				case TYPE_L:
1373*26048Sminshall 					settenex();
1374*26048Sminshall 					break;
1375*26048Sminshall 			}
1376*26048Sminshall 			if (cpend && telflag) {
1377*26048Sminshall 				char msg[2];
1378*26048Sminshall 
1379*26048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
1380*26048Sminshall 				(void) fflush(cout);
1381*26048Sminshall 				*msg = IAC;
1382*26048Sminshall 				*(msg+1) = DM;
1383*26048Sminshall 				if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
1384*26048Sminshall 					perror("abort");
1385*26048Sminshall 				}
1386*26048Sminshall 			}
1387*26048Sminshall 			if (cpend) {
1388*26048Sminshall 				fprintf(cout,"ABOR\r\n");
1389*26048Sminshall 				(void) fflush(cout);
1390*26048Sminshall 				mask = 1 << fileno(cin);
1391*26048Sminshall 				if ((mask = empty(mask,10)) < 0) {
1392*26048Sminshall 					perror("abort");
1393*26048Sminshall 					if (ptabflg) {
1394*26048Sminshall 						code = -1;
1395*26048Sminshall 					}
1396*26048Sminshall 					lostpeer();
1397*26048Sminshall 				}
1398*26048Sminshall 				(void) getreply(0);
1399*26048Sminshall 				(void) getreply(0);
1400*26048Sminshall 			}
1401*26048Sminshall 			pswitch(1);
1402*26048Sminshall 			if (ptabflg) {
1403*26048Sminshall 				code = -1;
1404*26048Sminshall 			}
1405*26048Sminshall 			(void) signal(SIGINT, oldintr);
1406*26048Sminshall 			return;
1407*26048Sminshall 		}
1408*26048Sminshall 	}
1409*26048Sminshall 	if (cpend && telflag) {
1410*26048Sminshall 		char msg[2];
1411*26048Sminshall 
1412*26048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
1413*26048Sminshall 		(void) fflush(cout);
1414*26048Sminshall 		*msg = IAC;
1415*26048Sminshall 		*(msg+1) = DM;
1416*26048Sminshall 		if (send(fileno(cout),msg,2,MSG_OOB) != 2) {
1417*26048Sminshall 			perror("abort");
1418*26048Sminshall 		}
1419*26048Sminshall 	}
1420*26048Sminshall 	if (cpend) {
1421*26048Sminshall 		fprintf(cout,"ABOR\r\n");
1422*26048Sminshall 		(void) fflush(cout);
1423*26048Sminshall 		mask = 1 << fileno(cin);
1424*26048Sminshall 		if ((mask = empty(mask,10)) < 0) {
1425*26048Sminshall 			perror("abort");
1426*26048Sminshall 			if (ptabflg) {
1427*26048Sminshall 				code = -1;
1428*26048Sminshall 			}
1429*26048Sminshall 			lostpeer();
1430*26048Sminshall 		}
1431*26048Sminshall 		(void) getreply(0);
1432*26048Sminshall 		(void) getreply(0);
1433*26048Sminshall 	}
1434*26048Sminshall 	pswitch(!proxy);
1435*26048Sminshall 	if (cpend) {
1436*26048Sminshall 		mask = 1 << fileno(cin);
1437*26048Sminshall 		if ((mask = empty(mask,10)) < 0) {
1438*26048Sminshall 			perror("abort");
1439*26048Sminshall 			if (ptabflg) {
1440*26048Sminshall 				code = -1;
1441*26048Sminshall 			}
1442*26048Sminshall 			lostpeer();
1443*26048Sminshall 		}
1444*26048Sminshall 		(void) getreply(0);
1445*26048Sminshall 		(void) getreply(0);
1446*26048Sminshall 	}
1447*26048Sminshall 	if (proxy) {
1448*26048Sminshall 		pswitch(0);
1449*26048Sminshall 	}
1450*26048Sminshall 	switch (oldtype) {
1451*26048Sminshall 		case 0:
1452*26048Sminshall 			break;
1453*26048Sminshall 		case TYPE_A:
1454*26048Sminshall 			setascii();
1455*26048Sminshall 			break;
1456*26048Sminshall 		case TYPE_I:
1457*26048Sminshall 			setbinary();
1458*26048Sminshall 			break;
1459*26048Sminshall 		case TYPE_E:
1460*26048Sminshall 			setebcdic();
1461*26048Sminshall 			break;
1462*26048Sminshall 		case TYPE_L:
1463*26048Sminshall 			settenex();
1464*26048Sminshall 			break;
1465*26048Sminshall 	}
1466*26048Sminshall 	pswitch(1);
1467*26048Sminshall 	if (ptabflg) {
1468*26048Sminshall 		code = -1;
1469*26048Sminshall 	}
1470*26048Sminshall 	(void) signal(SIGINT, oldintr);
1471*26048Sminshall }
1472*26048Sminshall 
1473*26048Sminshall reset()
1474*26048Sminshall {
1475*26048Sminshall 	long mask;
1476*26048Sminshall 
1477*26048Sminshall 	mask = 1 << fileno(cin);
1478*26048Sminshall 	while (mask > 0) {
1479*26048Sminshall 		if ((mask = empty(mask,0)) < 0) {
1480*26048Sminshall 			perror("reset");
1481*26048Sminshall 			code = -1;
1482*26048Sminshall 			lostpeer();
1483*26048Sminshall 		}
1484*26048Sminshall 		if (mask > 0) {
1485*26048Sminshall 			(void) getreply(0);
1486*26048Sminshall 		}
1487*26048Sminshall 	}
1488*26048Sminshall }
1489*26048Sminshall 
1490*26048Sminshall char *
1491*26048Sminshall gunique(local)
1492*26048Sminshall 	char *local;
1493*26048Sminshall {
1494*26048Sminshall 	static char new[MAXPATHLEN];
1495*26048Sminshall 	char *cp = rindex(local, '/');
1496*26048Sminshall 	int d, count=0;
1497*26048Sminshall 	char ext = '1';
1498*26048Sminshall 
1499*26048Sminshall 	if (cp) {
1500*26048Sminshall 		*cp = '\0';
1501*26048Sminshall 	}
1502*26048Sminshall 	d = access(cp ? local : ".", 2);
1503*26048Sminshall 	if (cp) {
1504*26048Sminshall 		*cp = '/';
1505*26048Sminshall 	}
1506*26048Sminshall 	if (d < 0) {
1507*26048Sminshall 		perror(local);
1508*26048Sminshall 		return((char *) 0);
1509*26048Sminshall 	}
1510*26048Sminshall 	(void) strcpy(new, local);
1511*26048Sminshall 	cp = new + strlen(new);
1512*26048Sminshall 	*cp++ = '.';
1513*26048Sminshall 	while (!d) {
1514*26048Sminshall 		if (++count == 100) {
1515*26048Sminshall 			printf("runique: can't find unique file name.\n");
1516*26048Sminshall 			return((char *) 0);
1517*26048Sminshall 		}
1518*26048Sminshall 		*cp++ = ext;
1519*26048Sminshall 		*cp = '\0';
1520*26048Sminshall 		if (ext == '9') {
1521*26048Sminshall 			ext = '0';
1522*26048Sminshall 		}
1523*26048Sminshall 		else {
1524*26048Sminshall 			ext++;
1525*26048Sminshall 		}
1526*26048Sminshall 		if ((d = access(new, 0)) < 0) {
1527*26048Sminshall 			break;
1528*26048Sminshall 		}
1529*26048Sminshall 		if (ext != '0') {
1530*26048Sminshall 			cp--;
1531*26048Sminshall 		}
1532*26048Sminshall 		else if (*(cp - 2) == '.') {
1533*26048Sminshall 			*(cp - 1) = '1';
1534*26048Sminshall 		}
1535*26048Sminshall 		else {
1536*26048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
1537*26048Sminshall 			cp--;
1538*26048Sminshall 		}
1539*26048Sminshall 	}
1540*26048Sminshall 	return(new);
1541*26048Sminshall }
1542