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