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