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