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