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