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