]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/ftp/ftp.c
Fix typo(s) I overlooked in my last commit.
[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 /* wrapper for KAME-special getnameinfo() */
75 #ifndef NI_WITHSCOPEID
76 #define NI_WITHSCOPEID  0
77 #endif
78
79 extern int h_errno;
80
81 int     data = -1;
82 int     abrtflag = 0;
83 jmp_buf ptabort;
84 int     ptabflg;
85 int     ptflag = 0;
86
87 FILE    *cin, *cout;
88
89 union sockunion {
90         struct sockinet {
91                 u_char si_len;
92                 u_char si_family;
93                 u_short si_port;
94         } su_si;
95         struct sockaddr_in  su_sin;
96         struct sockaddr_in6 su_sin6;
97 };
98 #define su_len          su_si.si_len
99 #define su_family       su_si.si_family
100 #define su_port         su_si.si_port
101
102 union sockunion myctladdr, hisctladdr, data_addr;
103
104 char *
105 hookup(host0, port)
106         const char *host0;
107         char *port;
108 {
109         int s, len, tos, error;
110         struct addrinfo hints, *res, *res0;
111         static char hostnamebuf[MAXHOSTNAMELEN];
112         char *host;
113
114         if (*host0 == '[' && strrchr(host0, ']') != NULL) { /*IPv6 addr in []*/
115                 strncpy(hostnamebuf, host0 + 1, strlen(host0) - 2);
116                 hostnamebuf[strlen(host0) - 2] = '\0';
117         } else {
118                 strncpy(hostnamebuf, host0, strlen(host0));
119                 hostnamebuf[strlen(host0)] = '\0';
120         }
121         host = hostnamebuf;
122         memset(&hints, 0, sizeof(hints));
123         hints.ai_flags = AI_CANONNAME;
124         hints.ai_family = family;
125         hints.ai_socktype = SOCK_STREAM;
126         hints.ai_protocol = 0;
127         error = getaddrinfo(host, port, &hints, &res0);
128         if (error) {
129                 warnx("%s: %s", host, gai_strerror(error));
130                 if (error == EAI_SYSTEM)
131                         warnx("%s: %s", host, strerror(errno));
132                 code = -1;
133                 return (0);
134         }
135
136         res = res0;
137         if (res->ai_canonname)
138                 (void) strncpy(hostnamebuf, res->ai_canonname,
139                                sizeof(hostnamebuf));
140         hostname = hostnamebuf;
141         while (1) {
142                 /*
143                  * make sure that ai_addr is NOT an IPv4 mapped address.
144                  * IPv4 mapped address complicates too many things in FTP
145                  * protocol handling, as FTP protocol is defined differently
146                  * between IPv4 and IPv6.
147                  */
148                 ai_unmapped(res);
149                 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
150                 if (s < 0) {
151                         res = res->ai_next;
152                         if (res)
153                                 continue;
154                         warn("socket");
155                         code = -1;
156                         return (0);
157                 }
158                 if (dobind) {
159                         struct addrinfo *bindres;
160                         int binderr = -1;
161
162                         for (bindres = bindres0;
163                              bindres != NULL;
164                              bindres = bindres->ai_next)
165                                 if (bindres->ai_family == res->ai_family)
166                                         break;
167                         if (bindres == NULL)
168                                 bindres = bindres0;
169                         binderr = bind(s, bindres->ai_addr,
170                                        bindres->ai_addrlen);
171                         if (binderr == -1)
172                       {
173                         res = res->ai_next;
174                         if (res) {
175                                 (void)close(s);
176                                 continue;
177                         }
178                         warn("bind");
179                         code = -1;
180                         goto bad;
181                       }
182                 }
183                 if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
184                         break;
185                 if (res->ai_next) {
186                         char hname[INET6_ADDRSTRLEN];
187                         getnameinfo(res->ai_addr, res->ai_addrlen,
188                                     hname, sizeof(hname) - 1, NULL, 0,
189                                     NI_NUMERICHOST|NI_WITHSCOPEID);
190                         warn("connect to address %s", hname);
191                         res = res->ai_next;
192                         getnameinfo(res->ai_addr, res->ai_addrlen,
193                                     hname, sizeof(hname) - 1, NULL, 0,
194                                     NI_NUMERICHOST|NI_WITHSCOPEID);
195                         printf("Trying %s...\n", hname);
196                         (void)close(s);
197                         continue;
198                 }
199                 warn("connect");
200                 code = -1;
201                 goto bad;
202         }
203         memcpy(&hisctladdr, res->ai_addr, res->ai_addrlen);
204         freeaddrinfo(res0);
205         len = sizeof(myctladdr);
206         if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
207                 warn("getsockname");
208                 code = -1;
209                 goto bad;
210         }
211 #ifdef IP_TOS
212         if (myctladdr.su_family == AF_INET)
213       {
214              tos = IPTOS_LOWDELAY;
215         if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
216                 warn("setsockopt TOS (ignored)");
217       }
218 #endif
219         cin = fdopen(s, "r");
220         cout = fdopen(s, "w");
221         if (cin == NULL || cout == NULL) {
222                 warnx("fdopen failed.");
223                 if (cin)
224                         (void)fclose(cin);
225                 if (cout)
226                         (void)fclose(cout);
227                 code = -1;
228                 goto bad;
229         }
230         if (verbose)
231                 printf("Connected to %s.\n", hostname);
232         if (getreply(0) > 2) {  /* read startup message from server */
233                 if (cin)
234                         (void)fclose(cin);
235                 if (cout)
236                         (void)fclose(cout);
237                 code = -1;
238                 goto bad;
239         }
240 #ifdef SO_OOBINLINE
241         {
242         int on = 1;
243
244         if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
245                 < 0 && debug) {
246                         warn("setsockopt");
247                 }
248         }
249 #endif /* SO_OOBINLINE */
250
251         return (hostname);
252 bad:
253         (void)close(s);
254         return ((char *)0);
255 }
256
257 void
258 cmdabort(notused)
259         int notused;
260 {
261
262         alarmtimer(0);
263         putchar('\n');
264         (void)fflush(stdout);
265         abrtflag++;
266         if (ptflag)
267                 longjmp(ptabort, 1);
268 }
269
270 /*VARARGS*/
271 int
272 #ifdef __STDC__
273 command(const char *fmt, ...)
274 #else
275 command(va_alist)
276         va_dcl
277 #endif
278 {
279         va_list ap;
280         int r;
281         sig_t oldintr;
282 #ifndef __STDC__
283         const char *fmt;
284 #endif
285
286         abrtflag = 0;
287         if (debug) {
288                 fputs("---> ", stdout);
289 #ifdef __STDC__
290                 va_start(ap, fmt);
291 #else
292                 va_start(ap);
293                 fmt = va_arg(ap, const char *);
294 #endif
295                 if (strncmp("PASS ", fmt, 5) == 0)
296                         fputs("PASS XXXX", stdout);
297                 else if (strncmp("ACCT ", fmt, 5) == 0)
298                         fputs("ACCT XXXX", stdout);
299                 else
300                         vprintf(fmt, ap);
301                 va_end(ap);
302                 putchar('\n');
303                 (void)fflush(stdout);
304         }
305         if (cout == NULL) {
306                 warnx("No control connection for command.");
307                 code = -1;
308                 return (0);
309         }
310         oldintr = signal(SIGINT, cmdabort);
311 #ifdef __STDC__
312         va_start(ap, fmt);
313 #else
314         va_start(ap);
315         fmt = va_arg(ap, char *);
316 #endif
317         vfprintf(cout, fmt, ap);
318         va_end(ap);
319         fputs("\r\n", cout);
320         (void)fflush(cout);
321         cpend = 1;
322         r = getreply(!strcmp(fmt, "QUIT"));
323         if (abrtflag && oldintr != SIG_IGN)
324                 (*oldintr)(SIGINT);
325         (void)signal(SIGINT, oldintr);
326         return (r);
327 }
328
329 char reply_string[BUFSIZ];              /* first line of previous reply */
330
331 int
332 getreply(expecteof)
333         int expecteof;
334 {
335         char current_line[BUFSIZ];      /* last line of previous reply */
336         int c, n, line;
337         int dig;
338         int originalcode = 0, continuation = 0;
339         sig_t oldintr;
340         int pflag = 0;
341         char *cp, *pt = pasv;
342
343         oldintr = signal(SIGINT, cmdabort);
344         for (line = 0 ;; line++) {
345                 dig = n = code = 0;
346                 cp = current_line;
347                 while ((c = getc(cin)) != '\n') {
348                         if (c == IAC) {     /* handle telnet commands */
349                                 switch (c = getc(cin)) {
350                                 case WILL:
351                                 case WONT:
352                                         c = getc(cin);
353                                         fprintf(cout, "%c%c%c", IAC, DONT, c);
354                                         (void)fflush(cout);
355                                         break;
356                                 case DO:
357                                 case DONT:
358                                         c = getc(cin);
359                                         fprintf(cout, "%c%c%c", IAC, WONT, c);
360                                         (void)fflush(cout);
361                                         break;
362                                 default:
363                                         break;
364                                 }
365                                 continue;
366                         }
367                         dig++;
368                         if (c == EOF) {
369                                 if (expecteof) {
370                                         (void)signal(SIGINT, oldintr);
371                                         code = 221;
372                                         return (0);
373                                 }
374                                 lostpeer();
375                                 if (verbose) {
376                                         puts(
377 "421 Service not available, remote server has closed connection.");
378                                         (void)fflush(stdout);
379                                 }
380                                 code = 421;
381                                 return (4);
382                         }
383                         if (c != '\r' && (verbose > 0 ||
384                             (verbose > -1 && n == '5' && dig > 4))) {
385                                 if (proxflag &&
386                                    (dig == 1 || (dig == 5 && verbose == 0)))
387                                         printf("%s:", hostname);
388                                 (void)putchar(c);
389                         }
390                         if (dig < 4 && isdigit((unsigned char)c))
391                                 code = code * 10 + (c - '0');
392                         switch (pflag) {
393                         case 0:
394                                 if (code == 227 || code == 228) {
395                                         /* result for PASV/LPSV */
396                                         pflag = 1;
397                                         /* fall through */
398                                 } else if (code == 229) {
399                                         /* result for EPSV */
400                                         pflag = 100;
401                                         break;
402                                 } else
403                                         break;
404                         case 1:
405                                 if (!(dig > 4 && isdigit((unsigned char)c)))
406                                         break;
407                                 pflag = 2;
408                                 /* fall through */
409                         case 2:
410                                 if (c != '\r' && c != ')' &&
411                                     pt < &pasv[sizeof(pasv)-1])
412                                         *pt++ = c;
413                                 else {
414                                         *pt = '\0';
415                                         pflag = 3;
416                                 }
417                                 break;
418                         case 100:
419                                 if (dig > 4 && c == '(')
420                                         pflag = 2;
421                                 break;
422                         }
423                         if (dig == 4 && c == '-') {
424                                 if (continuation)
425                                         code = 0;
426                                 continuation++;
427                         }
428                         if (n == 0)
429                                 n = c;
430                         if (cp < &current_line[sizeof(current_line) - 1])
431                                 *cp++ = c;
432                 }
433                 if (verbose > 0 || (verbose > -1 && n == '5')) {
434                         (void)putchar(c);
435                         (void)fflush (stdout);
436                 }
437                 if (line == 0) {
438                         size_t len = cp - current_line;
439
440                         if (len > sizeof(reply_string))
441                                 len = sizeof(reply_string);
442
443                         (void)strncpy(reply_string, current_line, len);
444                         reply_string[len] = '\0';
445                 }
446                 if (continuation && code != originalcode) {
447                         if (originalcode == 0)
448                                 originalcode = code;
449                         continue;
450                 }
451                 *cp = '\0';
452                 if (n != '1')
453                         cpend = 0;
454                 (void)signal(SIGINT, oldintr);
455                 if (code == 421 || originalcode == 421)
456                         lostpeer();
457                 if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
458                         (*oldintr)(SIGINT);
459                 return (n - '0');
460         }
461 }
462
463 int
464 empty(mask, sec)
465         fd_set *mask;
466         int sec;
467 {
468         struct timeval t;
469
470         t.tv_sec = (long) sec;
471         t.tv_usec = 0;
472         return (select(32, mask, (fd_set *) 0, (fd_set *) 0, &t));
473 }
474
475 jmp_buf sendabort;
476
477 void
478 abortsend(notused)
479         int notused;
480 {
481
482         alarmtimer(0);
483         mflag = 0;
484         abrtflag = 0;
485         puts("\nsend aborted\nwaiting for remote to finish abort.");
486         (void)fflush(stdout);
487         longjmp(sendabort, 1);
488 }
489
490 void
491 sendrequest(cmd, local, remote, printnames)
492         const char *cmd, *local, *remote;
493         int printnames;
494 {
495         struct stat st;
496         int c, d;
497         FILE *fin, *dout;
498         int (*closefunc) __P((FILE *));
499         sig_t oldinti, oldintr, oldintp;
500         volatile off_t hashbytes;
501         char *lmode, buf[BUFSIZ], *bufp;
502         int oprogress;
503
504 #ifdef __GNUC__                 /* XXX: to shut up gcc warnings */
505         (void)&fin;
506         (void)&dout;
507         (void)&closefunc;
508         (void)&oldinti;
509         (void)&oldintr;
510         (void)&oldintp;
511         (void)&lmode;
512 #endif
513
514         hashbytes = mark;
515         direction = "sent";
516         dout = NULL;
517         bytes = 0;
518         filesize = -1;
519         oprogress = progress;
520         if (verbose && printnames) {
521                 if (local && *local != '-')
522                         printf("local: %s ", local);
523                 if (remote)
524                         printf("remote: %s\n", remote);
525         }
526         if (proxy) {
527                 proxtrans(cmd, local, remote);
528                 return;
529         }
530         if (curtype != type)
531                 changetype(type, 0);
532         closefunc = NULL;
533         oldintr = NULL;
534         oldintp = NULL;
535         oldinti = NULL;
536         lmode = "w";
537         if (setjmp(sendabort)) {
538                 while (cpend) {
539                         (void)getreply(0);
540                 }
541                 if (data >= 0) {
542                         (void)close(data);
543                         data = -1;
544                 }
545                 if (oldintr)
546                         (void)signal(SIGINT, oldintr);
547                 if (oldintp)
548                         (void)signal(SIGPIPE, oldintp);
549                 if (oldinti)
550                         (void)signal(SIGINFO, oldinti);
551                 code = -1;
552                 goto cleanupsend;
553         }
554         oldintr = signal(SIGINT, abortsend);
555         oldinti = signal(SIGINFO, psummary);
556         if (strcmp(local, "-") == 0) {
557                 fin = stdin;
558                 progress = 0;
559         } else if (*local == '|') {
560                 oldintp = signal(SIGPIPE, SIG_IGN);
561                 fin = popen(local + 1, "r");
562                 if (fin == NULL) {
563                         warn("%s", local + 1);
564                         (void)signal(SIGINT, oldintr);
565                         (void)signal(SIGPIPE, oldintp);
566                         (void)signal(SIGINFO, oldinti);
567                         code = -1;
568                         goto cleanupsend;
569                 }
570                 progress = 0;
571                 closefunc = pclose;
572         } else {
573                 fin = fopen(local, "r");
574                 if (fin == NULL) {
575                         warn("local: %s", local);
576                         (void)signal(SIGINT, oldintr);
577                         (void)signal(SIGINFO, oldinti);
578                         code = -1;
579                         goto cleanupsend;
580                 }
581                 closefunc = fclose;
582                 if (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
583                         printf("%s: not a plain file.\n", local);
584                         (void)signal(SIGINT, oldintr);
585                         (void)signal(SIGINFO, oldinti);
586                         fclose(fin);
587                         code = -1;
588                         goto cleanupsend;
589                 }
590                 filesize = st.st_size;
591         }
592         if (initconn()) {
593                 (void)signal(SIGINT, oldintr);
594                 (void)signal(SIGINFO, oldinti);
595                 if (oldintp)
596                         (void)signal(SIGPIPE, oldintp);
597                 code = -1;
598                 if (closefunc != NULL)
599                         (*closefunc)(fin);
600                 goto cleanupsend;
601         }
602         if (setjmp(sendabort))
603                 goto abort;
604
605         if (restart_point &&
606             (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
607                 int rc;
608
609                 rc = -1;
610                 switch (curtype) {
611                 case TYPE_A:
612                         rc = fseek(fin, (long) restart_point, SEEK_SET);
613                         break;
614                 case TYPE_I:
615                 case TYPE_L:
616                         rc = lseek(fileno(fin), restart_point, SEEK_SET);
617                         break;
618                 }
619                 if (rc < 0) {
620                         warn("local: %s", local);
621                         if (closefunc != NULL)
622                                 (*closefunc)(fin);
623                         goto cleanupsend;
624                 }
625                 if (command("REST %qd", (long long) restart_point) !=
626                     CONTINUE) {
627                         if (closefunc != NULL)
628                                 (*closefunc)(fin);
629                         goto cleanupsend;
630                 }
631                 lmode = "r+w";
632         }
633         if (remote) {
634                 if (command("%s %s", cmd, remote) != PRELIM) {
635                         (void)signal(SIGINT, oldintr);
636                         (void)signal(SIGINFO, oldinti);
637                         if (oldintp)
638                                 (void)signal(SIGPIPE, oldintp);
639                         if (closefunc != NULL)
640                                 (*closefunc)(fin);
641                         goto cleanupsend;
642                 }
643         } else
644                 if (command("%s", cmd) != PRELIM) {
645                         (void)signal(SIGINT, oldintr);
646                         (void)signal(SIGINFO, oldinti);
647                         if (oldintp)
648                                 (void)signal(SIGPIPE, oldintp);
649                         if (closefunc != NULL)
650                                 (*closefunc)(fin);
651                         goto cleanupsend;
652                 }
653         dout = dataconn(lmode);
654         if (dout == NULL)
655                 goto abort;
656         progressmeter(-1);
657         oldintp = signal(SIGPIPE, SIG_IGN);
658         switch (curtype) {
659
660         case TYPE_I:
661         case TYPE_L:
662                 errno = d = 0;
663                 while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) {
664                         bytes += c;
665                         for (bufp = buf; c > 0; c -= d, bufp += d)
666                                 if ((d = write(fileno(dout), bufp, c)) <= 0)
667                                         break;
668                         if (hash && (!progress || filesize < 0) ) {
669                                 while (bytes >= hashbytes) {
670                                         (void)putchar('#');
671                                         hashbytes += mark;
672                                 }
673                                 (void)fflush(stdout);
674                         }
675                 }
676                 if (hash && (!progress || filesize < 0) && bytes > 0) {
677                         if (bytes < mark)
678                                 (void)putchar('#');
679                         (void)putchar('\n');
680                         (void)fflush(stdout);
681                 }
682                 if (c < 0)
683                         warn("local: %s", local);
684                 if (d < 0) {
685                         if (errno != EPIPE)
686                                 warn("netout");
687                         bytes = -1;
688                 }
689                 break;
690
691         case TYPE_A:
692                 while ((c = getc(fin)) != EOF) {
693                         if (c == '\n') {
694                                 while (hash && (!progress || filesize < 0) &&
695                                     (bytes >= hashbytes)) {
696                                         (void)putchar('#');
697                                         (void)fflush(stdout);
698                                         hashbytes += mark;
699                                 }
700                                 if (ferror(dout))
701                                         break;
702                                 (void)putc('\r', dout);
703                                 bytes++;
704                         }
705                         (void)putc(c, dout);
706                         bytes++;
707 #if 0   /* this violates RFC */
708                         if (c == '\r') {
709                                 (void)putc('\0', dout);
710                                 bytes++;
711                         }
712 #endif
713                 }
714                 if (hash && (!progress || filesize < 0)) {
715                         if (bytes < hashbytes)
716                                 (void)putchar('#');
717                         (void)putchar('\n');
718                         (void)fflush(stdout);
719                 }
720                 if (ferror(fin))
721                         warn("local: %s", local);
722                 if (ferror(dout)) {
723                         if (errno != EPIPE)
724                                 warn("netout");
725                         bytes = -1;
726                 }
727                 break;
728         }
729         progressmeter(1);
730         if (closefunc != NULL)
731                 (*closefunc)(fin);
732         (void)fclose(dout);
733         (void)getreply(0);
734         (void)signal(SIGINT, oldintr);
735         (void)signal(SIGINFO, oldinti);
736         if (oldintp)
737                 (void)signal(SIGPIPE, oldintp);
738         if (bytes > 0)
739                 ptransfer(0);
740         goto cleanupsend;
741 abort:
742         (void)signal(SIGINT, oldintr);
743         (void)signal(SIGINFO, oldinti);
744         if (oldintp)
745                 (void)signal(SIGPIPE, oldintp);
746         if (!cpend) {
747                 code = -1;
748                 return;
749         }
750         if (data >= 0) {
751                 (void)close(data);
752                 data = -1;
753         }
754         if (dout)
755                 (void)fclose(dout);
756         (void)getreply(0);
757         code = -1;
758         if (closefunc != NULL && fin != NULL)
759                 (*closefunc)(fin);
760         if (bytes > 0)
761                 ptransfer(0);
762 cleanupsend:
763         progress = oprogress;
764         restart_point = 0;
765 }
766
767 jmp_buf recvabort;
768
769 void
770 abortrecv(notused)
771         int notused;
772 {
773
774         alarmtimer(0);
775         mflag = 0;
776         abrtflag = 0;
777         puts("\nreceive aborted\nwaiting for remote to finish abort.");
778         (void)fflush(stdout);
779         longjmp(recvabort, 1);
780 }
781
782 void
783 recvrequest(cmd, local, remote, lmode, printnames, ignorespecial)
784         const char *cmd, *local, *remote, *lmode;
785         int printnames, ignorespecial;
786 {
787         FILE *fout, *din;
788         int (*closefunc) __P((FILE *));
789         sig_t oldinti, oldintr, oldintp;
790         int c, d;
791         volatile int is_retr, tcrflag, bare_lfs;
792         static size_t bufsize;
793         static char *buf;
794         volatile off_t hashbytes;
795         struct stat st;
796         time_t mtime;
797         struct timeval tval[2];
798         int oprogress;
799         int opreserve;
800
801 #ifdef __GNUC__                 /* XXX: to shut up gcc warnings */
802         (void)&local;
803         (void)&fout;
804         (void)&din;
805         (void)&closefunc;
806         (void)&oldinti;
807         (void)&oldintr;
808         (void)&oldintp;
809 #endif
810
811         fout = NULL;
812         din = NULL;
813         oldinti = NULL;
814         hashbytes = mark;
815         direction = "received";
816         bytes = 0;
817         bare_lfs = 0;
818         filesize = -1;
819         oprogress = progress;
820         opreserve = preserve;
821         is_retr = (strcmp(cmd, "RETR") == 0);
822         if (is_retr && verbose && printnames) {
823                 if (local && (ignorespecial || *local != '-'))
824                         printf("local: %s ", local);
825                 if (remote)
826                         printf("remote: %s\n", remote);
827         }
828         if (proxy && is_retr) {
829                 proxtrans(cmd, local, remote);
830                 return;
831         }
832         closefunc = NULL;
833         oldintr = NULL;
834         oldintp = NULL;
835         tcrflag = !crflag && is_retr;
836         if (setjmp(recvabort)) {
837                 while (cpend) {
838                         (void)getreply(0);
839                 }
840                 if (data >= 0) {
841                         (void)close(data);
842                         data = -1;
843                 }
844                 if (oldintr)
845                         (void)signal(SIGINT, oldintr);
846                 if (oldinti)
847                         (void)signal(SIGINFO, oldinti);
848                 progress = oprogress;
849                 preserve = opreserve;
850                 code = -1;
851                 return;
852         }
853         oldintr = signal(SIGINT, abortrecv);
854         oldinti = signal(SIGINFO, psummary);
855         if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
856                 if (access(local, W_OK) < 0) {
857                         char *dir = strrchr(local, '/');
858
859                         if (errno != ENOENT && errno != EACCES) {
860                                 warn("local: %s", local);
861                                 (void)signal(SIGINT, oldintr);
862                                 (void)signal(SIGINFO, oldinti);
863                                 code = -1;
864                                 return;
865                         }
866                         if (dir != NULL)
867                                 *dir = 0;
868                         d = access(dir == local ? "/" : dir ? local : ".", W_OK);
869                         if (dir != NULL)
870                                 *dir = '/';
871                         if (d < 0) {
872                                 warn("local: %s", local);
873                                 (void)signal(SIGINT, oldintr);
874                                 (void)signal(SIGINFO, oldinti);
875                                 code = -1;
876                                 return;
877                         }
878                         if (!runique && errno == EACCES &&
879                             chmod(local, 0600) < 0) {
880                                 warn("local: %s", local);
881                                 (void)signal(SIGINT, oldintr);
882                                 (void)signal(SIGINFO, oldinti);
883                                 code = -1;
884                                 return;
885                         }
886                         if (runique && errno == EACCES &&
887                            (local = gunique(local)) == NULL) {
888                                 (void)signal(SIGINT, oldintr);
889                                 (void)signal(SIGINFO, oldinti);
890                                 code = -1;
891                                 return;
892                         }
893                 }
894                 else if (runique && (local = gunique(local)) == NULL) {
895                         (void)signal(SIGINT, oldintr);
896                         (void)signal(SIGINFO, oldinti);
897                         code = -1;
898                         return;
899                 }
900         }
901         if (!is_retr) {
902                 if (curtype != TYPE_A)
903                         changetype(TYPE_A, 0);
904         } else {
905                 if (curtype != type)
906                         changetype(type, 0);
907                 filesize = remotesize(remote, 0);
908         }
909         if (initconn()) {
910                 (void)signal(SIGINT, oldintr);
911                 (void)signal(SIGINFO, oldinti);
912                 code = -1;
913                 return;
914         }
915         if (setjmp(recvabort))
916                 goto abort;
917         if (is_retr && restart_point &&
918             command("REST %qd", (long long) restart_point) != CONTINUE)
919                 return;
920         if (remote) {
921                 if (command("%s %s", cmd, remote) != PRELIM) {
922                         (void)signal(SIGINT, oldintr);
923                         (void)signal(SIGINFO, oldinti);
924                         return;
925                 }
926         } else {
927                 if (command("%s", cmd) != PRELIM) {
928                         (void)signal(SIGINT, oldintr);
929                         (void)signal(SIGINFO, oldinti);
930                         return;
931                 }
932         }
933         din = dataconn("r");
934         if (din == NULL)
935                 goto abort;
936         if (!ignorespecial && strcmp(local, "-") == 0) {
937                 fout = stdout;
938                 progress = 0;
939                 preserve = 0;
940         } else if (!ignorespecial && *local == '|') {
941                 oldintp = signal(SIGPIPE, SIG_IGN);
942                 fout = popen(local + 1, "w");
943                 if (fout == NULL) {
944                         warn("%s", local+1);
945                         goto abort;
946                 }
947                 progress = 0;
948                 preserve = 0;
949                 closefunc = pclose;
950         } else {
951                 fout = fopen(local, lmode);
952                 if (fout == NULL) {
953                         warn("local: %s", local);
954                         goto abort;
955                 }
956                 closefunc = fclose;
957         }
958         if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
959                 st.st_blksize = BUFSIZ;
960         if (st.st_blksize > bufsize) {
961                 if (buf)
962                         (void)free(buf);
963                 buf = malloc((unsigned)st.st_blksize);
964                 if (buf == NULL) {
965                         warn("malloc");
966                         bufsize = 0;
967                         goto abort;
968                 }
969                 bufsize = st.st_blksize;
970         }
971         if (!S_ISREG(st.st_mode)) {
972                 progress = 0;
973                 preserve = 0;
974         }
975         progressmeter(-1);
976         switch (curtype) {
977
978         case TYPE_I:
979         case TYPE_L:
980                 if (is_retr && restart_point &&
981                     lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
982                         warn("local: %s", local);
983                         progress = oprogress;
984                         preserve = opreserve;
985                         if (closefunc != NULL)
986                                 (*closefunc)(fout);
987                         return;
988                 }
989                 errno = d = 0;
990                 while ((c = read(fileno(din), buf, bufsize)) > 0) {
991                         if ((d = write(fileno(fout), buf, c)) != c)
992                                 break;
993                         bytes += c;
994                         if (hash && (!progress || filesize < 0)) {
995                                 while (bytes >= hashbytes) {
996                                         (void)putchar('#');
997                                         hashbytes += mark;
998                                 }
999                                 (void)fflush(stdout);
1000                         }
1001                 }
1002                 if (hash && (!progress || filesize < 0) && bytes > 0) {
1003                         if (bytes < mark)
1004                                 (void)putchar('#');
1005                         (void)putchar('\n');
1006                         (void)fflush(stdout);
1007                 }
1008                 if (c < 0) {
1009                         if (errno != EPIPE)
1010                                 warn("netin");
1011                         bytes = -1;
1012                 }
1013                 if (d < c) {
1014                         if (d < 0)
1015                                 warn("local: %s", local);
1016                         else
1017                                 warnx("%s: short write", local);
1018                 }
1019                 break;
1020
1021         case TYPE_A:
1022                 if (is_retr && restart_point) {
1023                         int ch;
1024                         long i, n;
1025
1026                         if (fseek(fout, 0L, SEEK_SET) < 0)
1027                                 goto done;
1028                         n = (long)restart_point;
1029                         for (i = 0; i++ < n;) {
1030                                 if ((ch = getc(fout)) == EOF)
1031                                         goto done;
1032                                 if (ch == '\n')
1033                                         i++;
1034                         }
1035                         if (fseek(fout, 0L, SEEK_CUR) < 0) {
1036 done:
1037                                 warn("local: %s", local);
1038                                 progress = oprogress;
1039                                 preserve = opreserve;
1040                                 if (closefunc != NULL)
1041                                         (*closefunc)(fout);
1042                                 return;
1043                         }
1044                 }
1045                 while ((c = getc(din)) != EOF) {
1046                         if (c == '\n')
1047                                 bare_lfs++;
1048                         while (c == '\r') {
1049                                 while (hash && (!progress || filesize < 0) &&
1050                                     (bytes >= hashbytes)) {
1051                                         (void)putchar('#');
1052                                         (void)fflush(stdout);
1053                                         hashbytes += mark;
1054                                 }
1055                                 bytes++;
1056                                 if ((c = getc(din)) != '\n' || tcrflag) {
1057                                         if (ferror(fout))
1058                                                 goto break2;
1059                                         (void)putc('\r', fout);
1060                                         if (c == '\0') {
1061                                                 bytes++;
1062                                                 goto contin2;
1063                                         }
1064                                         if (c == EOF)
1065                                                 goto contin2;
1066                                 }
1067                         }
1068                         (void)putc(c, fout);
1069                         bytes++;
1070         contin2:        ;
1071                 }
1072 break2:
1073                 if (bare_lfs) {
1074                         printf(
1075 "WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
1076                         puts("File may not have transferred correctly.");
1077                 }
1078                 if (hash && (!progress || filesize < 0)) {
1079                         if (bytes < hashbytes)
1080                                 (void)putchar('#');
1081                         (void)putchar('\n');
1082                         (void)fflush(stdout);
1083                 }
1084                 if (ferror(din)) {
1085                         if (errno != EPIPE)
1086                                 warn("netin");
1087                         bytes = -1;
1088                 }
1089                 if (ferror(fout))
1090                         warn("local: %s", local);
1091                 break;
1092         }
1093         progressmeter(1);
1094         progress = oprogress;
1095         preserve = opreserve;
1096         if (closefunc != NULL)
1097                 (*closefunc)(fout);
1098         (void)signal(SIGINT, oldintr);
1099         (void)signal(SIGINFO, oldinti);
1100         if (oldintp)
1101                 (void)signal(SIGPIPE, oldintp);
1102         (void)fclose(din);
1103         (void)getreply(0);
1104         if (bytes >= 0 && is_retr) {
1105                 if (bytes > 0)
1106                         ptransfer(0);
1107                 if (preserve && (closefunc == fclose)) {
1108                         mtime = remotemodtime(remote, 0);
1109                         if (mtime != -1) {
1110                                 (void)gettimeofday(&tval[0],
1111                                     (struct timezone *)0);
1112                                 tval[1].tv_sec = mtime;
1113                                 tval[1].tv_usec = 0;
1114                                 if (utimes(local, tval) == -1) {
1115                                         printf(
1116                                 "Can't change modification time on %s to %s",
1117                                             local, asctime(localtime(&mtime)));
1118                                 }
1119                         }
1120                 }
1121         }
1122         return;
1123
1124 abort:
1125
1126 /* abort using RFC959 recommended IP,SYNC sequence */
1127
1128         progress = oprogress;
1129         preserve = opreserve;
1130         if (oldintp)
1131                 (void)signal(SIGPIPE, oldintp);
1132         (void)signal(SIGINT, SIG_IGN);
1133         if (!cpend) {
1134                 code = -1;
1135                 (void)signal(SIGINT, oldintr);
1136                 (void)signal(SIGINFO, oldinti);
1137                 return;
1138         }
1139
1140         abort_remote(din);
1141         code = -1;
1142         if (data >= 0) {
1143                 (void)close(data);
1144                 data = -1;
1145         }
1146         if (closefunc != NULL && fout != NULL)
1147                 (*closefunc)(fout);
1148         if (din)
1149                 (void)fclose(din);
1150         if (bytes > 0)
1151                 ptransfer(0);
1152         (void)signal(SIGINT, oldintr);
1153         (void)signal(SIGINFO, oldinti);
1154 }
1155
1156 /*
1157  * Need to start a listen on the data channel before we send the command,
1158  * otherwise the server's connect may fail.
1159  */
1160 int
1161 initconn()
1162 {
1163         char *p, *a;
1164         int result, len, tmpno = 0;
1165         int on = 1;
1166         int error, ports;
1167         u_int af;
1168         u_int hal, h[16];
1169         u_int pal, prt[2];
1170         char *pasvcmd;
1171
1172 #ifdef INET6
1173         if (myctladdr.su_family == AF_INET6
1174          && (IN6_IS_ADDR_LINKLOCAL(&myctladdr.su_sin6.sin6_addr)
1175           || IN6_IS_ADDR_SITELOCAL(&myctladdr.su_sin6.sin6_addr))) {
1176                 warnx("use of scoped address can be troublesome");
1177         }
1178 #endif
1179
1180         if (passivemode) {
1181                 data_addr = myctladdr;
1182                 data = socket(data_addr.su_family, SOCK_STREAM, 0);
1183                 if (data < 0) {
1184                         warn("socket");
1185                         return (1);
1186                 }
1187                 if (dobind) {
1188                         struct addrinfo *bindres;
1189                         int binderr = -1;
1190
1191                         for (bindres = bindres0;
1192                              bindres != NULL;
1193                              bindres = bindres->ai_next)
1194                                 if (bindres->ai_family == data_addr.su_family)
1195                                         break;
1196                         if (bindres == NULL)
1197                                 bindres = bindres0;
1198                         binderr = bind(data, bindres->ai_addr,
1199                                        bindres->ai_addrlen);
1200                         if (binderr == -1)
1201                      {
1202                         warn("bind");
1203                         goto bad;
1204                      }
1205                 }
1206                 if ((options & SO_DEBUG) &&
1207                     setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1208                                sizeof(on)) < 0)
1209                         warn("setsockopt (ignored)");
1210                 switch (data_addr.su_family) {
1211                 case AF_INET:
1212                         if (try_epsv) {
1213                                 int overbose;
1214
1215                                 overbose = verbose;
1216                                 if (debug == 0)
1217                                         verbose = -1;
1218                                 result = command(pasvcmd = "EPSV");
1219                                 verbose = overbose;
1220                                 if (code / 10 == 22 && code != 229) {
1221                                         puts("wrong server: EPSV return code must be 229");
1222                                         result = COMPLETE + 1;
1223                                 }
1224                         } else
1225                                 result = COMPLETE + 1;
1226                         if (result != COMPLETE) {
1227                                 try_epsv = 0;
1228                                 result = command(pasvcmd = "PASV");
1229                         }
1230                         break;
1231 #ifdef INET6
1232                 case AF_INET6:
1233                         result = command(pasvcmd = "EPSV");
1234                         if (code / 10 == 22 && code != 229) {
1235                                 puts("wrong server: EPSV return code must be 229");
1236                                 result = COMPLETE + 1;
1237                         }
1238                         if (result != COMPLETE)
1239                                 result = command(pasvcmd = "LPSV");
1240                         break;
1241 #endif
1242                 default:
1243                         result = COMPLETE + 1;
1244                 }
1245                 if (result != COMPLETE) {
1246                         puts("Passive mode refused.");
1247                         goto bad;
1248                 }
1249
1250 #define pack2(var, offset) \
1251         (((var[(offset) + 0] & 0xff) << 8) | ((var[(offset) + 1] & 0xff) << 0))
1252 #define pack4(var, offset) \
1253     (((var[(offset) + 0] & 0xff) << 24) | ((var[(offset) + 1] & 0xff) << 16) \
1254      | ((var[(offset) + 2] & 0xff) << 8) | ((var[(offset) + 3] & 0xff) << 0))
1255                 /*
1256                  * What we've got at this point is a string of comma
1257                  * separated one-byte unsigned integer values.
1258                  * In PASV case,
1259                  * The first four are the an IP address. The fifth is
1260                  * the MSB of the port number, the sixth is the LSB.
1261                  * From that we'll prepare a sockaddr_in.
1262                  * In other case, the format is more complicated.
1263                  */
1264                 if (strcmp(pasvcmd, "PASV") == 0) {
1265                         if (code / 10 == 22 && code != 227) {
1266                                 puts("wrong server: return code must be 227");
1267                                 error = 1;
1268                                 goto bad;
1269                         }
1270                         error = sscanf(pasv, "%d,%d,%d,%d,%d,%d",
1271                                &h[0], &h[1], &h[2], &h[3],
1272                                &prt[0], &prt[1]);
1273                         if (error == 6) {
1274                                 error = 0;
1275                                 data_addr.su_sin.sin_addr.s_addr =
1276                                         htonl(pack4(h, 0));
1277                         } else
1278                                 error = 1;
1279                 } else if (strcmp(pasvcmd, "LPSV") == 0) {
1280                         if (code / 10 == 22 && code != 228) {
1281                                 puts("wrong server: return code must be 228");
1282                                 error = 1;
1283                                 goto bad;
1284                         }
1285                         switch (data_addr.su_family) {
1286                         case AF_INET:
1287                                 error = sscanf(pasv,
1288 "%d,%d,%d,%d,%d,%d,%d,%d,%d",
1289                                        &af, &hal,
1290                                        &h[0], &h[1], &h[2], &h[3],
1291                                        &pal, &prt[0], &prt[1]);
1292                                 if (error == 9 && af == 4 && hal == 4 && pal == 2) {
1293                                         error = 0;
1294                                         data_addr.su_sin.sin_addr.s_addr =
1295                                                 htonl(pack4(h, 0));
1296                                 } else
1297                                         error = 1;
1298                                 break;
1299 #ifdef INET6
1300                         case AF_INET6:
1301                                 error = sscanf(pasv,
1302 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1303                                                &af, &hal,
1304                                                &h[0], &h[1], &h[2], &h[3],
1305                                                &h[4], &h[5], &h[6], &h[7],
1306                                                &h[8], &h[9], &h[10], &h[11],
1307                                                &h[12], &h[13], &h[14], &h[15],
1308                                                &pal, &prt[0], &prt[1]);
1309                                 if (error != 21 || af != 6 || hal != 16 || pal != 2) {
1310                                         error = 1;
1311                                         break;
1312                                 }
1313
1314                                 error = 0;
1315                             {
1316                                 u_int32_t *p32;
1317                                 p32 = (u_int32_t *)&data_addr.su_sin6.sin6_addr;
1318                                 p32[0] = htonl(pack4(h, 0));
1319                                 p32[1] = htonl(pack4(h, 4));
1320                                 p32[2] = htonl(pack4(h, 8));
1321                                 p32[3] = htonl(pack4(h, 12));
1322                             }
1323                                 break;
1324 #endif
1325                         default:
1326                                 error = 1;
1327                         }
1328                 } else if (strcmp(pasvcmd, "EPSV") == 0) {
1329                         char delim[4];
1330                         char *tcpport;
1331
1332                         prt[0] = 0;
1333                         if (code / 10 == 22 && code != 229) {
1334                                 puts("wrong server: return code must be 229");
1335                                 error = 1;
1336                                 goto bad;
1337                         }
1338                         error = sscanf(pasv, "%c%c%c%d%c",
1339                                 &delim[0], &delim[1], &delim[2],
1340                                 &prt[1], &delim[3]);
1341                         if (error != 5) {
1342                                 error = 1;
1343                                 goto epsv_done;
1344                         }
1345                         if (delim[0] != delim[1] || delim[0] != delim[2]
1346                          || delim[0] != delim[3]) {
1347                                 error = 1;
1348                                 goto epsv_done;
1349                         }
1350
1351                         data_addr = hisctladdr;
1352                         /* quickhack */
1353                         prt[0] = (prt[1] & 0xff00) >> 8;
1354                         prt[1] &= 0xff;
1355                         error = 0;
1356 epsv_done:
1357                 } else
1358                         error = 1;
1359
1360                 if (error) {
1361                         puts(
1362 "Passive mode address scan failure. Shouldn't happen!");
1363                         goto bad;
1364                 };
1365
1366                 data_addr.su_port = htons(pack2(prt, 0));
1367
1368                 if (connect(data, (struct sockaddr *)&data_addr,
1369                             data_addr.su_len) < 0) {
1370                         warn("connect");
1371                         goto bad;
1372                 }
1373 #ifdef IP_TOS
1374                 if (data_addr.su_family == AF_INET)
1375               {
1376                 on = IPTOS_THROUGHPUT;
1377                 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1378                                sizeof(int)) < 0)
1379                         warn("setsockopt TOS (ignored)");
1380               }
1381 #endif
1382                 return (0);
1383         }
1384
1385 noport:
1386         data_addr = myctladdr;
1387         if (sendport)
1388                 data_addr.su_port = 0;  /* let system pick one */
1389         if (data != -1)
1390                 (void)close(data);
1391         data = socket(data_addr.su_family, SOCK_STREAM, 0);
1392         if (data < 0) {
1393                 warn("socket");
1394                 if (tmpno)
1395                         sendport = 1;
1396                 return (1);
1397         }
1398         if (!sendport)
1399                 if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1400                                 sizeof(on)) < 0) {
1401                         warn("setsockopt (reuse address)");
1402                         goto bad;
1403                 }
1404 #ifdef IP_PORTRANGE
1405         if (data_addr.su_family == AF_INET)
1406       {
1407         
1408         ports = restricted_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
1409         if (setsockopt(data, IPPROTO_IP, IP_PORTRANGE, (char *)&ports,
1410                        sizeof(ports)) < 0)
1411             warn("setsockopt PORTRANGE (ignored)");
1412       }
1413 #endif
1414 #ifdef INET6
1415 #ifdef IPV6_PORTRANGE
1416         if (data_addr.su_family == AF_INET6) {
1417                 ports = restricted_data_ports ? IPV6_PORTRANGE_HIGH
1418                         : IPV6_PORTRANGE_DEFAULT;
1419                 if (setsockopt(data, IPPROTO_IPV6, IPV6_PORTRANGE,
1420                                (char *)&ports, sizeof(ports)) < 0)
1421                   warn("setsockopt PORTRANGE (ignored)");
1422         }
1423 #endif
1424 #endif
1425         if (bind(data, (struct sockaddr *)&data_addr, data_addr.su_len) < 0) {
1426                 warn("bind");
1427                 goto bad;
1428         }
1429         if (options & SO_DEBUG &&
1430             setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1431                         sizeof(on)) < 0)
1432                 warn("setsockopt (ignored)");
1433         len = sizeof(data_addr);
1434         if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1435                 warn("getsockname");
1436                 goto bad;
1437         }
1438         if (listen(data, 1) < 0)
1439                 warn("listen");
1440         if (sendport) {
1441                 char hname[INET6_ADDRSTRLEN];
1442                 int af;
1443                 struct sockaddr_in data_addr4;
1444                 union sockunion *daddr;
1445
1446 #ifdef INET6
1447                 if (data_addr.su_family == AF_INET6 &&
1448                     IN6_IS_ADDR_V4MAPPED(&data_addr.su_sin6.sin6_addr)) {
1449                         memset(&data_addr4, 0, sizeof(data_addr4));
1450                         data_addr4.sin_len = sizeof(struct sockaddr_in);
1451                         data_addr4.sin_family = AF_INET;
1452                         data_addr4.sin_port = data_addr.su_port;
1453                         memcpy((caddr_t)&data_addr4.sin_addr,
1454                                (caddr_t)&data_addr.su_sin6.sin6_addr.s6_addr[12],
1455                                sizeof(struct in_addr));
1456                         daddr = (union sockunion *)&data_addr4;
1457                 } else
1458 #endif
1459                 daddr = &data_addr;
1460
1461
1462
1463 #define UC(b)   (((int)b)&0xff)
1464
1465                 switch (daddr->su_family) {
1466 #ifdef INET6
1467                 case AF_INET6:
1468 #endif
1469                         af = (daddr->su_family == AF_INET) ? 1 : 2;
1470                         if (getnameinfo((struct sockaddr *)daddr,
1471                                         daddr->su_len, hname,
1472                                         sizeof(hname) - 1, NULL, 0,
1473                                         NI_NUMERICHOST)) {
1474                                 result = ERROR;
1475                         } else {
1476                                 result = command("EPRT |%d|%s|%d|",
1477                                         af, hname, ntohs(daddr->su_port));
1478                         }
1479                         break;
1480                 default:
1481                         result = COMPLETE + 1;
1482                         break;
1483                 }
1484                 if (result == COMPLETE)
1485                         goto skip_port;
1486
1487                 p = (char *)&daddr->su_port;
1488                 switch (daddr->su_family) {
1489                 case AF_INET:
1490                         a = (char *)&daddr->su_sin.sin_addr;
1491                         result = command("PORT %d,%d,%d,%d,%d,%d",
1492                                          UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
1493                                          UC(p[0]), UC(p[1]));
1494                         break;
1495 #ifdef INET6
1496                 case AF_INET6:
1497                         a = (char *)&daddr->su_sin6.sin6_addr;
1498                         result = command(
1499 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1500                                          6, 16,
1501                                          UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
1502                                          UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
1503                                          UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
1504                                          UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
1505                                          2, UC(p[0]), UC(p[1]));
1506                         break;
1507 #endif
1508                 default:
1509                         result = COMPLETE + 1; /* xxx */
1510                 }
1511         skip_port:
1512                 
1513                 if (result == ERROR && sendport == -1) {
1514                         sendport = 0;
1515                         tmpno = 1;
1516                         goto noport;
1517                 }
1518                 return (result != COMPLETE);
1519         }
1520         if (tmpno)
1521                 sendport = 1;
1522 #ifdef IP_TOS
1523         if (data_addr.su_family == AF_INET)
1524       {
1525         on = IPTOS_THROUGHPUT;
1526         if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1527                 warn("setsockopt TOS (ignored)");
1528       }
1529 #endif
1530         return (0);
1531 bad:
1532         (void)close(data), data = -1;
1533         if (tmpno)
1534                 sendport = 1;
1535         return (1);
1536 }
1537
1538 FILE *
1539 dataconn(lmode)
1540         const char *lmode;
1541 {
1542         union sockunion from;
1543         int s, fromlen, tos;
1544
1545         fromlen = myctladdr.su_len;
1546
1547         if (passivemode)
1548                 return (fdopen(data, lmode));
1549
1550         s = accept(data, (struct sockaddr *) &from, &fromlen);
1551         if (s < 0) {
1552                 warn("accept");
1553                 (void)close(data), data = -1;
1554                 return (NULL);
1555         }
1556         (void)close(data);
1557         data = s;
1558 #ifdef IP_TOS
1559         if (data_addr.su_family == AF_INET)
1560       {
1561         tos = IPTOS_THROUGHPUT;
1562         if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1563                 warn("setsockopt TOS (ignored)");
1564       }
1565 #endif
1566         return (fdopen(data, lmode));
1567 }
1568
1569 void
1570 psummary(notused)
1571         int notused;
1572 {
1573
1574         if (bytes > 0)
1575                 ptransfer(1);
1576 }
1577
1578 void
1579 psabort(notused)
1580         int notused;
1581 {
1582
1583         alarmtimer(0);
1584         abrtflag++;
1585 }
1586
1587 void
1588 pswitch(flag)
1589         int flag;
1590 {
1591         sig_t oldintr;
1592         static struct comvars {
1593                 int connect;
1594                 char name[MAXHOSTNAMELEN];
1595                 union sockunion mctl;
1596                 union sockunion hctl;
1597                 FILE *in;
1598                 FILE *out;
1599                 int tpe;
1600                 int curtpe;
1601                 int cpnd;
1602                 int sunqe;
1603                 int runqe;
1604                 int mcse;
1605                 int ntflg;
1606                 char nti[17];
1607                 char nto[17];
1608                 int mapflg;
1609                 char mi[MAXPATHLEN];
1610                 char mo[MAXPATHLEN];
1611         } proxstruct, tmpstruct;
1612         struct comvars *ip, *op;
1613
1614         abrtflag = 0;
1615         oldintr = signal(SIGINT, psabort);
1616         if (flag) {
1617                 if (proxy)
1618                         return;
1619                 ip = &tmpstruct;
1620                 op = &proxstruct;
1621                 proxy++;
1622         } else {
1623                 if (!proxy)
1624                         return;
1625                 ip = &proxstruct;
1626                 op = &tmpstruct;
1627                 proxy = 0;
1628         }
1629         ip->connect = connected;
1630         connected = op->connect;
1631         if (hostname) {
1632                 (void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1633                 ip->name[sizeof(ip->name) - 1] = '\0';
1634         } else
1635                 ip->name[0] = '\0';
1636         hostname = op->name;
1637         ip->hctl = hisctladdr;
1638         hisctladdr = op->hctl;
1639         ip->mctl = myctladdr;
1640         myctladdr = op->mctl;
1641         ip->in = cin;
1642         cin = op->in;
1643         ip->out = cout;
1644         cout = op->out;
1645         ip->tpe = type;
1646         type = op->tpe;
1647         ip->curtpe = curtype;
1648         curtype = op->curtpe;
1649         ip->cpnd = cpend;
1650         cpend = op->cpnd;
1651         ip->sunqe = sunique;
1652         sunique = op->sunqe;
1653         ip->runqe = runique;
1654         runique = op->runqe;
1655         ip->mcse = mcase;
1656         mcase = op->mcse;
1657         ip->ntflg = ntflag;
1658         ntflag = op->ntflg;
1659         (void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
1660         (ip->nti)[sizeof(ip->nti) - 1] = '\0';
1661         (void)strcpy(ntin, op->nti);
1662         (void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
1663         (ip->nto)[sizeof(ip->nto) - 1] = '\0';
1664         (void)strcpy(ntout, op->nto);
1665         ip->mapflg = mapflag;
1666         mapflag = op->mapflg;
1667         (void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
1668         (ip->mi)[sizeof(ip->mi) - 1] = '\0';
1669         (void)strcpy(mapin, op->mi);
1670         (void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
1671         (ip->mo)[sizeof(ip->mo) - 1] = '\0';
1672         (void)strcpy(mapout, op->mo);
1673         (void)signal(SIGINT, oldintr);
1674         if (abrtflag) {
1675                 abrtflag = 0;
1676                 (*oldintr)(SIGINT);
1677         }
1678 }
1679
1680 void
1681 abortpt(notused)
1682         int notused;
1683 {
1684
1685         alarmtimer(0);
1686         putchar('\n');
1687         (void)fflush(stdout);
1688         ptabflg++;
1689         mflag = 0;
1690         abrtflag = 0;
1691         longjmp(ptabort, 1);
1692 }
1693
1694 void
1695 proxtrans(cmd, local, remote)
1696         const char *cmd, *local, *remote;
1697 {
1698         sig_t oldintr;
1699         int prox_type, nfnd;
1700         volatile int secndflag;
1701         char *cmd2;
1702         fd_set mask;
1703
1704 #ifdef __GNUC__                 /* XXX: to shut up gcc warnings */
1705         (void)&oldintr;
1706         (void)&cmd2;
1707 #endif
1708
1709         oldintr = NULL;
1710         secndflag = 0;
1711         if (strcmp(cmd, "RETR"))
1712                 cmd2 = "RETR";
1713         else
1714                 cmd2 = runique ? "STOU" : "STOR";
1715         if ((prox_type = type) == 0) {
1716                 if (unix_server && unix_proxy)
1717                         prox_type = TYPE_I;
1718                 else
1719                         prox_type = TYPE_A;
1720         }
1721         if (curtype != prox_type)
1722                 changetype(prox_type, 1);
1723         if (try_epsv && command("EPSV") != COMPLETE)
1724                 try_epsv = 0;
1725         if (!try_epsv && command("PASV") != COMPLETE) {
1726                 puts("proxy server does not support third party transfers.");
1727                 return;
1728         }
1729         pswitch(0);
1730         if (!connected) {
1731                 puts("No primary connection.");
1732                 pswitch(1);
1733                 code = -1;
1734                 return;
1735         }
1736         if (curtype != prox_type)
1737                 changetype(prox_type, 1);
1738         if (command("PORT %s", pasv) != COMPLETE) {
1739                 pswitch(1);
1740                 return;
1741         }
1742         if (setjmp(ptabort))
1743                 goto abort;
1744         oldintr = signal(SIGINT, abortpt);
1745         if (command("%s %s", cmd, remote) != PRELIM) {
1746                 (void)signal(SIGINT, oldintr);
1747                 pswitch(1);
1748                 return;
1749         }
1750         sleep(2);
1751         pswitch(1);
1752         secndflag++;
1753         if (command("%s %s", cmd2, local) != PRELIM)
1754                 goto abort;
1755         ptflag++;
1756         (void)getreply(0);
1757         pswitch(0);
1758         (void)getreply(0);
1759         (void)signal(SIGINT, oldintr);
1760         pswitch(1);
1761         ptflag = 0;
1762         printf("local: %s remote: %s\n", local, remote);
1763         return;
1764 abort:
1765         (void)signal(SIGINT, SIG_IGN);
1766         ptflag = 0;
1767         if (strcmp(cmd, "RETR") && !proxy)
1768                 pswitch(1);
1769         else if (!strcmp(cmd, "RETR") && proxy)
1770                 pswitch(0);
1771         if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
1772                 if (command("%s %s", cmd2, local) != PRELIM) {
1773                         pswitch(0);
1774                         if (cpend)
1775                                 abort_remote((FILE *) NULL);
1776                 }
1777                 pswitch(1);
1778                 if (ptabflg)
1779                         code = -1;
1780                 (void)signal(SIGINT, oldintr);
1781                 return;
1782         }
1783         if (cpend)
1784                 abort_remote((FILE *) NULL);
1785         pswitch(!proxy);
1786         if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
1787                 if (command("%s %s", cmd2, local) != PRELIM) {
1788                         pswitch(0);
1789                         if (cpend)
1790                                 abort_remote((FILE *) NULL);
1791                         pswitch(1);
1792                         if (ptabflg)
1793                                 code = -1;
1794                         (void)signal(SIGINT, oldintr);
1795                         return;
1796                 }
1797         }
1798         if (cpend)
1799                 abort_remote((FILE *) NULL);
1800         pswitch(!proxy);
1801         if (cpend) {
1802                 FD_ZERO(&mask);
1803                 FD_SET(fileno(cin), &mask);
1804                 if ((nfnd = empty(&mask, 10)) <= 0) {
1805                         if (nfnd < 0) {
1806                                 warn("abort");
1807                         }
1808                         if (ptabflg)
1809                                 code = -1;
1810                         lostpeer();
1811                 }
1812                 (void)getreply(0);
1813                 (void)getreply(0);
1814         }
1815         if (proxy)
1816                 pswitch(0);
1817         pswitch(1);
1818         if (ptabflg)
1819                 code = -1;
1820         (void)signal(SIGINT, oldintr);
1821 }
1822
1823 void
1824 reset(argc, argv)
1825         int argc;
1826         char *argv[];
1827 {
1828         fd_set mask;
1829         int nfnd = 1;
1830
1831         FD_ZERO(&mask);
1832         while (nfnd > 0) {
1833                 FD_SET(fileno(cin), &mask);
1834                 if ((nfnd = empty(&mask, 0)) < 0) {
1835                         warn("reset");
1836                         code = -1;
1837                         lostpeer();
1838                 }
1839                 else if (nfnd) {
1840                         (void)getreply(0);
1841                 }
1842         }
1843 }
1844
1845 char *
1846 gunique(local)
1847         const char *local;
1848 {
1849         static char new[MAXPATHLEN];
1850         char *cp = strrchr(local, '/');
1851         int d, count=0;
1852         char ext = '1';
1853
1854         if (cp)
1855                 *cp = '\0';
1856         d = access(cp == local ? "/" : cp ? local : ".", W_OK);
1857         if (cp)
1858                 *cp = '/';
1859         if (d < 0) {
1860                 warn("local: %s", local);
1861                 return ((char *) 0);
1862         }
1863         (void)strcpy(new, local);
1864         cp = new + strlen(new);
1865         *cp++ = '.';
1866         while (!d) {
1867                 if (++count == 100) {
1868                         puts("runique: can't find unique file name.");
1869                         return ((char *) 0);
1870                 }
1871                 *cp++ = ext;
1872                 *cp = '\0';
1873                 if (ext == '9')
1874                         ext = '0';
1875                 else
1876                         ext++;
1877                 if ((d = access(new, F_OK)) < 0)
1878                         break;
1879                 if (ext != '0')
1880                         cp--;
1881                 else if (*(cp - 2) == '.')
1882                         *(cp - 1) = '1';
1883                 else {
1884                         *(cp - 2) = *(cp - 2) + 1;
1885                         cp--;
1886                 }
1887         }
1888         return (new);
1889 }
1890
1891 void
1892 abort_remote(din)
1893         FILE *din;
1894 {
1895         char buf[BUFSIZ];
1896         int nfnd;
1897         fd_set mask;
1898
1899         if (cout == NULL) {
1900                 warnx("Lost control connection for abort.");
1901                 if (ptabflg)
1902                         code = -1;
1903                 lostpeer();
1904                 return;
1905         }
1906         /*
1907          * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1908          * after urgent byte rather than before as is protocol now
1909          */
1910         sprintf(buf, "%c%c%c", IAC, IP, IAC);
1911         if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1912                 warn("abort");
1913         fprintf(cout, "%cABOR\r\n", DM);
1914         (void)fflush(cout);
1915         FD_ZERO(&mask);
1916         FD_SET(fileno(cin), &mask);
1917         if (din) {
1918                 FD_SET(fileno(din), &mask);
1919         }
1920         if ((nfnd = empty(&mask, 10)) <= 0) {
1921                 if (nfnd < 0) {
1922                         warn("abort");
1923                 }
1924                 if (ptabflg)
1925                         code = -1;
1926                 lostpeer();
1927         }
1928         if (din && FD_ISSET(fileno(din), &mask)) {
1929                 while (read(fileno(din), buf, BUFSIZ) > 0)
1930                         /* LOOP */;
1931         }
1932         if (getreply(0) == ERROR && code == 552) {
1933                 /* 552 needed for nic style abort */
1934                 (void)getreply(0);
1935         }
1936         (void)getreply(0);
1937 }
1938
1939 void
1940 ai_unmapped(ai)
1941         struct addrinfo *ai;
1942 {
1943         struct sockaddr_in6 *sin6;
1944         struct sockaddr_in sin;
1945
1946         if (ai->ai_family != AF_INET6)
1947                 return;
1948         if (ai->ai_addrlen != sizeof(struct sockaddr_in6) ||
1949             sizeof(sin) > ai->ai_addrlen)
1950                 return;
1951         sin6 = (struct sockaddr_in6 *)ai->ai_addr;
1952         if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
1953                 return;
1954
1955         memset(&sin, 0, sizeof(sin));
1956         sin.sin_family = AF_INET;
1957         sin.sin_len = sizeof(struct sockaddr_in);
1958         memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
1959             sizeof(sin.sin_addr));
1960         sin.sin_port = sin6->sin6_port;
1961
1962         ai->ai_family = AF_INET;
1963         memcpy(ai->ai_addr, &sin, sin.sin_len);
1964         ai->ai_addrlen = sin.sin_len;
1965 }