Use the fliesystem block size instead of BUFSIZ when the client sends files.
[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.5 2004/01/22 19:39:13 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(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                 } else
1337                         error = 1;
1338
1339                 if (error) {
1340                         puts(
1341 "Passive mode address scan failure. Shouldn't happen!");
1342                         goto bad;
1343                 };
1344
1345                 data_addr.su_port = htons(pack2(prt, 0));
1346
1347                 if (connect(data, (struct sockaddr *)&data_addr,
1348                             data_addr.su_len) < 0) {
1349                         warn("connect");
1350                         goto bad;
1351                 }
1352 #ifdef IP_TOS
1353                 if (data_addr.su_family == AF_INET)
1354               {
1355                 on = IPTOS_THROUGHPUT;
1356                 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1357                                sizeof(int)) < 0)
1358                         warn("setsockopt TOS (ignored)");
1359               }
1360 #endif
1361                 return (0);
1362         }
1363
1364 noport:
1365         data_addr = myctladdr;
1366         if (sendport)
1367                 data_addr.su_port = 0;  /* let system pick one */
1368         if (data != -1)
1369                 (void)close(data);
1370         data = socket(data_addr.su_family, SOCK_STREAM, 0);
1371         if (data < 0) {
1372                 warn("socket");
1373                 if (tmpno)
1374                         sendport = 1;
1375                 return (1);
1376         }
1377         if (!sendport)
1378                 if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1379                                 sizeof(on)) < 0) {
1380                         warn("setsockopt (reuse address)");
1381                         goto bad;
1382                 }
1383 #ifdef IP_PORTRANGE
1384         if (data_addr.su_family == AF_INET)
1385       {
1386         
1387         ports = restricted_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
1388         if (setsockopt(data, IPPROTO_IP, IP_PORTRANGE, (char *)&ports,
1389                        sizeof(ports)) < 0)
1390             warn("setsockopt PORTRANGE (ignored)");
1391       }
1392 #endif
1393 #ifdef INET6
1394 #ifdef IPV6_PORTRANGE
1395         if (data_addr.su_family == AF_INET6) {
1396                 ports = restricted_data_ports ? IPV6_PORTRANGE_HIGH
1397                         : IPV6_PORTRANGE_DEFAULT;
1398                 if (setsockopt(data, IPPROTO_IPV6, IPV6_PORTRANGE,
1399                                (char *)&ports, sizeof(ports)) < 0)
1400                   warn("setsockopt PORTRANGE (ignored)");
1401         }
1402 #endif
1403 #endif
1404         if (bind(data, (struct sockaddr *)&data_addr, data_addr.su_len) < 0) {
1405                 warn("bind");
1406                 goto bad;
1407         }
1408         if (options & SO_DEBUG &&
1409             setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1410                         sizeof(on)) < 0)
1411                 warn("setsockopt (ignored)");
1412         len = sizeof(data_addr);
1413         if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1414                 warn("getsockname");
1415                 goto bad;
1416         }
1417         if (listen(data, 1) < 0)
1418                 warn("listen");
1419         if (sendport) {
1420                 char hname[INET6_ADDRSTRLEN];
1421                 int af;
1422                 struct sockaddr_in data_addr4;
1423                 union sockunion *daddr;
1424
1425 #ifdef INET6
1426                 if (data_addr.su_family == AF_INET6 &&
1427                     IN6_IS_ADDR_V4MAPPED(&data_addr.su_sin6.sin6_addr)) {
1428                         memset(&data_addr4, 0, sizeof(data_addr4));
1429                         data_addr4.sin_len = sizeof(struct sockaddr_in);
1430                         data_addr4.sin_family = AF_INET;
1431                         data_addr4.sin_port = data_addr.su_port;
1432                         memcpy((caddr_t)&data_addr4.sin_addr,
1433                                (caddr_t)&data_addr.su_sin6.sin6_addr.s6_addr[12],
1434                                sizeof(struct in_addr));
1435                         daddr = (union sockunion *)&data_addr4;
1436                 } else
1437 #endif
1438                 daddr = &data_addr;
1439
1440
1441
1442 #define UC(b)   (((int)b)&0xff)
1443
1444                 switch (daddr->su_family) {
1445 #ifdef INET6
1446                 case AF_INET6:
1447                         af = (daddr->su_family == AF_INET) ? 1 : 2;
1448                         if (daddr->su_family == AF_INET6)
1449                                 daddr->su_sin6.sin6_scope_id = 0;
1450                         if (getnameinfo((struct sockaddr *)daddr,
1451                                         daddr->su_len, hname,
1452                                         sizeof(hname) - 1, NULL, 0,
1453                                         NI_NUMERICHOST)) {
1454                                 result = ERROR;
1455                         } else {
1456                                 result = command("EPRT |%d|%s|%d|",
1457                                         af, hname, ntohs(daddr->su_port));
1458                         }
1459                         break;
1460 #endif
1461                 default:
1462                         result = COMPLETE + 1;
1463                         break;
1464                 }
1465                 if (result == COMPLETE)
1466                         goto skip_port;
1467
1468                 p = (char *)&daddr->su_port;
1469                 switch (daddr->su_family) {
1470                 case AF_INET:
1471                         a = (char *)&daddr->su_sin.sin_addr;
1472                         result = command("PORT %d,%d,%d,%d,%d,%d",
1473                                          UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
1474                                          UC(p[0]), UC(p[1]));
1475                         break;
1476 #ifdef INET6
1477                 case AF_INET6:
1478                         a = (char *)&daddr->su_sin6.sin6_addr;
1479                         result = command(
1480 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1481                                          6, 16,
1482                                          UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
1483                                          UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
1484                                          UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
1485                                          UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
1486                                          2, UC(p[0]), UC(p[1]));
1487                         break;
1488 #endif
1489                 default:
1490                         result = COMPLETE + 1; /* xxx */
1491                 }
1492         skip_port:
1493                 
1494                 if (result == ERROR && sendport == -1) {
1495                         sendport = 0;
1496                         tmpno = 1;
1497                         goto noport;
1498                 }
1499                 return (result != COMPLETE);
1500         }
1501         if (tmpno)
1502                 sendport = 1;
1503 #ifdef IP_TOS
1504         if (data_addr.su_family == AF_INET)
1505       {
1506         on = IPTOS_THROUGHPUT;
1507         if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1508                 warn("setsockopt TOS (ignored)");
1509       }
1510 #endif
1511         return (0);
1512 bad:
1513         (void)close(data), data = -1;
1514         if (tmpno)
1515                 sendport = 1;
1516         return (1);
1517 }
1518
1519 FILE *
1520 dataconn(const char *lmode)
1521 {
1522         union sockunion from;
1523         int s, fromlen, tos;
1524
1525         fromlen = myctladdr.su_len;
1526
1527         if (passivemode)
1528                 return (fdopen(data, lmode));
1529
1530         s = accept(data, (struct sockaddr *) &from, &fromlen);
1531         if (s < 0) {
1532                 warn("accept");
1533                 (void)close(data), data = -1;
1534                 return (NULL);
1535         }
1536         (void)close(data);
1537         data = s;
1538 #ifdef IP_TOS
1539         if (data_addr.su_family == AF_INET)
1540       {
1541         tos = IPTOS_THROUGHPUT;
1542         if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1543                 warn("setsockopt TOS (ignored)");
1544       }
1545 #endif
1546         return (fdopen(data, lmode));
1547 }
1548
1549 void
1550 psummary(int notused)
1551 {
1552
1553         if (bytes > 0)
1554                 ptransfer(1);
1555 }
1556
1557 void
1558 psabort(int notused)
1559 {
1560
1561         alarmtimer(0);
1562         abrtflag++;
1563 }
1564
1565 void
1566 pswitch(int flag)
1567 {
1568         sig_t oldintr;
1569         static struct comvars {
1570                 int connect;
1571                 char name[MAXHOSTNAMELEN];
1572                 union sockunion mctl;
1573                 union sockunion hctl;
1574                 FILE *in;
1575                 FILE *out;
1576                 int tpe;
1577                 int curtpe;
1578                 int cpnd;
1579                 int sunqe;
1580                 int runqe;
1581                 int mcse;
1582                 int ntflg;
1583                 char nti[17];
1584                 char nto[17];
1585                 int mapflg;
1586                 char mi[MAXPATHLEN];
1587                 char mo[MAXPATHLEN];
1588         } proxstruct, tmpstruct;
1589         struct comvars *ip, *op;
1590
1591         abrtflag = 0;
1592         oldintr = signal(SIGINT, psabort);
1593         if (flag) {
1594                 if (proxy)
1595                         return;
1596                 ip = &tmpstruct;
1597                 op = &proxstruct;
1598                 proxy++;
1599         } else {
1600                 if (!proxy)
1601                         return;
1602                 ip = &proxstruct;
1603                 op = &tmpstruct;
1604                 proxy = 0;
1605         }
1606         ip->connect = connected;
1607         connected = op->connect;
1608         if (hostname) {
1609                 (void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1610                 ip->name[sizeof(ip->name) - 1] = '\0';
1611         } else
1612                 ip->name[0] = '\0';
1613         hostname = op->name;
1614         ip->hctl = hisctladdr;
1615         hisctladdr = op->hctl;
1616         ip->mctl = myctladdr;
1617         myctladdr = op->mctl;
1618         ip->in = cin;
1619         cin = op->in;
1620         ip->out = cout;
1621         cout = op->out;
1622         ip->tpe = type;
1623         type = op->tpe;
1624         ip->curtpe = curtype;
1625         curtype = op->curtpe;
1626         ip->cpnd = cpend;
1627         cpend = op->cpnd;
1628         ip->sunqe = sunique;
1629         sunique = op->sunqe;
1630         ip->runqe = runique;
1631         runique = op->runqe;
1632         ip->mcse = mcase;
1633         mcase = op->mcse;
1634         ip->ntflg = ntflag;
1635         ntflag = op->ntflg;
1636         (void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
1637         (ip->nti)[sizeof(ip->nti) - 1] = '\0';
1638         (void)strcpy(ntin, op->nti);
1639         (void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
1640         (ip->nto)[sizeof(ip->nto) - 1] = '\0';
1641         (void)strcpy(ntout, op->nto);
1642         ip->mapflg = mapflag;
1643         mapflag = op->mapflg;
1644         (void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
1645         (ip->mi)[sizeof(ip->mi) - 1] = '\0';
1646         (void)strcpy(mapin, op->mi);
1647         (void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
1648         (ip->mo)[sizeof(ip->mo) - 1] = '\0';
1649         (void)strcpy(mapout, op->mo);
1650         (void)signal(SIGINT, oldintr);
1651         if (abrtflag) {
1652                 abrtflag = 0;
1653                 (*oldintr)(SIGINT);
1654         }
1655 }
1656
1657 void
1658 abortpt(int notused)
1659 {
1660
1661         alarmtimer(0);
1662         putchar('\n');
1663         (void)fflush(stdout);
1664         ptabflg++;
1665         mflag = 0;
1666         abrtflag = 0;
1667         longjmp(ptabort, 1);
1668 }
1669
1670 void
1671 proxtrans(const char *cmd, const char *local, const char *remote)
1672 {
1673         sig_t oldintr;
1674         int prox_type, nfnd;
1675         volatile int secndflag;
1676         char *cmd2;
1677         fd_set mask;
1678
1679 #ifdef __GNUC__                 /* XXX: to shut up gcc warnings */
1680         (void)&oldintr;
1681         (void)&cmd2;
1682 #endif
1683
1684         oldintr = NULL;
1685         secndflag = 0;
1686         if (strcmp(cmd, "RETR"))
1687                 cmd2 = "RETR";
1688         else
1689                 cmd2 = runique ? "STOU" : "STOR";
1690         if ((prox_type = type) == 0) {
1691                 if (unix_server && unix_proxy)
1692                         prox_type = TYPE_I;
1693                 else
1694                         prox_type = TYPE_A;
1695         }
1696         if (curtype != prox_type)
1697                 changetype(prox_type, 1);
1698         if (try_epsv && command("EPSV") != COMPLETE)
1699                 try_epsv = 0;
1700         if (!try_epsv && command("PASV") != COMPLETE) {
1701                 puts("proxy server does not support third party transfers.");
1702                 return;
1703         }
1704         pswitch(0);
1705         if (!connected) {
1706                 puts("No primary connection.");
1707                 pswitch(1);
1708                 code = -1;
1709                 return;
1710         }
1711         if (curtype != prox_type)
1712                 changetype(prox_type, 1);
1713         if (command("PORT %s", pasv) != COMPLETE) {
1714                 pswitch(1);
1715                 return;
1716         }
1717         if (setjmp(ptabort))
1718                 goto abort;
1719         oldintr = signal(SIGINT, abortpt);
1720         if (command("%s %s", cmd, remote) != PRELIM) {
1721                 (void)signal(SIGINT, oldintr);
1722                 pswitch(1);
1723                 return;
1724         }
1725         sleep(2);
1726         pswitch(1);
1727         secndflag++;
1728         if (command("%s %s", cmd2, local) != PRELIM)
1729                 goto abort;
1730         ptflag++;
1731         (void)getreply(0);
1732         pswitch(0);
1733         (void)getreply(0);
1734         (void)signal(SIGINT, oldintr);
1735         pswitch(1);
1736         ptflag = 0;
1737         printf("local: %s remote: %s\n", local, remote);
1738         return;
1739 abort:
1740         (void)signal(SIGINT, SIG_IGN);
1741         ptflag = 0;
1742         if (strcmp(cmd, "RETR") && !proxy)
1743                 pswitch(1);
1744         else if (!strcmp(cmd, "RETR") && proxy)
1745                 pswitch(0);
1746         if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
1747                 if (command("%s %s", cmd2, local) != PRELIM) {
1748                         pswitch(0);
1749                         if (cpend)
1750                                 abort_remote((FILE *) NULL);
1751                 }
1752                 pswitch(1);
1753                 if (ptabflg)
1754                         code = -1;
1755                 (void)signal(SIGINT, oldintr);
1756                 return;
1757         }
1758         if (cpend)
1759                 abort_remote((FILE *) NULL);
1760         pswitch(!proxy);
1761         if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
1762                 if (command("%s %s", cmd2, local) != PRELIM) {
1763                         pswitch(0);
1764                         if (cpend)
1765                                 abort_remote((FILE *) NULL);
1766                         pswitch(1);
1767                         if (ptabflg)
1768                                 code = -1;
1769                         (void)signal(SIGINT, oldintr);
1770                         return;
1771                 }
1772         }
1773         if (cpend)
1774                 abort_remote((FILE *) NULL);
1775         pswitch(!proxy);
1776         if (cpend) {
1777                 FD_ZERO(&mask);
1778                 FD_SET(fileno(cin), &mask);
1779                 if ((nfnd = empty(&mask, 10)) <= 0) {
1780                         if (nfnd < 0) {
1781                                 warn("abort");
1782                         }
1783                         if (ptabflg)
1784                                 code = -1;
1785                         lostpeer();
1786                 }
1787                 (void)getreply(0);
1788                 (void)getreply(0);
1789         }
1790         if (proxy)
1791                 pswitch(0);
1792         pswitch(1);
1793         if (ptabflg)
1794                 code = -1;
1795         (void)signal(SIGINT, oldintr);
1796 }
1797
1798 void
1799 reset(int argc, char **argv)
1800 {
1801         fd_set mask;
1802         int nfnd = 1;
1803
1804         FD_ZERO(&mask);
1805         while (nfnd > 0) {
1806                 FD_SET(fileno(cin), &mask);
1807                 if ((nfnd = empty(&mask, 0)) < 0) {
1808                         warn("reset");
1809                         code = -1;
1810                         lostpeer();
1811                 }
1812                 else if (nfnd) {
1813                         (void)getreply(0);
1814                 }
1815         }
1816 }
1817
1818 char *
1819 gunique(const char *local)
1820 {
1821         static char new[MAXPATHLEN];
1822         char *cp = strrchr(local, '/');
1823         int d, count=0;
1824         char ext = '1';
1825
1826         if (cp)
1827                 *cp = '\0';
1828         d = access(cp == local ? "/" : cp ? local : ".", W_OK);
1829         if (cp)
1830                 *cp = '/';
1831         if (d < 0) {
1832                 warn("local: %s", local);
1833                 return ((char *) 0);
1834         }
1835         (void)strcpy(new, local);
1836         cp = new + strlen(new);
1837         *cp++ = '.';
1838         while (!d) {
1839                 if (++count == 100) {
1840                         puts("runique: can't find unique file name.");
1841                         return ((char *) 0);
1842                 }
1843                 *cp++ = ext;
1844                 *cp = '\0';
1845                 if (ext == '9')
1846                         ext = '0';
1847                 else
1848                         ext++;
1849                 if ((d = access(new, F_OK)) < 0)
1850                         break;
1851                 if (ext != '0')
1852                         cp--;
1853                 else if (*(cp - 2) == '.')
1854                         *(cp - 1) = '1';
1855                 else {
1856                         *(cp - 2) = *(cp - 2) + 1;
1857                         cp--;
1858                 }
1859         }
1860         return (new);
1861 }
1862
1863 void
1864 abort_remote(FILE *din)
1865 {
1866         char buf[BUFSIZ];
1867         int nfnd;
1868         fd_set mask;
1869
1870         if (cout == NULL) {
1871                 warnx("Lost control connection for abort.");
1872                 if (ptabflg)
1873                         code = -1;
1874                 lostpeer();
1875                 return;
1876         }
1877         /*
1878          * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1879          * after urgent byte rather than before as is protocol now
1880          */
1881         sprintf(buf, "%c%c%c", IAC, IP, IAC);
1882         if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1883                 warn("abort");
1884         fprintf(cout, "%cABOR\r\n", DM);
1885         (void)fflush(cout);
1886         FD_ZERO(&mask);
1887         FD_SET(fileno(cin), &mask);
1888         if (din) {
1889                 FD_SET(fileno(din), &mask);
1890         }
1891         if ((nfnd = empty(&mask, 10)) <= 0) {
1892                 if (nfnd < 0) {
1893                         warn("abort");
1894                 }
1895                 if (ptabflg)
1896                         code = -1;
1897                 lostpeer();
1898         }
1899         if (din && FD_ISSET(fileno(din), &mask)) {
1900                 while (read(fileno(din), buf, BUFSIZ) > 0)
1901                         /* LOOP */;
1902         }
1903         if (getreply(0) == ERROR && code == 552) {
1904                 /* 552 needed for nic style abort */
1905                 (void)getreply(0);
1906         }
1907         (void)getreply(0);
1908 }
1909
1910 void
1911 ai_unmapped(struct addrinfo *ai)
1912 {
1913         struct sockaddr_in6 *sin6;
1914         struct sockaddr_in sin;
1915
1916         if (ai->ai_family != AF_INET6)
1917                 return;
1918         if (ai->ai_addrlen != sizeof(struct sockaddr_in6) ||
1919             sizeof(sin) > ai->ai_addrlen)
1920                 return;
1921         sin6 = (struct sockaddr_in6 *)ai->ai_addr;
1922         if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
1923                 return;
1924
1925         memset(&sin, 0, sizeof(sin));
1926         sin.sin_family = AF_INET;
1927         sin.sin_len = sizeof(struct sockaddr_in);
1928         memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
1929             sizeof(sin.sin_addr));
1930         sin.sin_port = sin6->sin6_port;
1931
1932         ai->ai_family = AF_INET;
1933         memcpy(ai->ai_addr, &sin, sin.sin_len);
1934         ai->ai_addrlen = sin.sin_len;
1935 }