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