ftp.c revision 1.46 1 /* $NetBSD: ftp.c,v 1.46 1999/06/29 10:43:18 lukem 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.46 1999/06/29 10:43:18 lukem 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 while (1) {
644 struct timeval then, now, td;
645 off_t bufrem, bufsize;
646
647 bufsize = sizeof(buf);
648 (void)gettimeofday(&then, NULL);
649 errno = c = d = 0;
650 bufrem = rate_put ? rate_put : bufsize;
651 while (bufrem > 0) {
652 if ((c = read(fileno(fin), buf,
653 MIN(bufsize, bufrem))) <= 0)
654 goto senddone;
655 bytes += c;
656 bufrem -= c;
657 for (bufp = buf; c > 0; c -= d, bufp += d)
658 if ((d = write(fileno(dout), bufp, c))
659 <= 0)
660 break;
661 if (d < 0)
662 goto senddone;
663 if (hash && (!progress || filesize < 0) ) {
664 while (bytes >= hashbytes) {
665 (void)putc('#', ttyout);
666 hashbytes += mark;
667 }
668 (void)fflush(ttyout);
669 }
670 }
671 if (rate_put) {
672 while (1) {
673 (void)gettimeofday(&now, NULL);
674 timersub(&now, &then, &td);
675 if (td.tv_sec > 0)
676 break;
677 usleep(1000000 - td.tv_usec);
678 }
679 }
680 }
681 senddone:
682 if (hash && (!progress || filesize < 0) && bytes > 0) {
683 if (bytes < mark)
684 (void)putc('#', ttyout);
685 (void)putc('\n', ttyout);
686 }
687 if (c < 0)
688 warn("local: %s", local);
689 if (d < 0) {
690 if (errno != EPIPE)
691 warn("netout");
692 bytes = -1;
693 }
694 break;
695
696 case TYPE_A:
697 while ((c = getc(fin)) != EOF) {
698 if (c == '\n') {
699 while (hash && (!progress || filesize < 0) &&
700 (bytes >= hashbytes)) {
701 (void)putc('#', ttyout);
702 (void)fflush(ttyout);
703 hashbytes += mark;
704 }
705 if (ferror(dout))
706 break;
707 (void)putc('\r', dout);
708 bytes++;
709 }
710 (void)putc(c, dout);
711 bytes++;
712 #if 0 /* this violates RFC */
713 if (c == '\r') {
714 (void)putc('\0', dout);
715 bytes++;
716 }
717 #endif
718 }
719 if (hash && (!progress || filesize < 0)) {
720 if (bytes < hashbytes)
721 (void)putc('#', ttyout);
722 (void)putc('\n', ttyout);
723 }
724 if (ferror(fin))
725 warn("local: %s", local);
726 if (ferror(dout)) {
727 if (errno != EPIPE)
728 warn("netout");
729 bytes = -1;
730 }
731 break;
732 }
733 progressmeter(1);
734 if (closefunc != NULL)
735 (*closefunc)(fin);
736 (void)fclose(dout);
737 (void)getreply(0);
738 (void)signal(SIGINT, oldintr);
739 (void)xsignal(SIGINFO, oldinti);
740 if (oldintp)
741 (void)signal(SIGPIPE, oldintp);
742 if (bytes > 0)
743 ptransfer(0);
744 goto cleanupsend;
745 abort:
746 (void)signal(SIGINT, oldintr);
747 (void)xsignal(SIGINFO, oldinti);
748 if (oldintp)
749 (void)signal(SIGPIPE, oldintp);
750 if (!cpend) {
751 code = -1;
752 return;
753 }
754 if (data >= 0) {
755 (void)close(data);
756 data = -1;
757 }
758 if (dout)
759 (void)fclose(dout);
760 (void)getreply(0);
761 code = -1;
762 if (closefunc != NULL && fin != NULL)
763 (*closefunc)(fin);
764 if (bytes > 0)
765 ptransfer(0);
766 cleanupsend:
767 progress = oprogress;
768 restart_point = 0;
769 }
770
771 jmp_buf recvabort;
772
773 void
774 abortrecv(notused)
775 int notused;
776 {
777
778 alarmtimer(0);
779 mflag = 0;
780 abrtflag = 0;
781 fputs("\nreceive aborted\nwaiting for remote to finish abort.\n",
782 ttyout);
783 longjmp(recvabort, 1);
784 }
785
786 void
787 recvrequest(cmd, local, remote, lmode, printnames, ignorespecial)
788 const char *cmd, *local, *remote, *lmode;
789 int printnames, ignorespecial;
790 {
791 FILE *fout, *din;
792 int (*closefunc) __P((FILE *));
793 sig_t oldinti, oldintr, oldintp;
794 int c, d;
795 volatile int is_retr, tcrflag, bare_lfs;
796 size_t bufsize;
797 char *buf;
798 volatile off_t hashbytes;
799 struct stat st;
800 time_t mtime;
801 struct timeval tval[2];
802 int oprogress;
803 int opreserve;
804
805 #ifdef __GNUC__ /* to shut up gcc warnings */
806 (void)&local;
807 (void)&fout;
808 (void)&din;
809 (void)&closefunc;
810 (void)&oldinti;
811 (void)&oldintr;
812 (void)&oldintp;
813 #endif
814
815 fout = NULL;
816 din = NULL;
817 oldinti = NULL;
818 hashbytes = mark;
819 direction = "received";
820 bytes = 0;
821 bare_lfs = 0;
822 filesize = -1;
823 oprogress = progress;
824 opreserve = preserve;
825 is_retr = (strcmp(cmd, "RETR") == 0);
826 if (is_retr && verbose && printnames) {
827 if (local && (ignorespecial || *local != '-'))
828 fprintf(ttyout, "local: %s ", local);
829 if (remote)
830 fprintf(ttyout, "remote: %s\n", remote);
831 }
832 if (proxy && is_retr) {
833 proxtrans(cmd, local, remote);
834 return;
835 }
836 closefunc = NULL;
837 oldintr = NULL;
838 oldintp = NULL;
839 tcrflag = !crflag && is_retr;
840 if (setjmp(recvabort)) {
841 while (cpend) {
842 (void)getreply(0);
843 }
844 if (data >= 0) {
845 (void)close(data);
846 data = -1;
847 }
848 if (oldintr)
849 (void)signal(SIGINT, oldintr);
850 if (oldinti)
851 (void)xsignal(SIGINFO, oldinti);
852 progress = oprogress;
853 preserve = opreserve;
854 code = -1;
855 return;
856 }
857 oldintr = signal(SIGINT, abortrecv);
858 oldinti = xsignal(SIGINFO, psummary);
859 if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
860 if (access(local, W_OK) < 0) {
861 char *dir = strrchr(local, '/');
862
863 if (errno != ENOENT && errno != EACCES) {
864 warn("local: %s", local);
865 (void)signal(SIGINT, oldintr);
866 (void)xsignal(SIGINFO, oldinti);
867 code = -1;
868 return;
869 }
870 if (dir != NULL)
871 *dir = 0;
872 d = access(dir == local ? "/" :
873 dir ? local : ".", W_OK);
874 if (dir != NULL)
875 *dir = '/';
876 if (d < 0) {
877 warn("local: %s", local);
878 (void)signal(SIGINT, oldintr);
879 (void)xsignal(SIGINFO, oldinti);
880 code = -1;
881 return;
882 }
883 if (!runique && errno == EACCES &&
884 chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
885 warn("local: %s", local);
886 (void)signal(SIGINT, oldintr);
887 (void)xsignal(SIGINFO, oldinti);
888 code = -1;
889 return;
890 }
891 if (runique && errno == EACCES &&
892 (local = gunique(local)) == NULL) {
893 (void)signal(SIGINT, oldintr);
894 (void)xsignal(SIGINFO, oldinti);
895 code = -1;
896 return;
897 }
898 }
899 else if (runique && (local = gunique(local)) == NULL) {
900 (void)signal(SIGINT, oldintr);
901 (void)xsignal(SIGINFO, oldinti);
902 code = -1;
903 return;
904 }
905 }
906 if (!is_retr) {
907 if (curtype != TYPE_A)
908 changetype(TYPE_A, 0);
909 } else {
910 if (curtype != type)
911 changetype(type, 0);
912 filesize = remotesize(remote, 0);
913 }
914 if (initconn()) {
915 (void)signal(SIGINT, oldintr);
916 (void)xsignal(SIGINFO, oldinti);
917 code = -1;
918 return;
919 }
920 if (setjmp(recvabort))
921 goto abort;
922 if (is_retr && restart_point &&
923 #ifndef NO_QUAD
924 command("REST %qd", (long long) restart_point) != CONTINUE)
925 #else
926 command("REST %ld", (long) restart_point) != CONTINUE)
927 #endif
928 return;
929 if (remote) {
930 if (command("%s %s", cmd, remote) != PRELIM) {
931 (void)signal(SIGINT, oldintr);
932 (void)xsignal(SIGINFO, oldinti);
933 return;
934 }
935 } else {
936 if (command("%s", cmd) != PRELIM) {
937 (void)signal(SIGINT, oldintr);
938 (void)xsignal(SIGINFO, oldinti);
939 return;
940 }
941 }
942 din = dataconn("r");
943 if (din == NULL)
944 goto abort;
945 if (!ignorespecial && strcmp(local, "-") == 0) {
946 fout = stdout;
947 progress = 0;
948 preserve = 0;
949 } else if (!ignorespecial && *local == '|') {
950 oldintp = signal(SIGPIPE, SIG_IGN);
951 fout = popen(local + 1, "w");
952 if (fout == NULL) {
953 warn("%s", local+1);
954 goto abort;
955 }
956 progress = 0;
957 preserve = 0;
958 closefunc = pclose;
959 } else {
960 fout = fopen(local, lmode);
961 if (fout == NULL) {
962 warn("local: %s", local);
963 goto abort;
964 }
965 closefunc = fclose;
966 }
967
968 /*
969 * XXX: look at punting and just using sndbuf_* for
970 * the buffer size, since st.st_blksize ~= 512
971 * and BUFSIZ ~= 4K
972 */
973 if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
974 st.st_blksize = BUFSIZ;
975 if (st.st_blksize > bufsize) {
976 if (buf)
977 (void)free(buf);
978 bufsize = st.st_blksize;
979 buf = xmalloc(bufsize);
980 }
981 if (!S_ISREG(st.st_mode)) {
982 progress = 0;
983 preserve = 0;
984 }
985 progressmeter(-1);
986 switch (curtype) {
987
988 case TYPE_I:
989 case TYPE_L:
990 if (is_retr && restart_point &&
991 lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
992 warn("local: %s", local);
993 progress = oprogress;
994 preserve = opreserve;
995 if (closefunc != NULL)
996 (*closefunc)(fout);
997 return;
998 }
999 while (1) {
1000 struct timeval then, now, td;
1001 off_t bufrem;
1002
1003 (void)gettimeofday(&then, NULL);
1004 errno = c = d = 0;
1005 bufrem = rate_get ? rate_get : bufsize;
1006 while (bufrem > 0) {
1007 if ((c = read(fileno(din), buf,
1008 MIN(bufsize, bufrem))) <= 0)
1009 goto recvdone;
1010 bytes += c;
1011 bufrem -=c;
1012 if ((d = write(fileno(fout), buf, c)) != c)
1013 goto recvdone;
1014 if (hash && (!progress || filesize < 0)) {
1015 while (bytes >= hashbytes) {
1016 (void)putc('#', ttyout);
1017 hashbytes += mark;
1018 }
1019 (void)fflush(ttyout);
1020 }
1021 }
1022 if (rate_get) {
1023 while (1) {
1024 (void)gettimeofday(&now, NULL);
1025 timersub(&now, &then, &td);
1026 if (td.tv_sec > 0)
1027 break;
1028 usleep(1000000 - td.tv_usec);
1029 }
1030 }
1031 }
1032 recvdone:
1033 if (hash && (!progress || filesize < 0) && bytes > 0) {
1034 if (bytes < mark)
1035 (void)putc('#', ttyout);
1036 (void)putc('\n', ttyout);
1037 }
1038 if (c < 0) {
1039 if (errno != EPIPE)
1040 warn("netin");
1041 bytes = -1;
1042 }
1043 if (d < c) {
1044 if (d < 0)
1045 warn("local: %s", local);
1046 else
1047 warnx("%s: short write", local);
1048 }
1049 break;
1050
1051 case TYPE_A:
1052 if (is_retr && restart_point) {
1053 int ch;
1054 long i, n;
1055
1056 if (fseek(fout, 0L, SEEK_SET) < 0)
1057 goto done;
1058 n = (long)restart_point;
1059 for (i = 0; i++ < n;) {
1060 if ((ch = getc(fout)) == EOF)
1061 goto done;
1062 if (ch == '\n')
1063 i++;
1064 }
1065 if (fseek(fout, 0L, SEEK_CUR) < 0) {
1066 done:
1067 warn("local: %s", local);
1068 progress = oprogress;
1069 preserve = opreserve;
1070 if (closefunc != NULL)
1071 (*closefunc)(fout);
1072 return;
1073 }
1074 }
1075 while ((c = getc(din)) != EOF) {
1076 if (c == '\n')
1077 bare_lfs++;
1078 while (c == '\r') {
1079 while (hash && (!progress || filesize < 0) &&
1080 (bytes >= hashbytes)) {
1081 (void)putc('#', ttyout);
1082 (void)fflush(ttyout);
1083 hashbytes += mark;
1084 }
1085 bytes++;
1086 if ((c = getc(din)) != '\n' || tcrflag) {
1087 if (ferror(fout))
1088 goto break2;
1089 (void)putc('\r', fout);
1090 if (c == '\0') {
1091 bytes++;
1092 goto contin2;
1093 }
1094 if (c == EOF)
1095 goto contin2;
1096 }
1097 }
1098 (void)putc(c, fout);
1099 bytes++;
1100 contin2: ;
1101 }
1102 break2:
1103 if (hash && (!progress || filesize < 0)) {
1104 if (bytes < hashbytes)
1105 (void)putc('#', ttyout);
1106 (void)putc('\n', ttyout);
1107 }
1108 if (ferror(din)) {
1109 if (errno != EPIPE)
1110 warn("netin");
1111 bytes = -1;
1112 }
1113 if (ferror(fout))
1114 warn("local: %s", local);
1115 break;
1116 }
1117 progressmeter(1);
1118 if (closefunc != NULL)
1119 (*closefunc)(fout);
1120 (void)signal(SIGINT, oldintr);
1121 (void)xsignal(SIGINFO, oldinti);
1122 if (oldintp)
1123 (void)signal(SIGPIPE, oldintp);
1124 (void)fclose(din);
1125 (void)getreply(0);
1126 if (bare_lfs) {
1127 fprintf(ttyout,
1128 "WARNING! %d bare linefeeds received in ASCII mode.\n",
1129 bare_lfs);
1130 fputs("File may not have transferred correctly.\n", ttyout);
1131 }
1132 if (bytes >= 0 && is_retr) {
1133 if (bytes > 0)
1134 ptransfer(0);
1135 if (preserve && (closefunc == fclose)) {
1136 mtime = remotemodtime(remote, 0);
1137 if (mtime != -1) {
1138 (void)gettimeofday(&tval[0], NULL);
1139 tval[1].tv_sec = mtime;
1140 tval[1].tv_usec = 0;
1141 if (utimes(local, tval) == -1) {
1142 fprintf(ttyout,
1143 "Can't change modification time on %s to %s",
1144 local, asctime(localtime(&mtime)));
1145 }
1146 }
1147 }
1148 }
1149 progress = oprogress;
1150 preserve = opreserve;
1151 return;
1152
1153 abort:
1154
1155 /* abort using RFC 959 recommended IP,SYNC sequence */
1156
1157 progress = oprogress;
1158 preserve = opreserve;
1159 if (oldintp)
1160 (void)signal(SIGPIPE, oldintp);
1161 (void)signal(SIGINT, SIG_IGN);
1162 if (!cpend) {
1163 code = -1;
1164 (void)signal(SIGINT, oldintr);
1165 (void)xsignal(SIGINFO, oldinti);
1166 return;
1167 }
1168
1169 abort_remote(din);
1170 code = -1;
1171 if (data >= 0) {
1172 (void)close(data);
1173 data = -1;
1174 }
1175 if (closefunc != NULL && fout != NULL)
1176 (*closefunc)(fout);
1177 if (din)
1178 (void)fclose(din);
1179 if (bytes > 0)
1180 ptransfer(0);
1181 (void)signal(SIGINT, oldintr);
1182 (void)xsignal(SIGINFO, oldinti);
1183 }
1184
1185 /*
1186 * Need to start a listen on the data channel before we send the command,
1187 * otherwise the server's connect may fail.
1188 */
1189 int
1190 initconn()
1191 {
1192 char *p, *a;
1193 int result, len, tmpno = 0;
1194 int on = 1;
1195 int a0, a1, a2, a3, p0, p1;
1196
1197 reinit:
1198 if (passivemode) {
1199 data = socket(AF_INET, SOCK_STREAM, 0);
1200 if (data < 0) {
1201 warn("socket");
1202 return (1);
1203 }
1204 if ((options & SO_DEBUG) &&
1205 setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1206 sizeof(on)) < 0)
1207 warn("setsockopt (ignored)");
1208 if (command("PASV") != COMPLETE) {
1209 if (activefallback) {
1210 (void)close(data);
1211 data = -1;
1212 passivemode = 0;
1213 activefallback = 0;
1214 goto reinit;
1215 }
1216 fputs("Passive mode refused.\n", ttyout);
1217 goto bad;
1218 }
1219
1220 /*
1221 * What we've got at this point is a string of comma
1222 * separated one-byte unsigned integer values.
1223 * The first four are the an IP address. The fifth is
1224 * the MSB of the port number, the sixth is the LSB.
1225 * From that we'll prepare a sockaddr_in.
1226 */
1227
1228 if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
1229 &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
1230 fputs(
1231 "Passive mode address scan failure. Shouldn't happen!\n",
1232 ttyout);
1233 goto bad;
1234 }
1235
1236 memset(&data_addr, 0, sizeof(data_addr));
1237 data_addr.sin_family = AF_INET;
1238 a = (char *)&data_addr.sin_addr.s_addr;
1239 a[0] = a0 & 0xff;
1240 a[1] = a1 & 0xff;
1241 a[2] = a2 & 0xff;
1242 a[3] = a3 & 0xff;
1243 p = (char *)&data_addr.sin_port;
1244 p[0] = p0 & 0xff;
1245 p[1] = p1 & 0xff;
1246
1247 while (xconnect(data, (struct sockaddr *)&data_addr,
1248 sizeof(data_addr)) < 0) {
1249 if (errno == EINTR)
1250 continue;
1251 if (activefallback) {
1252 (void)close(data);
1253 data = -1;
1254 passivemode = 0;
1255 activefallback = 0;
1256 goto reinit;
1257 }
1258 warn("connect");
1259 goto bad;
1260 }
1261 #ifdef IP_TOS
1262 on = IPTOS_THROUGHPUT;
1263 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1264 sizeof(int)) < 0)
1265 warn("setsockopt TOS (ignored)");
1266 #endif
1267 return (0);
1268 }
1269
1270 noport:
1271 data_addr = myctladdr;
1272 if (sendport)
1273 data_addr.sin_port = 0; /* let system pick one */
1274 if (data != -1)
1275 (void)close(data);
1276 data = socket(AF_INET, SOCK_STREAM, 0);
1277 if (data < 0) {
1278 warn("socket");
1279 if (tmpno)
1280 sendport = 1;
1281 return (1);
1282 }
1283 if (!sendport)
1284 if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1285 sizeof(on)) < 0) {
1286 warn("setsockopt (reuse address)");
1287 goto bad;
1288 }
1289 if (bind(data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0) {
1290 warn("bind");
1291 goto bad;
1292 }
1293 if (options & SO_DEBUG &&
1294 setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1295 sizeof(on)) < 0)
1296 warn("setsockopt (ignored)");
1297 len = sizeof(data_addr);
1298 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1299 warn("getsockname");
1300 goto bad;
1301 }
1302 if (xlisten(data, 1) < 0)
1303 warn("listen");
1304 if (sendport) {
1305 a = (char *)&data_addr.sin_addr;
1306 p = (char *)&data_addr.sin_port;
1307 #define UC(b) (((int)b)&0xff)
1308 result =
1309 command("PORT %d,%d,%d,%d,%d,%d",
1310 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1311 UC(p[0]), UC(p[1]));
1312 if (result == ERROR && sendport == -1) {
1313 sendport = 0;
1314 tmpno = 1;
1315 goto noport;
1316 }
1317 return (result != COMPLETE);
1318 }
1319 if (tmpno)
1320 sendport = 1;
1321 #ifdef IP_TOS
1322 on = IPTOS_THROUGHPUT;
1323 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1324 warn("setsockopt TOS (ignored)");
1325 #endif
1326 return (0);
1327 bad:
1328 (void)close(data), data = -1;
1329 if (tmpno)
1330 sendport = 1;
1331 return (1);
1332 }
1333
1334 FILE *
1335 dataconn(lmode)
1336 const char *lmode;
1337 {
1338 struct sockaddr_in from;
1339 int s, fromlen, tos;
1340
1341 fromlen = sizeof(from);
1342
1343 if (passivemode)
1344 return (fdopen(data, lmode));
1345
1346 s = accept(data, (struct sockaddr *) &from, &fromlen);
1347 if (s < 0) {
1348 warn("accept");
1349 (void)close(data), data = -1;
1350 return (NULL);
1351 }
1352 (void)close(data);
1353 data = s;
1354 #ifdef IP_TOS
1355 tos = IPTOS_THROUGHPUT;
1356 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1357 warn("setsockopt TOS (ignored)");
1358 #endif
1359 return (fdopen(data, lmode));
1360 }
1361
1362 void
1363 psummary(notused)
1364 int notused;
1365 {
1366 int oerrno;
1367
1368 oerrno = errno;
1369 if (bytes > 0)
1370 ptransfer(1);
1371 errno = oerrno;
1372 }
1373
1374 void
1375 psabort(notused)
1376 int notused;
1377 {
1378
1379 alarmtimer(0);
1380 abrtflag++;
1381 }
1382
1383 void
1384 pswitch(flag)
1385 int flag;
1386 {
1387 sig_t oldintr;
1388 static struct comvars {
1389 int connect;
1390 char name[MAXHOSTNAMELEN];
1391 struct sockaddr_in mctl;
1392 struct sockaddr_in hctl;
1393 FILE *in;
1394 FILE *out;
1395 int tpe;
1396 int curtpe;
1397 int cpnd;
1398 int sunqe;
1399 int runqe;
1400 int mcse;
1401 int ntflg;
1402 char nti[17];
1403 char nto[17];
1404 int mapflg;
1405 char mi[MAXPATHLEN];
1406 char mo[MAXPATHLEN];
1407 } proxstruct, tmpstruct;
1408 struct comvars *ip, *op;
1409
1410 abrtflag = 0;
1411 oldintr = signal(SIGINT, psabort);
1412 if (flag) {
1413 if (proxy)
1414 return;
1415 ip = &tmpstruct;
1416 op = &proxstruct;
1417 proxy++;
1418 } else {
1419 if (!proxy)
1420 return;
1421 ip = &proxstruct;
1422 op = &tmpstruct;
1423 proxy = 0;
1424 }
1425 ip->connect = connected;
1426 connected = op->connect;
1427 if (hostname) {
1428 (void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1429 ip->name[sizeof(ip->name) - 1] = '\0';
1430 } else
1431 ip->name[0] = '\0';
1432 hostname = op->name;
1433 ip->hctl = hisctladdr;
1434 hisctladdr = op->hctl;
1435 ip->mctl = myctladdr;
1436 myctladdr = op->mctl;
1437 ip->in = cin;
1438 cin = op->in;
1439 ip->out = cout;
1440 cout = op->out;
1441 ip->tpe = type;
1442 type = op->tpe;
1443 ip->curtpe = curtype;
1444 curtype = op->curtpe;
1445 ip->cpnd = cpend;
1446 cpend = op->cpnd;
1447 ip->sunqe = sunique;
1448 sunique = op->sunqe;
1449 ip->runqe = runique;
1450 runique = op->runqe;
1451 ip->mcse = mcase;
1452 mcase = op->mcse;
1453 ip->ntflg = ntflag;
1454 ntflag = op->ntflg;
1455 (void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
1456 (ip->nti)[sizeof(ip->nti) - 1] = '\0';
1457 (void)strcpy(ntin, op->nti);
1458 (void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
1459 (ip->nto)[sizeof(ip->nto) - 1] = '\0';
1460 (void)strcpy(ntout, op->nto);
1461 ip->mapflg = mapflag;
1462 mapflag = op->mapflg;
1463 (void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
1464 (ip->mi)[sizeof(ip->mi) - 1] = '\0';
1465 (void)strcpy(mapin, op->mi);
1466 (void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
1467 (ip->mo)[sizeof(ip->mo) - 1] = '\0';
1468 (void)strcpy(mapout, op->mo);
1469 (void)signal(SIGINT, oldintr);
1470 if (abrtflag) {
1471 abrtflag = 0;
1472 (*oldintr)(SIGINT);
1473 }
1474 }
1475
1476 void
1477 abortpt(notused)
1478 int notused;
1479 {
1480
1481 alarmtimer(0);
1482 putc('\n', ttyout);
1483 ptabflg++;
1484 mflag = 0;
1485 abrtflag = 0;
1486 longjmp(ptabort, 1);
1487 }
1488
1489 void
1490 proxtrans(cmd, local, remote)
1491 const char *cmd, *local, *remote;
1492 {
1493 sig_t oldintr;
1494 int prox_type, nfnd;
1495 volatile int secndflag;
1496 char *cmd2;
1497
1498 #ifdef __GNUC__ /* to shut up gcc warnings */
1499 (void)&oldintr;
1500 (void)&cmd2;
1501 #endif
1502
1503 oldintr = NULL;
1504 secndflag = 0;
1505 if (strcmp(cmd, "RETR"))
1506 cmd2 = "RETR";
1507 else
1508 cmd2 = runique ? "STOU" : "STOR";
1509 if ((prox_type = type) == 0) {
1510 if (unix_server && unix_proxy)
1511 prox_type = TYPE_I;
1512 else
1513 prox_type = TYPE_A;
1514 }
1515 if (curtype != prox_type)
1516 changetype(prox_type, 1);
1517 if (command("PASV") != COMPLETE) {
1518 fputs("proxy server does not support third party transfers.\n",
1519 ttyout);
1520 return;
1521 }
1522 pswitch(0);
1523 if (!connected) {
1524 fputs("No primary connection.\n", ttyout);
1525 pswitch(1);
1526 code = -1;
1527 return;
1528 }
1529 if (curtype != prox_type)
1530 changetype(prox_type, 1);
1531 if (command("PORT %s", pasv) != COMPLETE) {
1532 pswitch(1);
1533 return;
1534 }
1535 if (setjmp(ptabort))
1536 goto abort;
1537 oldintr = signal(SIGINT, abortpt);
1538 if ((restart_point &&
1539 #ifndef NO_QUAD
1540 (command("REST %qd", (long long) restart_point) != CONTINUE)
1541 #else
1542 (command("REST %ld", (long) restart_point) != CONTINUE)
1543 #endif
1544 ) || (command("%s %s", cmd, remote) != PRELIM)) {
1545 (void)signal(SIGINT, oldintr);
1546 pswitch(1);
1547 return;
1548 }
1549 sleep(2);
1550 pswitch(1);
1551 secndflag++;
1552 if ((restart_point &&
1553 #ifndef NO_QUAD
1554 (command("REST %qd", (long long) restart_point) != CONTINUE)
1555 #else
1556 (command("REST %ld", (long) restart_point) != CONTINUE)
1557 #endif
1558 ) || (command("%s %s", cmd2, local) != PRELIM))
1559 goto abort;
1560 ptflag++;
1561 (void)getreply(0);
1562 pswitch(0);
1563 (void)getreply(0);
1564 (void)signal(SIGINT, oldintr);
1565 pswitch(1);
1566 ptflag = 0;
1567 fprintf(ttyout, "local: %s remote: %s\n", local, remote);
1568 return;
1569 abort:
1570 (void)signal(SIGINT, SIG_IGN);
1571 ptflag = 0;
1572 if (strcmp(cmd, "RETR") && !proxy)
1573 pswitch(1);
1574 else if (!strcmp(cmd, "RETR") && proxy)
1575 pswitch(0);
1576 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1577 if (command("%s %s", cmd2, local) != PRELIM) {
1578 pswitch(0);
1579 if (cpend)
1580 abort_remote(NULL);
1581 }
1582 pswitch(1);
1583 if (ptabflg)
1584 code = -1;
1585 (void)signal(SIGINT, oldintr);
1586 return;
1587 }
1588 if (cpend)
1589 abort_remote(NULL);
1590 pswitch(!proxy);
1591 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
1592 if (command("%s %s", cmd2, local) != PRELIM) {
1593 pswitch(0);
1594 if (cpend)
1595 abort_remote(NULL);
1596 pswitch(1);
1597 if (ptabflg)
1598 code = -1;
1599 (void)signal(SIGINT, oldintr);
1600 return;
1601 }
1602 }
1603 if (cpend)
1604 abort_remote(NULL);
1605 pswitch(!proxy);
1606 if (cpend) {
1607 if ((nfnd = empty(cin, NULL, 10)) <= 0) {
1608 if (nfnd < 0) {
1609 warn("abort");
1610 }
1611 if (ptabflg)
1612 code = -1;
1613 lostpeer();
1614 }
1615 (void)getreply(0);
1616 (void)getreply(0);
1617 }
1618 if (proxy)
1619 pswitch(0);
1620 pswitch(1);
1621 if (ptabflg)
1622 code = -1;
1623 (void)signal(SIGINT, oldintr);
1624 }
1625
1626 void
1627 reset(argc, argv)
1628 int argc;
1629 char *argv[];
1630 {
1631 int nfnd = 1;
1632
1633 while (nfnd > 0) {
1634 if ((nfnd = empty(cin, NULL, 0)) < 0) {
1635 warn("reset");
1636 code = -1;
1637 lostpeer();
1638 }
1639 else if (nfnd) {
1640 (void)getreply(0);
1641 }
1642 }
1643 }
1644
1645 char *
1646 gunique(local)
1647 const char *local;
1648 {
1649 static char new[MAXPATHLEN];
1650 char *cp = strrchr(local, '/');
1651 int d, count=0;
1652 char ext = '1';
1653
1654 if (cp)
1655 *cp = '\0';
1656 d = access(cp == local ? "/" : cp ? local : ".", W_OK);
1657 if (cp)
1658 *cp = '/';
1659 if (d < 0) {
1660 warn("local: %s", local);
1661 return (NULL);
1662 }
1663 (void)strcpy(new, local);
1664 cp = new + strlen(new);
1665 *cp++ = '.';
1666 while (!d) {
1667 if (++count == 100) {
1668 fputs("runique: can't find unique file name.\n",
1669 ttyout);
1670 return (NULL);
1671 }
1672 *cp++ = ext;
1673 *cp = '\0';
1674 if (ext == '9')
1675 ext = '0';
1676 else
1677 ext++;
1678 if ((d = access(new, F_OK)) < 0)
1679 break;
1680 if (ext != '0')
1681 cp--;
1682 else if (*(cp - 2) == '.')
1683 *(cp - 1) = '1';
1684 else {
1685 *(cp - 2) = *(cp - 2) + 1;
1686 cp--;
1687 }
1688 }
1689 return (new);
1690 }
1691
1692 void
1693 abort_remote(din)
1694 FILE *din;
1695 {
1696 char buf[BUFSIZ];
1697 int nfnd;
1698
1699 if (cout == NULL) {
1700 warnx("Lost control connection for abort.");
1701 if (ptabflg)
1702 code = -1;
1703 lostpeer();
1704 return;
1705 }
1706 /*
1707 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1708 * after urgent byte rather than before as is protocol now
1709 */
1710 snprintf(buf, sizeof(buf), "%c%c%c", IAC, IP, IAC);
1711 if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1712 warn("abort");
1713 fprintf(cout, "%cABOR\r\n", DM);
1714 (void)fflush(cout);
1715 if ((nfnd = empty(cin, din, 10)) <= 0) {
1716 if (nfnd < 0) {
1717 warn("abort");
1718 }
1719 if (ptabflg)
1720 code = -1;
1721 lostpeer();
1722 }
1723 if (din && (nfnd & 2)) {
1724 while (read(fileno(din), buf, BUFSIZ) > 0)
1725 continue;
1726 }
1727 if (getreply(0) == ERROR && code == 552) {
1728 /* 552 needed for nic style abort */
1729 (void)getreply(0);
1730 }
1731 (void)getreply(0);
1732 }
1733