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