1/*
2 * Copyright (c) 1985, 1989, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "ftp_locl.h"
35RCSID ("$Id: ftp.c 16650 2006-01-24 08:16:08Z lha $");
36
37struct sockaddr_storage hisctladdr_ss;
38struct sockaddr *hisctladdr = (struct sockaddr *)&hisctladdr_ss;
39struct sockaddr_storage data_addr_ss;
40struct sockaddr *data_addr  = (struct sockaddr *)&data_addr_ss;
41struct sockaddr_storage myctladdr_ss;
42struct sockaddr *myctladdr = (struct sockaddr *)&myctladdr_ss;
43int data = -1;
44int abrtflag = 0;
45jmp_buf ptabort;
46int ptabflg;
47int ptflag = 0;
48off_t restart_point = 0;
49
50
51FILE *cin, *cout;
52
53typedef void (*sighand) (int);
54
55char *
56hookup (const char *host, int port)
57{
58    static char hostnamebuf[MaxHostNameLen];
59    struct addrinfo *ai, *a;
60    struct addrinfo hints;
61    int error;
62    char portstr[NI_MAXSERV];
63    socklen_t len;
64    int s;
65
66    memset (&hints, 0, sizeof(hints));
67    hints.ai_socktype = SOCK_STREAM;
68    hints.ai_protocol = IPPROTO_TCP;
69    hints.ai_flags    = AI_CANONNAME;
70
71    snprintf (portstr, sizeof(portstr), "%u", ntohs(port));
72
73    error = getaddrinfo (host, portstr, &hints, &ai);
74    if (error) {
75	warnx ("%s: %s", host, gai_strerror(error));
76	code = -1;
77	return NULL;
78    }
79    strlcpy (hostnamebuf, host, sizeof(hostnamebuf));
80    hostname = hostnamebuf;
81
82    s = -1;
83    for (a = ai; a != NULL; a = a->ai_next) {
84	s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
85	if (s < 0)
86	    continue;
87
88	if (a->ai_canonname != NULL)
89	    strlcpy (hostnamebuf, a->ai_canonname, sizeof(hostnamebuf));
90
91	memcpy (hisctladdr, a->ai_addr, a->ai_addrlen);
92
93	error = connect (s, a->ai_addr, a->ai_addrlen);
94	if (error < 0) {
95	    char addrstr[256];
96
97	    if (getnameinfo (a->ai_addr, a->ai_addrlen,
98			     addrstr, sizeof(addrstr),
99			     NULL, 0, NI_NUMERICHOST) != 0)
100		strlcpy (addrstr, "unknown address", sizeof(addrstr));
101
102	    warn ("connect %s", addrstr);
103	    close (s);
104	    s = -1;
105	    continue;
106	}
107	break;
108    }
109    freeaddrinfo (ai);
110    if (s < 0) {
111	warnx ("failed to contact %s", host);
112	code = -1;
113	return NULL;
114    }
115
116    len = sizeof(myctladdr_ss);
117    if (getsockname (s, myctladdr, &len) < 0) {
118	warn ("getsockname");
119	code = -1;
120	close (s);
121	return NULL;
122    }
123#ifdef IPTOS_LOWDELAY
124    socket_set_tos (s, IPTOS_LOWDELAY);
125#endif
126    cin = fdopen (s, "r");
127    cout = fdopen (s, "w");
128    if (cin == NULL || cout == NULL) {
129	warnx ("fdopen failed.");
130	if (cin)
131	    fclose (cin);
132	if (cout)
133	    fclose (cout);
134	code = -1;
135	goto bad;
136    }
137    if (verbose)
138	printf ("Connected to %s.\n", hostname);
139    if (getreply (0) > 2) {	/* read startup message from server */
140	if (cin)
141	    fclose (cin);
142	if (cout)
143	    fclose (cout);
144	code = -1;
145	goto bad;
146    }
147#if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
148    {
149	int on = 1;
150
151	if (setsockopt (s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof (on))
152	    < 0 && debug) {
153	    warn ("setsockopt");
154	}
155    }
156#endif				/* SO_OOBINLINE */
157
158    return (hostname);
159bad:
160    close (s);
161    return NULL;
162}
163
164int
165login (char *host)
166{
167    char tmp[80];
168    char defaultpass[128];
169    char *userstr, *pass, *acctstr;
170    int n, aflag = 0;
171
172    char *myname = NULL;
173    struct passwd *pw = k_getpwuid(getuid());
174
175    if (pw != NULL)
176	myname = pw->pw_name;
177
178    userstr = pass = acctstr = 0;
179
180    if(sec_login(host))
181	printf("\n*** Using plaintext user and password ***\n\n");
182    else{
183	printf("Authentication successful.\n\n");
184    }
185
186    if (ruserpass (host, &userstr, &pass, &acctstr) < 0) {
187	code = -1;
188	return (0);
189    }
190    while (userstr == NULL) {
191	if (myname)
192	    printf ("Name (%s:%s): ", host, myname);
193	else
194	    printf ("Name (%s): ", host);
195	*tmp = '\0';
196	if (fgets (tmp, sizeof (tmp) - 1, stdin) != NULL)
197	    tmp[strlen (tmp) - 1] = '\0';
198	if (*tmp == '\0')
199	    userstr = myname;
200	else
201	    userstr = tmp;
202    }
203    strlcpy(username, userstr, sizeof(username));
204    n = command("USER %s", userstr);
205    if (n == COMPLETE)
206       n = command("PASS dummy"); /* DK: Compatibility with gssftp daemon */
207    else if(n == CONTINUE) {
208	if (pass == NULL) {
209	    char prompt[128];
210	    if(myname &&
211	       (!strcmp(userstr, "ftp") || !strcmp(userstr, "anonymous"))) {
212		snprintf(defaultpass, sizeof(defaultpass),
213			 "%s@%s", myname, mydomain);
214		snprintf(prompt, sizeof(prompt),
215			 "Password (%s): ", defaultpass);
216	    } else if (sec_complete) {
217		pass = myname;
218	    } else {
219		*defaultpass = '\0';
220		snprintf(prompt, sizeof(prompt), "Password: ");
221	    }
222	    if (pass == NULL) {
223		pass = defaultpass;
224		UI_UTIL_read_pw_string (tmp, sizeof (tmp), prompt, 0);
225		if (tmp[0])
226		    pass = tmp;
227	    }
228	}
229	n = command ("PASS %s", pass);
230    }
231    if (n == CONTINUE) {
232	aflag++;
233	acctstr = tmp;
234	UI_UTIL_read_pw_string (acctstr, 128, "Account:", 0);
235	n = command ("ACCT %s", acctstr);
236    }
237    if (n != COMPLETE) {
238	warnx ("Login failed.");
239	return (0);
240    }
241    if (!aflag && acctstr != NULL)
242	command ("ACCT %s", acctstr);
243    if (proxy)
244	return (1);
245    for (n = 0; n < macnum; ++n) {
246	if (!strcmp("init", macros[n].mac_name)) {
247	    strlcpy (line, "$init", sizeof (line));
248	    makeargv();
249	    domacro(margc, margv);
250	    break;
251	}
252    }
253    sec_set_protection_level ();
254    return (1);
255}
256
257void
258cmdabort (int sig)
259{
260
261    printf ("\n");
262    fflush (stdout);
263    abrtflag++;
264    if (ptflag)
265	longjmp (ptabort, 1);
266}
267
268int
269command (char *fmt,...)
270{
271    va_list ap;
272    int r;
273    sighand oldintr;
274
275    abrtflag = 0;
276    if (cout == NULL) {
277	warn ("No control connection for command");
278	code = -1;
279	return (0);
280    }
281    oldintr = signal(SIGINT, cmdabort);
282    if(debug){
283	printf("---> ");
284	if (strncmp("PASS ", fmt, 5) == 0)
285	    printf("PASS XXXX");
286	else {
287	    va_start(ap, fmt);
288	    vfprintf(stdout, fmt, ap);
289	    va_end(ap);
290	}
291    }
292    va_start(ap, fmt);
293    sec_vfprintf(cout, fmt, ap);
294    va_end(ap);
295    if(debug){
296	printf("\n");
297	fflush(stdout);
298    }
299    fprintf (cout, "\r\n");
300    fflush (cout);
301    cpend = 1;
302    r = getreply (!strcmp (fmt, "QUIT"));
303    if (abrtflag && oldintr != SIG_IGN)
304	(*oldintr) (SIGINT);
305    signal (SIGINT, oldintr);
306    return (r);
307}
308
309char reply_string[BUFSIZ];	/* last line of previous reply */
310
311int
312getreply (int expecteof)
313{
314    char *p;
315    char *lead_string;
316    int c;
317    struct sigaction sa, osa;
318    char buf[8192];
319    int reply_code;
320    int long_warn = 0;
321
322    sigemptyset (&sa.sa_mask);
323    sa.sa_flags = 0;
324    sa.sa_handler = cmdabort;
325    sigaction (SIGINT, &sa, &osa);
326
327    p = buf;
328
329    reply_code = 0;
330    while (1) {
331	c = getc (cin);
332	switch (c) {
333	case EOF:
334	    if (expecteof) {
335		sigaction (SIGINT, &osa, NULL);
336		code = 221;
337		return 0;
338	    }
339	    lostpeer (0);
340	    if (verbose) {
341		printf ("421 Service not available, "
342			"remote server has closed connection\n");
343		fflush (stdout);
344	    }
345	    code = 421;
346	    return (4);
347	case IAC:
348	    c = getc (cin);
349	    if (c == WILL || c == WONT)
350		fprintf (cout, "%c%c%c", IAC, DONT, getc (cin));
351	    if (c == DO || c == DONT)
352		fprintf (cout, "%c%c%c", IAC, WONT, getc (cin));
353	    continue;
354	case '\n':
355	    *p++ = '\0';
356	    if(isdigit((unsigned char)buf[0])){
357		sscanf(buf, "%d", &code);
358		if(code == 631){
359		    code = 0;
360		    sec_read_msg(buf, prot_safe);
361		    sscanf(buf, "%d", &code);
362		    lead_string = "S:";
363		} else if(code == 632){
364		    code = 0;
365		    sec_read_msg(buf, prot_private);
366		    sscanf(buf, "%d", &code);
367		    lead_string = "P:";
368		}else if(code == 633){
369		    code = 0;
370		    sec_read_msg(buf, prot_confidential);
371		    sscanf(buf, "%d", &code);
372		    lead_string = "C:";
373		}else if(sec_complete)
374		    lead_string = "!!";
375		else
376		    lead_string = "";
377		if(code != 0 && reply_code == 0)
378		    reply_code = code;
379		if (verbose > 0 || (verbose > -1 && code > 499))
380		    fprintf (stdout, "%s%s\n", lead_string, buf);
381		if (code == reply_code && buf[3] == ' ') {
382		    strlcpy (reply_string, buf, sizeof(reply_string));
383		    if (code >= 200)
384			cpend = 0;
385		    sigaction (SIGINT, &osa, NULL);
386		    if (code == 421)
387			lostpeer (0);
388#if 1
389		    if (abrtflag &&
390			osa.sa_handler != cmdabort &&
391			osa.sa_handler != SIG_IGN)
392			osa.sa_handler (SIGINT);
393#endif
394		    if (code == 227 || code == 229) {
395			char *q;
396
397			q = strchr (reply_string, '(');
398			if (q) {
399			    q++;
400			    strlcpy(pasv, q, sizeof(pasv));
401			    q = strrchr(pasv, ')');
402			    if (q)
403				*q = '\0';
404			}
405		    }
406		    return code / 100;
407		}
408	    }else{
409		if(verbose > 0 || (verbose > -1 && code > 499)){
410		    if(sec_complete)
411			fprintf(stdout, "!!");
412		    fprintf(stdout, "%s\n", buf);
413		}
414	    }
415	    p = buf;
416	    long_warn = 0;
417	    continue;
418	default:
419	    if(p < buf + sizeof(buf) - 1)
420		*p++ = c;
421	    else if(long_warn == 0) {
422		fprintf(stderr, "WARNING: incredibly long line received\n");
423		long_warn = 1;
424	    }
425	}
426    }
427
428}
429
430
431#if 0
432int
433getreply (int expecteof)
434{
435    int c, n;
436    int dig;
437    int originalcode = 0, continuation = 0;
438    sighand oldintr;
439    int pflag = 0;
440    char *cp, *pt = pasv;
441
442    oldintr = signal (SIGINT, cmdabort);
443    for (;;) {
444	dig = n = code = 0;
445	cp = reply_string;
446	while ((c = getc (cin)) != '\n') {
447	    if (c == IAC) {	/* handle telnet commands */
448		switch (c = getc (cin)) {
449		case WILL:
450		case WONT:
451		    c = getc (cin);
452		    fprintf (cout, "%c%c%c", IAC, DONT, c);
453		    fflush (cout);
454		    break;
455		case DO:
456		case DONT:
457		    c = getc (cin);
458		    fprintf (cout, "%c%c%c", IAC, WONT, c);
459		    fflush (cout);
460		    break;
461		default:
462		    break;
463		}
464		continue;
465	    }
466	    dig++;
467	    if (c == EOF) {
468		if (expecteof) {
469		    signal (SIGINT, oldintr);
470		    code = 221;
471		    return (0);
472		}
473		lostpeer (0);
474		if (verbose) {
475		    printf ("421 Service not available, remote server has closed connection\n");
476		    fflush (stdout);
477		}
478		code = 421;
479		return (4);
480	    }
481	    if (c != '\r' && (verbose > 0 ||
482			      (verbose > -1 && n == '5' && dig > 4))) {
483		if (proxflag &&
484		    (dig == 1 || dig == 5 && verbose == 0))
485		    printf ("%s:", hostname);
486		putchar (c);
487	    }
488	    if (dig < 4 && isdigit (c))
489		code = code * 10 + (c - '0');
490	    if (!pflag && code == 227)
491		pflag = 1;
492	    if (dig > 4 && pflag == 1 && isdigit (c))
493		pflag = 2;
494	    if (pflag == 2) {
495		if (c != '\r' && c != ')')
496		    *pt++ = c;
497		else {
498		    *pt = '\0';
499		    pflag = 3;
500		}
501	    }
502	    if (dig == 4 && c == '-') {
503		if (continuation)
504		    code = 0;
505		continuation++;
506	    }
507	    if (n == 0)
508		n = c;
509	    if (cp < &reply_string[sizeof (reply_string) - 1])
510		*cp++ = c;
511	}
512	if (verbose > 0 || verbose > -1 && n == '5') {
513	    putchar (c);
514	    fflush (stdout);
515	}
516	if (continuation && code != originalcode) {
517	    if (originalcode == 0)
518		originalcode = code;
519	    continue;
520	}
521	*cp = '\0';
522	if(sec_complete){
523	    if(code == 631)
524		sec_read_msg(reply_string, prot_safe);
525	    else if(code == 632)
526		sec_read_msg(reply_string, prot_private);
527	    else if(code == 633)
528		sec_read_msg(reply_string, prot_confidential);
529	    n = code / 100 + '0';
530	}
531	if (n != '1')
532	    cpend = 0;
533	signal (SIGINT, oldintr);
534	if (code == 421 || originalcode == 421)
535	    lostpeer (0);
536	if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
537	    (*oldintr) (SIGINT);
538	return (n - '0');
539    }
540}
541
542#endif
543
544int
545empty (fd_set * mask, int sec)
546{
547    struct timeval t;
548
549    t.tv_sec = sec;
550    t.tv_usec = 0;
551    return (select (FD_SETSIZE, mask, NULL, NULL, &t));
552}
553
554jmp_buf sendabort;
555
556static RETSIGTYPE
557abortsend (int sig)
558{
559
560    mflag = 0;
561    abrtflag = 0;
562    printf ("\nsend aborted\nwaiting for remote to finish abort\n");
563    fflush (stdout);
564    longjmp (sendabort, 1);
565}
566
567#define HASHBYTES 1024
568
569static int
570copy_stream (FILE * from, FILE * to)
571{
572    static size_t bufsize;
573    static char *buf;
574    int n;
575    int bytes = 0;
576    int werr = 0;
577    int hashbytes = HASHBYTES;
578    struct stat st;
579
580#if defined(HAVE_MMAP) && !defined(NO_MMAP)
581    void *chunk;
582
583#ifndef MAP_FAILED
584#define MAP_FAILED (-1)
585#endif
586
587    if (fstat (fileno (from), &st) == 0 && S_ISREG (st.st_mode)) {
588	/*
589	 * mmap zero bytes has potential of loosing, don't do it.
590	 */
591	if (st.st_size == 0)
592	    return 0;
593	chunk = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fileno (from), 0);
594	if (chunk != (void *) MAP_FAILED) {
595	    int res;
596
597	    res = sec_write (fileno (to), chunk, st.st_size);
598	    if (munmap (chunk, st.st_size) < 0)
599		warn ("munmap");
600	    sec_fflush (to);
601	    return res;
602	}
603    }
604#endif
605
606    buf = alloc_buffer (buf, &bufsize,
607			fstat (fileno (from), &st) >= 0 ? &st : NULL);
608    if (buf == NULL)
609	return -1;
610
611    while ((n = read (fileno (from), buf, bufsize)) > 0) {
612	werr = sec_write (fileno (to), buf, n);
613	if (werr < 0)
614	    break;
615	bytes += werr;
616	while (hash && bytes > hashbytes) {
617	    putchar ('#');
618	    hashbytes += HASHBYTES;
619	}
620    }
621    sec_fflush (to);
622    if (n < 0)
623	warn ("local");
624
625    if (werr < 0) {
626	if (errno != EPIPE)
627	    warn ("netout");
628	bytes = -1;
629    }
630    return bytes;
631}
632
633void
634sendrequest (char *cmd, char *local, char *remote, char *lmode, int printnames)
635{
636    struct stat st;
637    struct timeval start, stop;
638    int c, d;
639    FILE *fin, *dout = 0;
640    int (*closefunc) (FILE *);
641    RETSIGTYPE (*oldintr)(int), (*oldintp)(int);
642    long bytes = 0, hashbytes = HASHBYTES;
643    char *rmode = "w";
644
645    if (verbose && printnames) {
646	if (local && strcmp (local, "-") != 0)
647	    printf ("local: %s ", local);
648	if (remote)
649	    printf ("remote: %s\n", remote);
650    }
651    if (proxy) {
652	proxtrans (cmd, local, remote);
653	return;
654    }
655    if (curtype != type)
656	changetype (type, 0);
657    closefunc = NULL;
658    oldintr = NULL;
659    oldintp = NULL;
660
661    if (setjmp (sendabort)) {
662	while (cpend) {
663	    getreply (0);
664	}
665	if (data >= 0) {
666	    close (data);
667	    data = -1;
668	}
669	if (oldintr)
670	    signal (SIGINT, oldintr);
671	if (oldintp)
672	    signal (SIGPIPE, oldintp);
673	code = -1;
674	return;
675    }
676    oldintr = signal (SIGINT, abortsend);
677    if (strcmp (local, "-") == 0)
678	fin = stdin;
679    else if (*local == '|') {
680	oldintp = signal (SIGPIPE, SIG_IGN);
681	fin = popen (local + 1, lmode);
682	if (fin == NULL) {
683	    warn ("%s", local + 1);
684	    signal (SIGINT, oldintr);
685	    signal (SIGPIPE, oldintp);
686	    code = -1;
687	    return;
688	}
689	closefunc = pclose;
690    } else {
691	fin = fopen (local, lmode);
692	if (fin == NULL) {
693	    warn ("local: %s", local);
694	    signal (SIGINT, oldintr);
695	    code = -1;
696	    return;
697	}
698	closefunc = fclose;
699	if (fstat (fileno (fin), &st) < 0 ||
700	    (st.st_mode & S_IFMT) != S_IFREG) {
701	    fprintf (stdout, "%s: not a plain file.\n", local);
702	    signal (SIGINT, oldintr);
703	    fclose (fin);
704	    code = -1;
705	    return;
706	}
707    }
708    if (initconn ()) {
709	signal (SIGINT, oldintr);
710	if (oldintp)
711	    signal (SIGPIPE, oldintp);
712	code = -1;
713	if (closefunc != NULL)
714	    (*closefunc) (fin);
715	return;
716    }
717    if (setjmp (sendabort))
718	goto abort;
719
720    if (restart_point &&
721	(strcmp (cmd, "STOR") == 0 || strcmp (cmd, "APPE") == 0)) {
722	int rc;
723
724	switch (curtype) {
725	case TYPE_A:
726	    rc = fseek (fin, (long) restart_point, SEEK_SET);
727	    break;
728	case TYPE_I:
729	case TYPE_L:
730	    rc = lseek (fileno (fin), restart_point, SEEK_SET);
731	    break;
732	default:
733	    abort();
734	}
735	if (rc < 0) {
736	    warn ("local: %s", local);
737	    restart_point = 0;
738	    if (closefunc != NULL)
739		(*closefunc) (fin);
740	    return;
741	}
742	if (command ("REST %ld", (long) restart_point)
743	    != CONTINUE) {
744	    restart_point = 0;
745	    if (closefunc != NULL)
746		(*closefunc) (fin);
747	    return;
748	}
749	restart_point = 0;
750	rmode = "r+w";
751    }
752    if (remote) {
753	if (command ("%s %s", cmd, remote) != PRELIM) {
754	    signal (SIGINT, oldintr);
755	    if (oldintp)
756		signal (SIGPIPE, oldintp);
757	    if (closefunc != NULL)
758		(*closefunc) (fin);
759	    return;
760	}
761    } else if (command ("%s", cmd) != PRELIM) {
762	    signal(SIGINT, oldintr);
763	    if (oldintp)
764		signal(SIGPIPE, oldintp);
765	    if (closefunc != NULL)
766		(*closefunc)(fin);
767	    return;
768	}
769    dout = dataconn(rmode);
770    if (dout == NULL)
771	goto abort;
772    set_buffer_size (fileno (dout), 0);
773    gettimeofday (&start, (struct timezone *) 0);
774    oldintp = signal (SIGPIPE, SIG_IGN);
775    switch (curtype) {
776
777    case TYPE_I:
778    case TYPE_L:
779	errno = d = c = 0;
780	bytes = copy_stream (fin, dout);
781	break;
782
783    case TYPE_A:
784	while ((c = getc (fin)) != EOF) {
785	    if (c == '\n') {
786		while (hash && (bytes >= hashbytes)) {
787		    putchar ('#');
788		    fflush (stdout);
789		    hashbytes += HASHBYTES;
790		}
791		if (ferror (dout))
792		    break;
793		sec_putc ('\r', dout);
794		bytes++;
795	    }
796	    sec_putc (c, dout);
797	    bytes++;
798	}
799	sec_fflush (dout);
800	if (hash) {
801	    if (bytes < hashbytes)
802		putchar ('#');
803	    putchar ('\n');
804	    fflush (stdout);
805	}
806	if (ferror (fin))
807	    warn ("local: %s", local);
808	if (ferror (dout)) {
809	    if (errno != EPIPE)
810		warn ("netout");
811	    bytes = -1;
812	}
813	break;
814    }
815    if (closefunc != NULL)
816	(*closefunc) (fin);
817    fclose (dout);
818    gettimeofday (&stop, (struct timezone *) 0);
819    getreply (0);
820    signal (SIGINT, oldintr);
821    if (oldintp)
822	signal (SIGPIPE, oldintp);
823    if (bytes > 0)
824	ptransfer ("sent", bytes, &start, &stop);
825    return;
826abort:
827    signal (SIGINT, oldintr);
828    if (oldintp)
829	signal (SIGPIPE, oldintp);
830    if (!cpend) {
831	code = -1;
832	return;
833    }
834    if (data >= 0) {
835	close (data);
836	data = -1;
837    }
838    if (dout)
839	fclose (dout);
840    getreply (0);
841    code = -1;
842    if (closefunc != NULL && fin != NULL)
843	(*closefunc) (fin);
844    gettimeofday (&stop, (struct timezone *) 0);
845    if (bytes > 0)
846	ptransfer ("sent", bytes, &start, &stop);
847}
848
849jmp_buf recvabort;
850
851void
852abortrecv (int sig)
853{
854
855    mflag = 0;
856    abrtflag = 0;
857    printf ("\nreceive aborted\nwaiting for remote to finish abort\n");
858    fflush (stdout);
859    longjmp (recvabort, 1);
860}
861
862void
863recvrequest (char *cmd, char *local, char *remote,
864	     char *lmode, int printnames, int local_given)
865{
866    FILE *fout = NULL, *din = NULL;
867    int (*closefunc) (FILE *);
868    sighand oldintr, oldintp;
869    int c, d, is_retr, tcrflag, bare_lfs = 0;
870    static size_t bufsize;
871    static char *buf;
872    long bytes = 0, hashbytes = HASHBYTES;
873    struct timeval start, stop;
874    struct stat st;
875
876    is_retr = strcmp (cmd, "RETR") == 0;
877    if (is_retr && verbose && printnames) {
878	if (local && strcmp (local, "-") != 0)
879	    printf ("local: %s ", local);
880	if (remote)
881	    printf ("remote: %s\n", remote);
882    }
883    if (proxy && is_retr) {
884	proxtrans (cmd, local, remote);
885	return;
886    }
887    closefunc = NULL;
888    oldintr = NULL;
889    oldintp = NULL;
890    tcrflag = !crflag && is_retr;
891    if (setjmp (recvabort)) {
892	while (cpend) {
893	    getreply (0);
894	}
895	if (data >= 0) {
896	    close (data);
897	    data = -1;
898	}
899	if (oldintr)
900	    signal (SIGINT, oldintr);
901	code = -1;
902	return;
903    }
904    oldintr = signal (SIGINT, abortrecv);
905    if (!local_given || (strcmp (local, "-") && *local != '|')) {
906	if (access (local, 2) < 0) {
907	    char *dir = strrchr (local, '/');
908
909	    if (errno != ENOENT && errno != EACCES) {
910		warn ("local: %s", local);
911		signal (SIGINT, oldintr);
912		code = -1;
913		return;
914	    }
915	    if (dir != NULL)
916		*dir = 0;
917	    d = access (dir ? local : ".", 2);
918	    if (dir != NULL)
919		*dir = '/';
920	    if (d < 0) {
921		warn ("local: %s", local);
922		signal (SIGINT, oldintr);
923		code = -1;
924		return;
925	    }
926	    if (!runique && errno == EACCES &&
927		chmod (local, 0600) < 0) {
928		warn ("local: %s", local);
929		signal (SIGINT, oldintr);
930		signal (SIGINT, oldintr);
931		code = -1;
932		return;
933	    }
934	    if (runique && errno == EACCES &&
935		(local = gunique (local)) == NULL) {
936		signal (SIGINT, oldintr);
937		code = -1;
938		return;
939	    }
940	} else if (runique && (local = gunique (local)) == NULL) {
941	    signal(SIGINT, oldintr);
942	    code = -1;
943	    return;
944	}
945    }
946    if (!is_retr) {
947	if (curtype != TYPE_A)
948	    changetype (TYPE_A, 0);
949    } else if (curtype != type)
950	changetype (type, 0);
951    if (initconn ()) {
952	signal (SIGINT, oldintr);
953	code = -1;
954	return;
955    }
956    if (setjmp (recvabort))
957	goto abort;
958    if (is_retr && restart_point &&
959	command ("REST %ld", (long) restart_point) != CONTINUE)
960	return;
961    if (remote) {
962	if (command ("%s %s", cmd, remote) != PRELIM) {
963	    signal (SIGINT, oldintr);
964	    return;
965	}
966    } else {
967	if (command ("%s", cmd) != PRELIM) {
968	    signal (SIGINT, oldintr);
969	    return;
970	}
971    }
972    din = dataconn ("r");
973    if (din == NULL)
974	goto abort;
975    set_buffer_size (fileno (din), 1);
976    if (local_given && strcmp (local, "-") == 0)
977	fout = stdout;
978    else if (local_given && *local == '|') {
979	oldintp = signal (SIGPIPE, SIG_IGN);
980	fout = popen (local + 1, "w");
981	if (fout == NULL) {
982	    warn ("%s", local + 1);
983	    goto abort;
984	}
985	closefunc = pclose;
986    } else {
987	fout = fopen (local, lmode);
988	if (fout == NULL) {
989	    warn ("local: %s", local);
990	    goto abort;
991	}
992	closefunc = fclose;
993    }
994    buf = alloc_buffer (buf, &bufsize,
995			fstat (fileno (fout), &st) >= 0 ? &st : NULL);
996    if (buf == NULL)
997	goto abort;
998
999    gettimeofday (&start, (struct timezone *) 0);
1000    switch (curtype) {
1001
1002    case TYPE_I:
1003    case TYPE_L:
1004	if (restart_point &&
1005	    lseek (fileno (fout), restart_point, SEEK_SET) < 0) {
1006	    warn ("local: %s", local);
1007	    if (closefunc != NULL)
1008		(*closefunc) (fout);
1009	    return;
1010	}
1011	errno = d = 0;
1012	while ((c = sec_read (fileno (din), buf, bufsize)) > 0) {
1013	    if ((d = write (fileno (fout), buf, c)) != c)
1014		break;
1015	    bytes += c;
1016	    if (hash) {
1017		while (bytes >= hashbytes) {
1018		    putchar ('#');
1019		    hashbytes += HASHBYTES;
1020		}
1021		fflush (stdout);
1022	    }
1023	}
1024	if (hash && bytes > 0) {
1025	    if (bytes < HASHBYTES)
1026		putchar ('#');
1027	    putchar ('\n');
1028	    fflush (stdout);
1029	}
1030	if (c < 0) {
1031	    if (errno != EPIPE)
1032		warn ("netin");
1033	    bytes = -1;
1034	}
1035	if (d < c) {
1036	    if (d < 0)
1037		warn ("local: %s", local);
1038	    else
1039		warnx ("%s: short write", local);
1040	}
1041	break;
1042
1043    case TYPE_A:
1044	if (restart_point) {
1045	    int i, n, ch;
1046
1047	    if (fseek (fout, 0L, SEEK_SET) < 0)
1048		goto done;
1049	    n = restart_point;
1050	    for (i = 0; i++ < n;) {
1051		if ((ch = sec_getc (fout)) == EOF)
1052		    goto done;
1053		if (ch == '\n')
1054		    i++;
1055	    }
1056	    if (fseek (fout, 0L, SEEK_CUR) < 0) {
1057	done:
1058		warn ("local: %s", local);
1059		if (closefunc != NULL)
1060		    (*closefunc) (fout);
1061		return;
1062	    }
1063	}
1064	while ((c = sec_getc(din)) != EOF) {
1065	    if (c == '\n')
1066		bare_lfs++;
1067	    while (c == '\r') {
1068		while (hash && (bytes >= hashbytes)) {
1069		    putchar ('#');
1070		    fflush (stdout);
1071		    hashbytes += HASHBYTES;
1072		}
1073		bytes++;
1074		if ((c = sec_getc (din)) != '\n' || tcrflag) {
1075		    if (ferror (fout))
1076			goto break2;
1077		    putc ('\r', fout);
1078		    if (c == '\0') {
1079			bytes++;
1080			goto contin2;
1081		    }
1082		    if (c == EOF)
1083			goto contin2;
1084		}
1085	    }
1086	    putc (c, fout);
1087	    bytes++;
1088    contin2:;
1089	}
1090break2:
1091	if (bare_lfs) {
1092	    printf ("WARNING! %d bare linefeeds received in ASCII mode\n",
1093		    bare_lfs);
1094	    printf ("File may not have transferred correctly.\n");
1095	}
1096	if (hash) {
1097	    if (bytes < hashbytes)
1098		putchar ('#');
1099	    putchar ('\n');
1100	    fflush (stdout);
1101	}
1102	if (ferror (din)) {
1103	    if (errno != EPIPE)
1104		warn ("netin");
1105	    bytes = -1;
1106	}
1107	if (ferror (fout))
1108	    warn ("local: %s", local);
1109	break;
1110    }
1111    if (closefunc != NULL)
1112	(*closefunc) (fout);
1113    signal (SIGINT, oldintr);
1114    if (oldintp)
1115	signal (SIGPIPE, oldintp);
1116    fclose (din);
1117    gettimeofday (&stop, (struct timezone *) 0);
1118    getreply (0);
1119    if (bytes > 0 && is_retr)
1120	ptransfer ("received", bytes, &start, &stop);
1121    return;
1122abort:
1123
1124    /* abort using RFC959 recommended IP,SYNC sequence  */
1125
1126    if (oldintp)
1127	signal (SIGPIPE, oldintr);
1128    signal (SIGINT, SIG_IGN);
1129    if (!cpend) {
1130	code = -1;
1131	signal (SIGINT, oldintr);
1132	return;
1133    }
1134    abort_remote(din);
1135    code = -1;
1136    if (data >= 0) {
1137	close (data);
1138	data = -1;
1139    }
1140    if (closefunc != NULL && fout != NULL)
1141	(*closefunc) (fout);
1142    if (din)
1143	fclose (din);
1144    gettimeofday (&stop, (struct timezone *) 0);
1145    if (bytes > 0)
1146	ptransfer ("received", bytes, &start, &stop);
1147    signal (SIGINT, oldintr);
1148}
1149
1150static int
1151parse_epsv (const char *str)
1152{
1153    char sep;
1154    char *end;
1155    int port;
1156
1157    if (*str == '\0')
1158	return -1;
1159    sep = *str++;
1160    if (sep != *str++)
1161	return -1;
1162    if (sep != *str++)
1163	return -1;
1164    port = strtol (str, &end, 0);
1165    if (str == end)
1166	return -1;
1167    if (end[0] != sep || end[1] != '\0')
1168	return -1;
1169    return htons(port);
1170}
1171
1172static int
1173parse_pasv (struct sockaddr_in *sin4, const char *str)
1174{
1175    int a0, a1, a2, a3, p0, p1;
1176
1177    /*
1178     * What we've got at this point is a string of comma separated
1179     * one-byte unsigned integer values. The first four are the an IP
1180     * address. The fifth is the MSB of the port number, the sixth is the
1181     * LSB. From that we'll prepare a sockaddr_in.
1182     */
1183
1184    if (sscanf (str, "%d,%d,%d,%d,%d,%d",
1185		&a0, &a1, &a2, &a3, &p0, &p1) != 6) {
1186	printf ("Passive mode address scan failure. "
1187		"Shouldn't happen!\n");
1188	return -1;
1189    }
1190    if (a0 < 0 || a0 > 255 ||
1191	a1 < 0 || a1 > 255 ||
1192	a2 < 0 || a2 > 255 ||
1193	a3 < 0 || a3 > 255 ||
1194	p0 < 0 || p0 > 255 ||
1195	p1 < 0 || p1 > 255) {
1196	printf ("Can't parse passive mode string.\n");
1197	return -1;
1198    }
1199    memset (sin4, 0, sizeof(*sin4));
1200    sin4->sin_family      = AF_INET;
1201    sin4->sin_addr.s_addr = htonl ((a0 << 24) | (a1 << 16) |
1202				  (a2 << 8) | a3);
1203    sin4->sin_port = htons ((p0 << 8) | p1);
1204    return 0;
1205}
1206
1207static int
1208passive_mode (void)
1209{
1210    int port;
1211
1212    data = socket (myctladdr->sa_family, SOCK_STREAM, 0);
1213    if (data < 0) {
1214	warn ("socket");
1215	return (1);
1216    }
1217    if (options & SO_DEBUG)
1218	socket_set_debug (data);
1219    if (command ("EPSV") != COMPLETE) {
1220	if (command ("PASV") != COMPLETE) {
1221	    printf ("Passive mode refused.\n");
1222	    goto bad;
1223	}
1224    }
1225
1226    /*
1227     * Parse the reply to EPSV or PASV
1228     */
1229
1230    port = parse_epsv (pasv);
1231    if (port > 0) {
1232	data_addr->sa_family = myctladdr->sa_family;
1233	socket_set_address_and_port (data_addr,
1234				     socket_get_address (hisctladdr),
1235				     port);
1236    } else {
1237	if (parse_pasv ((struct sockaddr_in *)data_addr, pasv) < 0)
1238	    goto bad;
1239    }
1240
1241    if (connect (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
1242	warn ("connect");
1243	goto bad;
1244    }
1245#ifdef IPTOS_THROUGHPUT
1246    socket_set_tos (data, IPTOS_THROUGHPUT);
1247#endif
1248    return (0);
1249bad:
1250    close (data);
1251    data = -1;
1252    sendport = 1;
1253    return (1);
1254}
1255
1256
1257static int
1258active_mode (void)
1259{
1260    int tmpno = 0;
1261    socklen_t len;
1262    int result;
1263
1264noport:
1265    data_addr->sa_family = myctladdr->sa_family;
1266    socket_set_address_and_port (data_addr, socket_get_address (myctladdr),
1267				 sendport ? 0 : socket_get_port (myctladdr));
1268
1269    if (data != -1)
1270	close (data);
1271    data = socket (data_addr->sa_family, SOCK_STREAM, 0);
1272    if (data < 0) {
1273	warn ("socket");
1274	if (tmpno)
1275	    sendport = 1;
1276	return (1);
1277    }
1278    if (!sendport)
1279	socket_set_reuseaddr (data, 1);
1280    if (bind (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
1281	warn ("bind");
1282	goto bad;
1283    }
1284    if (options & SO_DEBUG)
1285	socket_set_debug (data);
1286    len = sizeof (data_addr_ss);
1287    if (getsockname (data, data_addr, &len) < 0) {
1288	warn ("getsockname");
1289	goto bad;
1290    }
1291    if (listen (data, 1) < 0)
1292	warn ("listen");
1293    if (sendport) {
1294	char addr_str[256];
1295	int inet_af;
1296	int overbose;
1297
1298	if (inet_ntop (data_addr->sa_family, socket_get_address (data_addr),
1299		       addr_str, sizeof(addr_str)) == NULL)
1300	    errx (1, "inet_ntop failed");
1301	switch (data_addr->sa_family) {
1302	case AF_INET :
1303	    inet_af = 1;
1304	    break;
1305#ifdef HAVE_IPV6
1306	case AF_INET6 :
1307	    inet_af = 2;
1308	    break;
1309#endif
1310	default :
1311	    errx (1, "bad address family %d", data_addr->sa_family);
1312	}
1313
1314
1315	overbose = verbose;
1316	if (debug == 0)
1317	    verbose  = -1;
1318
1319	result = command ("EPRT |%d|%s|%d|",
1320			  inet_af, addr_str,
1321			  ntohs(socket_get_port (data_addr)));
1322	verbose = overbose;
1323
1324	if (result == ERROR) {
1325	    struct sockaddr_in *sin4 = (struct sockaddr_in *)data_addr;
1326
1327	    unsigned int a = ntohl(sin4->sin_addr.s_addr);
1328	    unsigned int p = ntohs(sin4->sin_port);
1329
1330	    if (data_addr->sa_family != AF_INET) {
1331		warnx ("remote server doesn't support EPRT");
1332		goto bad;
1333	    }
1334
1335	    result = command("PORT %d,%d,%d,%d,%d,%d",
1336			     (a >> 24) & 0xff,
1337			     (a >> 16) & 0xff,
1338			     (a >> 8) & 0xff,
1339			     a & 0xff,
1340			     (p >> 8) & 0xff,
1341			     p & 0xff);
1342	    if (result == ERROR && sendport == -1) {
1343		sendport = 0;
1344		tmpno = 1;
1345		goto noport;
1346	    }
1347	    return (result != COMPLETE);
1348	}
1349	return result != COMPLETE;
1350    }
1351    if (tmpno)
1352	sendport = 1;
1353
1354
1355#ifdef IPTOS_THROUGHPUT
1356    socket_set_tos (data, IPTOS_THROUGHPUT);
1357#endif
1358    return (0);
1359bad:
1360    close (data);
1361    data = -1;
1362    if (tmpno)
1363	sendport = 1;
1364    return (1);
1365}
1366
1367/*
1368 * Need to start a listen on the data channel before we send the command,
1369 * otherwise the server's connect may fail.
1370 */
1371int
1372initconn (void)
1373{
1374    if (passivemode)
1375	return passive_mode ();
1376    else
1377	return active_mode ();
1378}
1379
1380FILE *
1381dataconn (const char *lmode)
1382{
1383    struct sockaddr_storage from_ss;
1384    struct sockaddr *from = (struct sockaddr *)&from_ss;
1385    socklen_t fromlen = sizeof(from_ss);
1386    int s;
1387
1388    if (passivemode)
1389	return (fdopen (data, lmode));
1390
1391    s = accept (data, from, &fromlen);
1392    if (s < 0) {
1393	warn ("accept");
1394	close (data), data = -1;
1395	return (NULL);
1396    }
1397    close (data);
1398    data = s;
1399#ifdef IPTOS_THROUGHPUT
1400    socket_set_tos (s, IPTOS_THROUGHPUT);
1401#endif
1402    return (fdopen (data, lmode));
1403}
1404
1405void
1406ptransfer (char *direction, long int bytes,
1407	   struct timeval * t0, struct timeval * t1)
1408{
1409    struct timeval td;
1410    float s;
1411    float bs;
1412    int prec;
1413    char *unit;
1414
1415    if (verbose) {
1416	td.tv_sec = t1->tv_sec - t0->tv_sec;
1417	td.tv_usec = t1->tv_usec - t0->tv_usec;
1418	if (td.tv_usec < 0) {
1419	    td.tv_sec--;
1420	    td.tv_usec += 1000000;
1421	}
1422	s = td.tv_sec + (td.tv_usec / 1000000.);
1423	bs = bytes / (s ? s : 1);
1424	if (bs >= 1048576) {
1425	    bs /= 1048576;
1426	    unit = "M";
1427	    prec = 2;
1428	} else if (bs >= 1024) {
1429	    bs /= 1024;
1430	    unit = "k";
1431	    prec = 1;
1432	} else {
1433	    unit = "";
1434	    prec = 0;
1435	}
1436
1437	printf ("%ld bytes %s in %.3g seconds (%.*f %sbyte/s)\n",
1438		bytes, direction, s, prec, bs, unit);
1439    }
1440}
1441
1442void
1443psabort (int sig)
1444{
1445
1446    abrtflag++;
1447}
1448
1449void
1450pswitch (int flag)
1451{
1452    sighand oldintr;
1453    static struct comvars {
1454	int connect;
1455	char name[MaxHostNameLen];
1456	struct sockaddr_storage mctl;
1457	struct sockaddr_storage hctl;
1458	FILE *in;
1459	FILE *out;
1460	int tpe;
1461	int curtpe;
1462	int cpnd;
1463	int sunqe;
1464	int runqe;
1465	int mcse;
1466	int ntflg;
1467	char nti[17];
1468	char nto[17];
1469	int mapflg;
1470	char mi[MaxPathLen];
1471	char mo[MaxPathLen];
1472    } proxstruct, tmpstruct;
1473    struct comvars *ip, *op;
1474
1475    abrtflag = 0;
1476    oldintr = signal (SIGINT, psabort);
1477    if (flag) {
1478	if (proxy)
1479	    return;
1480	ip = &tmpstruct;
1481	op = &proxstruct;
1482	proxy++;
1483    } else {
1484	if (!proxy)
1485	    return;
1486	ip = &proxstruct;
1487	op = &tmpstruct;
1488	proxy = 0;
1489    }
1490    ip->connect = connected;
1491    connected = op->connect;
1492    if (hostname) {
1493	strlcpy (ip->name, hostname, sizeof (ip->name));
1494    } else
1495	ip->name[0] = 0;
1496    hostname = op->name;
1497    ip->hctl = hisctladdr_ss;
1498    hisctladdr_ss = op->hctl;
1499    ip->mctl = myctladdr_ss;
1500    myctladdr_ss = op->mctl;
1501    ip->in = cin;
1502    cin = op->in;
1503    ip->out = cout;
1504    cout = op->out;
1505    ip->tpe = type;
1506    type = op->tpe;
1507    ip->curtpe = curtype;
1508    curtype = op->curtpe;
1509    ip->cpnd = cpend;
1510    cpend = op->cpnd;
1511    ip->sunqe = sunique;
1512    sunique = op->sunqe;
1513    ip->runqe = runique;
1514    runique = op->runqe;
1515    ip->mcse = mcase;
1516    mcase = op->mcse;
1517    ip->ntflg = ntflag;
1518    ntflag = op->ntflg;
1519    strlcpy (ip->nti, ntin, sizeof (ip->nti));
1520    strlcpy (ntin, op->nti, 17);
1521    strlcpy (ip->nto, ntout, sizeof (ip->nto));
1522    strlcpy (ntout, op->nto, 17);
1523    ip->mapflg = mapflag;
1524    mapflag = op->mapflg;
1525    strlcpy (ip->mi, mapin, MaxPathLen);
1526    strlcpy (mapin, op->mi, MaxPathLen);
1527    strlcpy (ip->mo, mapout, MaxPathLen);
1528    strlcpy (mapout, op->mo, MaxPathLen);
1529    signal(SIGINT, oldintr);
1530    if (abrtflag) {
1531	abrtflag = 0;
1532	(*oldintr) (SIGINT);
1533    }
1534}
1535
1536void
1537abortpt (int sig)
1538{
1539
1540    printf ("\n");
1541    fflush (stdout);
1542    ptabflg++;
1543    mflag = 0;
1544    abrtflag = 0;
1545    longjmp (ptabort, 1);
1546}
1547
1548void
1549proxtrans (char *cmd, char *local, char *remote)
1550{
1551    sighand oldintr = NULL;
1552    int secndflag = 0, prox_type, nfnd;
1553    char *cmd2;
1554    fd_set mask;
1555
1556    if (strcmp (cmd, "RETR"))
1557	cmd2 = "RETR";
1558    else
1559	cmd2 = runique ? "STOU" : "STOR";
1560    if ((prox_type = type) == 0) {
1561	if (unix_server && unix_proxy)
1562	    prox_type = TYPE_I;
1563	else
1564	    prox_type = TYPE_A;
1565    }
1566    if (curtype != prox_type)
1567	changetype (prox_type, 1);
1568    if (command ("PASV") != COMPLETE) {
1569	printf ("proxy server does not support third party transfers.\n");
1570	return;
1571    }
1572    pswitch (0);
1573    if (!connected) {
1574	printf ("No primary connection\n");
1575	pswitch (1);
1576	code = -1;
1577	return;
1578    }
1579    if (curtype != prox_type)
1580	changetype (prox_type, 1);
1581    if (command ("PORT %s", pasv) != COMPLETE) {
1582	pswitch (1);
1583	return;
1584    }
1585    if (setjmp (ptabort))
1586	goto abort;
1587    oldintr = signal (SIGINT, abortpt);
1588    if (command ("%s %s", cmd, remote) != PRELIM) {
1589	signal (SIGINT, oldintr);
1590	pswitch (1);
1591	return;
1592    }
1593    sleep (2);
1594    pswitch (1);
1595    secndflag++;
1596    if (command ("%s %s", cmd2, local) != PRELIM)
1597	goto abort;
1598    ptflag++;
1599    getreply (0);
1600    pswitch (0);
1601    getreply (0);
1602    signal (SIGINT, oldintr);
1603    pswitch (1);
1604    ptflag = 0;
1605    printf ("local: %s remote: %s\n", local, remote);
1606    return;
1607abort:
1608    signal (SIGINT, SIG_IGN);
1609    ptflag = 0;
1610    if (strcmp (cmd, "RETR") && !proxy)
1611	pswitch (1);
1612    else if (!strcmp (cmd, "RETR") && proxy)
1613	pswitch (0);
1614    if (!cpend && !secndflag) {	/* only here if cmd = "STOR" (proxy=1) */
1615	if (command ("%s %s", cmd2, local) != PRELIM) {
1616	    pswitch (0);
1617	    if (cpend)
1618		abort_remote ((FILE *) NULL);
1619	}
1620	pswitch (1);
1621	if (ptabflg)
1622	    code = -1;
1623	if (oldintr)
1624	    signal (SIGINT, oldintr);
1625	return;
1626    }
1627    if (cpend)
1628	abort_remote ((FILE *) NULL);
1629    pswitch (!proxy);
1630    if (!cpend && !secndflag) {	/* only if cmd = "RETR" (proxy=1) */
1631	if (command ("%s %s", cmd2, local) != PRELIM) {
1632	    pswitch (0);
1633	    if (cpend)
1634		abort_remote ((FILE *) NULL);
1635	    pswitch (1);
1636	    if (ptabflg)
1637		code = -1;
1638	    signal (SIGINT, oldintr);
1639	    return;
1640	}
1641    }
1642    if (cpend)
1643	abort_remote ((FILE *) NULL);
1644    pswitch (!proxy);
1645    if (cpend) {
1646	FD_ZERO (&mask);
1647	if (fileno(cin) >= FD_SETSIZE)
1648	    errx (1, "fd too large");
1649	FD_SET (fileno (cin), &mask);
1650	if ((nfnd = empty (&mask, 10)) <= 0) {
1651	    if (nfnd < 0) {
1652		warn ("abort");
1653	    }
1654	    if (ptabflg)
1655		code = -1;
1656	    lostpeer (0);
1657	}
1658	getreply (0);
1659	getreply (0);
1660    }
1661    if (proxy)
1662	pswitch (0);
1663    pswitch (1);
1664    if (ptabflg)
1665	code = -1;
1666    signal (SIGINT, oldintr);
1667}
1668
1669void
1670reset (int argc, char **argv)
1671{
1672    fd_set mask;
1673    int nfnd = 1;
1674
1675    FD_ZERO (&mask);
1676    while (nfnd > 0) {
1677	if (fileno (cin) >= FD_SETSIZE)
1678	    errx (1, "fd too large");
1679	FD_SET (fileno (cin), &mask);
1680	if ((nfnd = empty (&mask, 0)) < 0) {
1681	    warn ("reset");
1682	    code = -1;
1683	    lostpeer(0);
1684	} else if (nfnd) {
1685	    getreply(0);
1686	}
1687    }
1688}
1689
1690char *
1691gunique (char *local)
1692{
1693    static char new[MaxPathLen];
1694    char *cp = strrchr (local, '/');
1695    int d, count = 0;
1696    char ext = '1';
1697
1698    if (cp)
1699	*cp = '\0';
1700    d = access (cp ? local : ".", 2);
1701    if (cp)
1702	*cp = '/';
1703    if (d < 0) {
1704	warn ("local: %s", local);
1705	return NULL;
1706    }
1707    strlcpy (new, local, sizeof(new));
1708    cp = new + strlen(new);
1709    *cp++ = '.';
1710    while (!d) {
1711	if (++count == 100) {
1712	    printf ("runique: can't find unique file name.\n");
1713	    return NULL;
1714	}
1715	*cp++ = ext;
1716	*cp = '\0';
1717	if (ext == '9')
1718	    ext = '0';
1719	else
1720	    ext++;
1721	if ((d = access (new, 0)) < 0)
1722	    break;
1723	if (ext != '0')
1724	    cp--;
1725	else if (*(cp - 2) == '.')
1726	    *(cp - 1) = '1';
1727	else {
1728	    *(cp - 2) = *(cp - 2) + 1;
1729	    cp--;
1730	}
1731    }
1732    return (new);
1733}
1734
1735void
1736abort_remote (FILE * din)
1737{
1738    char buf[BUFSIZ];
1739    int nfnd;
1740    fd_set mask;
1741
1742    /*
1743     * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1744     * after urgent byte rather than before as is protocol now
1745     */
1746    snprintf (buf, sizeof (buf), "%c%c%c", IAC, IP, IAC);
1747    if (send (fileno (cout), buf, 3, MSG_OOB) != 3)
1748	warn ("abort");
1749    fprintf (cout, "%c", DM);
1750    sec_fprintf(cout, "ABOR");
1751    sec_fflush (cout);
1752    fprintf (cout, "\r\n");
1753    fflush(cout);
1754    FD_ZERO (&mask);
1755    if (fileno (cin) >= FD_SETSIZE)
1756	errx (1, "fd too large");
1757    FD_SET (fileno (cin), &mask);
1758    if (din) {
1759	if (fileno (din) >= FD_SETSIZE)
1760	    errx (1, "fd too large");
1761	FD_SET (fileno (din), &mask);
1762    }
1763    if ((nfnd = empty (&mask, 10)) <= 0) {
1764	if (nfnd < 0) {
1765	    warn ("abort");
1766	}
1767	if (ptabflg)
1768	    code = -1;
1769	lostpeer (0);
1770    }
1771    if (din && FD_ISSET (fileno (din), &mask)) {
1772	while (read (fileno (din), buf, BUFSIZ) > 0)
1773	     /* LOOP */ ;
1774    }
1775    if (getreply (0) == ERROR && code == 552) {
1776	/* 552 needed for nic style abort */
1777	getreply (0);
1778    }
1779    getreply (0);
1780}
1781