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