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