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