- Complete re-write of sasc.
[dragonfly.git] / crypto / heimdal / appl / ftp / ftp / ftp.c
1 /*
2  * Copyright (c) 1985, 1989, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "ftp_locl.h"
35 RCSID ("$Id: ftp.c,v 1.74.4.1 2002/10/21 14:26:31 joda Exp $");
36
37 struct sockaddr_storage hisctladdr_ss;
38 struct sockaddr *hisctladdr = (struct sockaddr *)&hisctladdr_ss;
39 struct sockaddr_storage data_addr_ss;
40 struct sockaddr *data_addr  = (struct sockaddr *)&data_addr_ss;
41 struct sockaddr_storage myctladdr_ss;
42 struct sockaddr *myctladdr = (struct sockaddr *)&myctladdr_ss;
43 int data = -1;
44 int abrtflag = 0;
45 jmp_buf ptabort;
46 int ptabflg;
47 int ptflag = 0;
48 off_t restart_point = 0;
49
50
51 FILE *cin, *cout;
52
53 typedef void (*sighand) (int);
54
55 char *
56 hookup (const char *host, int port)
57 {
58     static char hostnamebuf[MaxHostNameLen];
59     struct addrinfo *ai, *a;
60     struct addrinfo hints;
61     int error;
62     char portstr[NI_MAXSERV];
63     socklen_t len;
64     int s;
65
66     memset (&hints, 0, sizeof(hints));
67     hints.ai_socktype = SOCK_STREAM;
68     hints.ai_protocol = IPPROTO_TCP;
69     hints.ai_flags    = AI_CANONNAME;
70
71     snprintf (portstr, sizeof(portstr), "%u", ntohs(port));
72
73     error = getaddrinfo (host, portstr, &hints, &ai);
74     if (error) {
75         warnx ("%s: %s", host, gai_strerror(error));
76         code = -1;
77         return NULL;
78     }
79     strlcpy (hostnamebuf, host, sizeof(hostnamebuf));
80     hostname = hostnamebuf;
81
82     for (a = ai; a != NULL; a = a->ai_next) {
83         s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
84         if (s < 0)
85             continue;
86
87         if (a->ai_canonname != NULL)
88             strlcpy (hostnamebuf, a->ai_canonname, sizeof(hostnamebuf));
89
90         memcpy (hisctladdr, a->ai_addr, a->ai_addrlen);
91         
92         error = connect (s, a->ai_addr, a->ai_addrlen);
93         if (error < 0) {
94             char addrstr[256];
95
96             if (getnameinfo (a->ai_addr, a->ai_addrlen,
97                              addrstr, sizeof(addrstr),
98                              NULL, 0, NI_NUMERICHOST) != 0)
99                 strlcpy (addrstr, "unknown address", sizeof(addrstr));
100                              
101             warn ("connect %s", addrstr);
102             close (s);
103             continue;
104         }
105         break;
106     }
107     freeaddrinfo (ai);
108     if (error < 0) {
109         warnx ("failed to contact %s", host);
110         code = -1;
111         return NULL;
112     }
113
114     len = sizeof(myctladdr_ss);
115     if (getsockname (s, myctladdr, &len) < 0) {
116         warn ("getsockname");
117         code = -1;
118         close (s);
119         return NULL;
120     }
121 #ifdef IPTOS_LOWDELAY
122     socket_set_tos (s, IPTOS_LOWDELAY);
123 #endif
124     cin = fdopen (s, "r");
125     cout = fdopen (s, "w");
126     if (cin == NULL || cout == NULL) {
127         warnx ("fdopen failed.");
128         if (cin)
129             fclose (cin);
130         if (cout)
131             fclose (cout);
132         code = -1;
133         goto bad;
134     }
135     if (verbose)
136         printf ("Connected to %s.\n", hostname);
137     if (getreply (0) > 2) {     /* read startup message from server */
138         if (cin)
139             fclose (cin);
140         if (cout)
141             fclose (cout);
142         code = -1;
143         goto bad;
144     }
145 #if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
146     {
147         int on = 1;
148
149         if (setsockopt (s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof (on))
150             < 0 && debug) {
151             warn ("setsockopt");
152         }
153     }
154 #endif                          /* SO_OOBINLINE */
155
156     return (hostname);
157 bad:
158     close (s);
159     return NULL;
160 }
161
162 int
163 login (char *host)
164 {
165     char tmp[80];
166     char defaultpass[128];
167     char *user, *pass, *acct;
168     int n, aflag = 0;
169
170     char *myname = NULL;
171     struct passwd *pw = k_getpwuid(getuid());
172
173     if (pw != NULL)
174         myname = pw->pw_name;
175
176     user = pass = acct = 0;
177
178     if(sec_login(host))
179         printf("\n*** Using plaintext user and password ***\n\n");
180     else{
181         printf("Authentication successful.\n\n");
182     }
183
184     if (ruserpass (host, &user, &pass, &acct) < 0) {
185         code = -1;
186         return (0);
187     }
188     while (user == NULL) {
189         if (myname)
190             printf ("Name (%s:%s): ", host, myname);
191         else
192             printf ("Name (%s): ", host);
193         *tmp = '\0';
194         if (fgets (tmp, sizeof (tmp) - 1, stdin) != NULL)
195             tmp[strlen (tmp) - 1] = '\0';
196         if (*tmp == '\0')
197             user = myname;
198         else
199             user = tmp;
200     }
201     strlcpy(username, user, sizeof(username));
202     n = command("USER %s", user);
203     if (n == COMPLETE) 
204        n = command("PASS dummy"); /* DK: Compatibility with gssftp daemon */
205     else if(n == CONTINUE) {
206         if (pass == NULL) {
207             char prompt[128];
208             if(myname && 
209                (!strcmp(user, "ftp") || !strcmp(user, "anonymous"))) {
210                 snprintf(defaultpass, sizeof(defaultpass), 
211                          "%s@%s", myname, mydomain);
212                 snprintf(prompt, sizeof(prompt), 
213                          "Password (%s): ", defaultpass);
214             } else if (sec_complete) {
215                 pass = myname;
216             } else {
217                 *defaultpass = '\0';
218                 snprintf(prompt, sizeof(prompt), "Password: ");
219             }
220             if (pass == NULL) {
221                 pass = defaultpass;
222                 des_read_pw_string (tmp, sizeof (tmp), prompt, 0);
223                 if (tmp[0])
224                     pass = tmp;
225             }
226         }
227         n = command ("PASS %s", pass);
228     }
229     if (n == CONTINUE) {
230         aflag++;
231         acct = tmp;
232         des_read_pw_string (acct, 128, "Account:", 0);
233         n = command ("ACCT %s", acct);
234     }
235     if (n != COMPLETE) {
236         warnx ("Login failed.");
237         return (0);
238     }
239     if (!aflag && acct != NULL)
240         command ("ACCT %s", acct);
241     if (proxy)
242         return (1);
243     for (n = 0; n < macnum; ++n) {
244         if (!strcmp("init", macros[n].mac_name)) {
245             strlcpy (line, "$init", sizeof (line));
246             makeargv();
247             domacro(margc, margv);
248             break;
249         }
250     }
251     sec_set_protection_level ();
252     return (1);
253 }
254
255 void
256 cmdabort (int sig)
257 {
258
259     printf ("\n");
260     fflush (stdout);
261     abrtflag++;
262     if (ptflag)
263         longjmp (ptabort, 1);
264 }
265
266 int
267 command (char *fmt,...)
268 {
269     va_list ap;
270     int r;
271     sighand oldintr;
272
273     abrtflag = 0;
274     if (cout == NULL) {
275         warn ("No control connection for command");
276         code = -1;
277         return (0);
278     }
279     oldintr = signal(SIGINT, cmdabort);
280     if(debug){
281         printf("---> ");
282         if (strncmp("PASS ", fmt, 5) == 0)
283             printf("PASS XXXX");
284         else {
285             va_start(ap, fmt);
286             vfprintf(stdout, fmt, ap);
287             va_end(ap);
288         }
289     }
290     va_start(ap, fmt);
291     sec_vfprintf(cout, fmt, ap);
292     va_end(ap);
293     if(debug){
294         printf("\n");
295         fflush(stdout);
296     }
297     fprintf (cout, "\r\n");
298     fflush (cout);
299     cpend = 1;
300     r = getreply (!strcmp (fmt, "QUIT"));
301     if (abrtflag && oldintr != SIG_IGN)
302         (*oldintr) (SIGINT);
303     signal (SIGINT, oldintr);
304     return (r);
305 }
306
307 char reply_string[BUFSIZ];      /* last line of previous reply */
308
309 int
310 getreply (int expecteof)
311 {
312     char *p;
313     char *lead_string;
314     int c;
315     struct sigaction sa, osa;
316     char buf[8192];
317     int reply_code;
318     int long_warn = 0;
319
320     sigemptyset (&sa.sa_mask);
321     sa.sa_flags = 0;
322     sa.sa_handler = cmdabort;
323     sigaction (SIGINT, &sa, &osa);
324
325     p = buf;
326
327     reply_code = 0;
328     while (1) {
329         c = getc (cin);
330         switch (c) {
331         case EOF:
332             if (expecteof) {
333                 sigaction (SIGINT, &osa, NULL);
334                 code = 221;
335                 return 0;
336             }
337             lostpeer (0);
338             if (verbose) {
339                 printf ("421 Service not available, "
340                         "remote server has closed connection\n");
341                 fflush (stdout);
342             }
343             code = 421;
344             return (4);
345         case IAC:
346             c = getc (cin);
347             if (c == WILL || c == WONT)
348                 fprintf (cout, "%c%c%c", IAC, DONT, getc (cin));
349             if (c == DO || c == DONT)
350                 fprintf (cout, "%c%c%c", IAC, WONT, getc (cin));
351             continue;
352         case '\n':
353             *p++ = '\0';
354             if(isdigit(buf[0])){
355                 sscanf(buf, "%d", &code);
356                 if(code == 631){
357                     code = 0;
358                     sec_read_msg(buf, prot_safe);
359                     sscanf(buf, "%d", &code);
360                     lead_string = "S:";
361                 } else if(code == 632){
362                     code = 0;
363                     sec_read_msg(buf, prot_private);
364                     sscanf(buf, "%d", &code);
365                     lead_string = "P:";
366                 }else if(code == 633){
367                     code = 0;
368                     sec_read_msg(buf, prot_confidential);
369                     sscanf(buf, "%d", &code);
370                     lead_string = "C:";
371                 }else if(sec_complete)
372                     lead_string = "!!";
373                 else
374                     lead_string = "";
375                 if(code != 0 && reply_code == 0)
376                     reply_code = code;
377                 if (verbose > 0 || (verbose > -1 && code > 499))
378                     fprintf (stdout, "%s%s\n", lead_string, buf);
379                 if (code == reply_code && buf[3] == ' ') {
380                     strlcpy (reply_string, buf, sizeof(reply_string));
381                     if (code >= 200)
382                         cpend = 0;
383                     sigaction (SIGINT, &osa, NULL);
384                     if (code == 421)
385                         lostpeer (0);
386 #if 1
387                     if (abrtflag &&
388                         osa.sa_handler != cmdabort &&
389                         osa.sa_handler != SIG_IGN)
390                         osa.sa_handler (SIGINT);
391 #endif
392                     if (code == 227 || code == 229) {
393                         char *p;
394
395                         p = strchr (reply_string, '(');
396                         if (p) {
397                             p++;
398                             strlcpy(pasv, p, sizeof(pasv));
399                             p = strrchr(pasv, ')');
400                             if (p)
401                                 *p = '\0';
402                         }
403                     }
404                     return code / 100;
405                 }
406             }else{
407                 if(verbose > 0 || (verbose > -1 && code > 499)){
408                     if(sec_complete)
409                         fprintf(stdout, "!!");
410                     fprintf(stdout, "%s\n", buf);
411                 }
412             }
413             p = buf;
414             long_warn = 0;
415             continue;
416         default:
417             if(p < buf + sizeof(buf) - 1)
418                 *p++ = c; 
419             else if(long_warn == 0) {
420                 fprintf(stderr, "WARNING: incredibly long line received\n");
421                 long_warn = 1;
422             }
423         }
424     }
425
426 }
427
428
429 #if 0
430 int
431 getreply (int expecteof)
432 {
433     int c, n;
434     int dig;
435     int originalcode = 0, continuation = 0;
436     sighand oldintr;
437     int pflag = 0;
438     char *cp, *pt = pasv;
439
440     oldintr = signal (SIGINT, cmdabort);
441     for (;;) {
442         dig = n = code = 0;
443         cp = reply_string;
444         while ((c = getc (cin)) != '\n') {
445             if (c == IAC) {     /* handle telnet commands */
446                 switch (c = getc (cin)) {
447                 case WILL:
448                 case WONT:
449                     c = getc (cin);
450                     fprintf (cout, "%c%c%c", IAC, DONT, c);
451                     fflush (cout);
452                     break;
453                 case DO:
454                 case DONT:
455                     c = getc (cin);
456                     fprintf (cout, "%c%c%c", IAC, WONT, c);
457                     fflush (cout);
458                     break;
459                 default:
460                     break;
461                 }
462                 continue;
463             }
464             dig++;
465             if (c == EOF) {
466                 if (expecteof) {
467                     signal (SIGINT, oldintr);
468                     code = 221;
469                     return (0);
470                 }
471                 lostpeer (0);
472                 if (verbose) {
473                     printf ("421 Service not available, remote server has closed connection\n");
474                     fflush (stdout);
475                 }
476                 code = 421;
477                 return (4);
478             }
479             if (c != '\r' && (verbose > 0 ||
480                               (verbose > -1 && n == '5' && dig > 4))) {
481                 if (proxflag &&
482                     (dig == 1 || dig == 5 && verbose == 0))
483                     printf ("%s:", hostname);
484                 putchar (c);
485             }
486             if (dig < 4 && isdigit (c))
487                 code = code * 10 + (c - '0');
488             if (!pflag && code == 227)
489                 pflag = 1;
490             if (dig > 4 && pflag == 1 && isdigit (c))
491                 pflag = 2;
492             if (pflag == 2) {
493                 if (c != '\r' && c != ')')
494                     *pt++ = c;
495                 else {
496                     *pt = '\0';
497                     pflag = 3;
498                 }
499             }
500             if (dig == 4 && c == '-') {
501                 if (continuation)
502                     code = 0;
503                 continuation++;
504             }
505             if (n == 0)
506                 n = c;
507             if (cp < &reply_string[sizeof (reply_string) - 1])
508                 *cp++ = c;
509         }
510         if (verbose > 0 || verbose > -1 && n == '5') {
511             putchar (c);
512             fflush (stdout);
513         }
514         if (continuation && code != originalcode) {
515             if (originalcode == 0)
516                 originalcode = code;
517             continue;
518         }
519         *cp = '\0';
520         if(sec_complete){
521             if(code == 631)
522                 sec_read_msg(reply_string, prot_safe);
523             else if(code == 632)
524                 sec_read_msg(reply_string, prot_private);
525             else if(code == 633)
526                 sec_read_msg(reply_string, prot_confidential);
527             n = code / 100 + '0';
528         }
529         if (n != '1')
530             cpend = 0;
531         signal (SIGINT, oldintr);
532         if (code == 421 || originalcode == 421)
533             lostpeer (0);
534         if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
535             (*oldintr) (SIGINT);
536         return (n - '0');
537     }
538 }
539
540 #endif
541
542 int
543 empty (fd_set * mask, int sec)
544 {
545     struct timeval t;
546
547     t.tv_sec = sec;
548     t.tv_usec = 0;
549     return (select (FD_SETSIZE, mask, NULL, NULL, &t));
550 }
551
552 jmp_buf sendabort;
553
554 static RETSIGTYPE
555 abortsend (int sig)
556 {
557
558     mflag = 0;
559     abrtflag = 0;
560     printf ("\nsend aborted\nwaiting for remote to finish abort\n");
561     fflush (stdout);
562     longjmp (sendabort, 1);
563 }
564
565 #define HASHBYTES 1024
566
567 static int
568 copy_stream (FILE * from, FILE * to)
569 {
570     static size_t bufsize;
571     static char *buf;
572     int n;
573     int bytes = 0;
574     int werr = 0;
575     int hashbytes = HASHBYTES;
576     struct stat st;
577
578 #if defined(HAVE_MMAP) && !defined(NO_MMAP)
579     void *chunk;
580
581 #ifndef MAP_FAILED
582 #define MAP_FAILED (-1)
583 #endif
584
585     if (fstat (fileno (from), &st) == 0 && S_ISREG (st.st_mode)) {
586         /*
587          * mmap zero bytes has potential of loosing, don't do it.
588          */
589         if (st.st_size == 0)
590             return 0;
591         chunk = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fileno (from), 0);
592         if (chunk != (void *) MAP_FAILED) {
593             int res;
594
595             res = sec_write (fileno (to), chunk, st.st_size);
596             if (munmap (chunk, st.st_size) < 0)
597                 warn ("munmap");
598             sec_fflush (to);
599             return res;
600         }
601     }
602 #endif
603
604     buf = alloc_buffer (buf, &bufsize,
605                         fstat (fileno (from), &st) >= 0 ? &st : NULL);
606     if (buf == NULL)
607         return -1;
608
609     while ((n = read (fileno (from), buf, bufsize)) > 0) {
610         werr = sec_write (fileno (to), buf, n);
611         if (werr < 0)
612             break;
613         bytes += werr;
614         while (hash && bytes > hashbytes) {
615             putchar ('#');
616             hashbytes += HASHBYTES;
617         }
618     }
619     sec_fflush (to);
620     if (n < 0)
621         warn ("local");
622
623     if (werr < 0) {
624         if (errno != EPIPE)
625             warn ("netout");
626         bytes = -1;
627     }
628     return bytes;
629 }
630
631 void
632 sendrequest (char *cmd, char *local, char *remote, char *lmode, int printnames)
633 {
634     struct stat st;
635     struct timeval start, stop;
636     int c, d;
637     FILE *fin, *dout = 0;
638     int (*closefunc) (FILE *);
639     RETSIGTYPE (*oldintr)(int), (*oldintp)(int);
640     long bytes = 0, hashbytes = HASHBYTES;
641     char *rmode = "w";
642
643     if (verbose && printnames) {
644         if (local && strcmp (local, "-") != 0)
645             printf ("local: %s ", local);
646         if (remote)
647             printf ("remote: %s\n", remote);
648     }
649     if (proxy) {
650         proxtrans (cmd, local, remote);
651         return;
652     }
653     if (curtype != type)
654         changetype (type, 0);
655     closefunc = NULL;
656     oldintr = NULL;
657     oldintp = NULL;
658
659     if (setjmp (sendabort)) {
660         while (cpend) {
661             getreply (0);
662         }
663         if (data >= 0) {
664             close (data);
665             data = -1;
666         }
667         if (oldintr)
668             signal (SIGINT, oldintr);
669         if (oldintp)
670             signal (SIGPIPE, oldintp);
671         code = -1;
672         return;
673     }
674     oldintr = signal (SIGINT, abortsend);
675     if (strcmp (local, "-") == 0)
676         fin = stdin;
677     else if (*local == '|') {
678         oldintp = signal (SIGPIPE, SIG_IGN);
679         fin = popen (local + 1, lmode);
680         if (fin == NULL) {
681             warn ("%s", local + 1);
682             signal (SIGINT, oldintr);
683             signal (SIGPIPE, oldintp);
684             code = -1;
685             return;
686         }
687         closefunc = pclose;
688     } else {
689         fin = fopen (local, lmode);
690         if (fin == NULL) {
691             warn ("local: %s", local);
692             signal (SIGINT, oldintr);
693             code = -1;
694             return;
695         }
696         closefunc = fclose;
697         if (fstat (fileno (fin), &st) < 0 ||
698             (st.st_mode & S_IFMT) != S_IFREG) {
699             fprintf (stdout, "%s: not a plain file.\n", local);
700             signal (SIGINT, oldintr);
701             fclose (fin);
702             code = -1;
703             return;
704         }
705     }
706     if (initconn ()) {
707         signal (SIGINT, oldintr);
708         if (oldintp)
709             signal (SIGPIPE, oldintp);
710         code = -1;
711         if (closefunc != NULL)
712             (*closefunc) (fin);
713         return;
714     }
715     if (setjmp (sendabort))
716         goto abort;
717
718     if (restart_point &&
719         (strcmp (cmd, "STOR") == 0 || strcmp (cmd, "APPE") == 0)) {
720         int rc;
721
722         switch (curtype) {
723         case TYPE_A:
724             rc = fseek (fin, (long) restart_point, SEEK_SET);
725             break;
726         case TYPE_I:
727         case TYPE_L:
728             rc = lseek (fileno (fin), restart_point, SEEK_SET);
729             break;
730         }
731         if (rc < 0) {
732             warn ("local: %s", local);
733             restart_point = 0;
734             if (closefunc != NULL)
735                 (*closefunc) (fin);
736             return;
737         }
738         if (command ("REST %ld", (long) restart_point)
739             != CONTINUE) {
740             restart_point = 0;
741             if (closefunc != NULL)
742                 (*closefunc) (fin);
743             return;
744         }
745         restart_point = 0;
746         rmode = "r+w";
747     }
748     if (remote) {
749         if (command ("%s %s", cmd, remote) != PRELIM) {
750             signal (SIGINT, oldintr);
751             if (oldintp)
752                 signal (SIGPIPE, oldintp);
753             if (closefunc != NULL)
754                 (*closefunc) (fin);
755             return;
756         }
757     } else if (command ("%s", cmd) != PRELIM) {
758             signal(SIGINT, oldintr);
759             if (oldintp)
760                 signal(SIGPIPE, oldintp);
761             if (closefunc != NULL)
762                 (*closefunc)(fin);
763             return;
764         }
765     dout = dataconn(rmode);
766     if (dout == NULL)
767         goto abort;
768     set_buffer_size (fileno (dout), 0);
769     gettimeofday (&start, (struct timezone *) 0);
770     oldintp = signal (SIGPIPE, SIG_IGN);
771     switch (curtype) {
772
773     case TYPE_I:
774     case TYPE_L:
775         errno = d = c = 0;
776         bytes = copy_stream (fin, dout);
777         break;
778
779     case TYPE_A:
780         while ((c = getc (fin)) != EOF) {
781             if (c == '\n') {
782                 while (hash && (bytes >= hashbytes)) {
783                     putchar ('#');
784                     fflush (stdout);
785                     hashbytes += HASHBYTES;
786                 }
787                 if (ferror (dout))
788                     break;
789                 sec_putc ('\r', dout);
790                 bytes++;
791             }
792             sec_putc (c, dout);
793             bytes++;
794         }
795         sec_fflush (dout);
796         if (hash) {
797             if (bytes < hashbytes)
798                 putchar ('#');
799             putchar ('\n');
800             fflush (stdout);
801         }
802         if (ferror (fin))
803             warn ("local: %s", local);
804         if (ferror (dout)) {
805             if (errno != EPIPE)
806                 warn ("netout");
807             bytes = -1;
808         }
809         break;
810     }
811     if (closefunc != NULL)
812         (*closefunc) (fin);
813     fclose (dout);
814     gettimeofday (&stop, (struct timezone *) 0);
815     getreply (0);
816     signal (SIGINT, oldintr);
817     if (oldintp)
818         signal (SIGPIPE, oldintp);
819     if (bytes > 0)
820         ptransfer ("sent", bytes, &start, &stop);
821     return;
822 abort:
823     signal (SIGINT, oldintr);
824     if (oldintp)
825         signal (SIGPIPE, oldintp);
826     if (!cpend) {
827         code = -1;
828         return;
829     }
830     if (data >= 0) {
831         close (data);
832         data = -1;
833     }
834     if (dout)
835         fclose (dout);
836     getreply (0);
837     code = -1;
838     if (closefunc != NULL && fin != NULL)
839         (*closefunc) (fin);
840     gettimeofday (&stop, (struct timezone *) 0);
841     if (bytes > 0)
842         ptransfer ("sent", bytes, &start, &stop);
843 }
844
845 jmp_buf recvabort;
846
847 void
848 abortrecv (int sig)
849 {
850
851     mflag = 0;
852     abrtflag = 0;
853     printf ("\nreceive aborted\nwaiting for remote to finish abort\n");
854     fflush (stdout);
855     longjmp (recvabort, 1);
856 }
857
858 void
859 recvrequest (char *cmd, char *local, char *remote,
860              char *lmode, int printnames, int local_given)
861 {
862     FILE *fout, *din = 0;
863     int (*closefunc) (FILE *);
864     sighand oldintr, oldintp;
865     int c, d, is_retr, tcrflag, bare_lfs = 0;
866     static size_t bufsize;
867     static char *buf;
868     long bytes = 0, hashbytes = HASHBYTES;
869     struct timeval start, stop;
870     struct stat st;
871
872     is_retr = strcmp (cmd, "RETR") == 0;
873     if (is_retr && verbose && printnames) {
874         if (local && strcmp (local, "-") != 0)
875             printf ("local: %s ", local);
876         if (remote)
877             printf ("remote: %s\n", remote);
878     }
879     if (proxy && is_retr) {
880         proxtrans (cmd, local, remote);
881         return;
882     }
883     closefunc = NULL;
884     oldintr = NULL;
885     oldintp = NULL;
886     tcrflag = !crflag && is_retr;
887     if (setjmp (recvabort)) {
888         while (cpend) {
889             getreply (0);
890         }
891         if (data >= 0) {
892             close (data);
893             data = -1;
894         }
895         if (oldintr)
896             signal (SIGINT, oldintr);
897         code = -1;
898         return;
899     }
900     oldintr = signal (SIGINT, abortrecv);
901     if (!local_given || (strcmp (local, "-") && *local != '|')) {
902         if (access (local, 2) < 0) {
903             char *dir = strrchr (local, '/');
904
905             if (errno != ENOENT && errno != EACCES) {
906                 warn ("local: %s", local);
907                 signal (SIGINT, oldintr);
908                 code = -1;
909                 return;
910             }
911             if (dir != NULL)
912                 *dir = 0;
913             d = access (dir ? local : ".", 2);
914             if (dir != NULL)
915                 *dir = '/';
916             if (d < 0) {
917                 warn ("local: %s", local);
918                 signal (SIGINT, oldintr);
919                 code = -1;
920                 return;
921             }
922             if (!runique && errno == EACCES &&
923                 chmod (local, 0600) < 0) {
924                 warn ("local: %s", local);
925                 signal (SIGINT, oldintr);
926                 signal (SIGINT, oldintr);
927                 code = -1;
928                 return;
929             }
930             if (runique && errno == EACCES &&
931                 (local = gunique (local)) == NULL) {
932                 signal (SIGINT, oldintr);
933                 code = -1;
934                 return;
935             }
936         } else if (runique && (local = gunique (local)) == NULL) {
937             signal(SIGINT, oldintr);
938             code = -1;
939             return;
940         }
941     }
942     if (!is_retr) {
943         if (curtype != TYPE_A)
944             changetype (TYPE_A, 0);
945     } else if (curtype != type)
946         changetype (type, 0);
947     if (initconn ()) {
948         signal (SIGINT, oldintr);
949         code = -1;
950         return;
951     }
952     if (setjmp (recvabort))
953         goto abort;
954     if (is_retr && restart_point &&
955         command ("REST %ld", (long) restart_point) != CONTINUE)
956         return;
957     if (remote) {
958         if (command ("%s %s", cmd, remote) != PRELIM) {
959             signal (SIGINT, oldintr);
960             return;
961         }
962     } else {
963         if (command ("%s", cmd) != PRELIM) {
964             signal (SIGINT, oldintr);
965             return;
966         }
967     }
968     din = dataconn ("r");
969     if (din == NULL)
970         goto abort;
971     set_buffer_size (fileno (din), 1);
972     if (local_given && strcmp (local, "-") == 0)
973         fout = stdout;
974     else if (local_given && *local == '|') {
975         oldintp = signal (SIGPIPE, SIG_IGN);
976         fout = popen (local + 1, "w");
977         if (fout == NULL) {
978             warn ("%s", local + 1);
979             goto abort;
980         }
981         closefunc = pclose;
982     } else {
983         fout = fopen (local, lmode);
984         if (fout == NULL) {
985             warn ("local: %s", local);
986             goto abort;
987         }
988         closefunc = fclose;
989     }
990     buf = alloc_buffer (buf, &bufsize,
991                         fstat (fileno (fout), &st) >= 0 ? &st : NULL);
992     if (buf == NULL)
993         goto abort;
994
995     gettimeofday (&start, (struct timezone *) 0);
996     switch (curtype) {
997
998     case TYPE_I:
999     case TYPE_L:
1000         if (restart_point &&
1001             lseek (fileno (fout), restart_point, SEEK_SET) < 0) {
1002             warn ("local: %s", local);
1003             if (closefunc != NULL)
1004                 (*closefunc) (fout);
1005             return;
1006         }
1007         errno = d = 0;
1008         while ((c = sec_read (fileno (din), buf, bufsize)) > 0) {
1009             if ((d = write (fileno (fout), buf, c)) != c)
1010                 break;
1011             bytes += c;
1012             if (hash) {
1013                 while (bytes >= hashbytes) {
1014                     putchar ('#');
1015                     hashbytes += HASHBYTES;
1016                 }
1017                 fflush (stdout);
1018             }
1019         }
1020         if (hash && bytes > 0) {
1021             if (bytes < HASHBYTES)
1022                 putchar ('#');
1023             putchar ('\n');
1024             fflush (stdout);
1025         }
1026         if (c < 0) {
1027             if (errno != EPIPE)
1028                 warn ("netin");
1029             bytes = -1;
1030         }
1031         if (d < c) {
1032             if (d < 0)
1033                 warn ("local: %s", local);
1034             else
1035                 warnx ("%s: short write", local);
1036         }
1037         break;
1038
1039     case TYPE_A:
1040         if (restart_point) {
1041             int i, n, ch;
1042
1043             if (fseek (fout, 0L, SEEK_SET) < 0)
1044                 goto done;
1045             n = restart_point;
1046             for (i = 0; i++ < n;) {
1047                 if ((ch = sec_getc (fout)) == EOF)
1048                     goto done;
1049                 if (ch == '\n')
1050                     i++;
1051             }
1052             if (fseek (fout, 0L, SEEK_CUR) < 0) {
1053         done:
1054                 warn ("local: %s", local);
1055                 if (closefunc != NULL)
1056                     (*closefunc) (fout);
1057                 return;
1058             }
1059         }
1060         while ((c = sec_getc(din)) != EOF) {
1061             if (c == '\n')
1062                 bare_lfs++;
1063             while (c == '\r') {
1064                 while (hash && (bytes >= hashbytes)) {
1065                     putchar ('#');
1066                     fflush (stdout);
1067                     hashbytes += HASHBYTES;
1068                 }
1069                 bytes++;
1070                 if ((c = sec_getc (din)) != '\n' || tcrflag) {
1071                     if (ferror (fout))
1072                         goto break2;
1073                     putc ('\r', fout);
1074                     if (c == '\0') {
1075                         bytes++;
1076                         goto contin2;
1077                     }
1078                     if (c == EOF)
1079                         goto contin2;
1080                 }
1081             }
1082             putc (c, fout);
1083             bytes++;
1084     contin2:;
1085         }
1086 break2:
1087         if (bare_lfs) {
1088             printf ("WARNING! %d bare linefeeds received in ASCII mode\n",
1089                     bare_lfs);
1090             printf ("File may not have transferred correctly.\n");
1091         }
1092         if (hash) {
1093             if (bytes < hashbytes)
1094                 putchar ('#');
1095             putchar ('\n');
1096             fflush (stdout);
1097         }
1098         if (ferror (din)) {
1099             if (errno != EPIPE)
1100                 warn ("netin");
1101             bytes = -1;
1102         }
1103         if (ferror (fout))
1104             warn ("local: %s", local);
1105         break;
1106     }
1107     if (closefunc != NULL)
1108         (*closefunc) (fout);
1109     signal (SIGINT, oldintr);
1110     if (oldintp)
1111         signal (SIGPIPE, oldintp);
1112     fclose (din);
1113     gettimeofday (&stop, (struct timezone *) 0);
1114     getreply (0);
1115     if (bytes > 0 && is_retr)
1116         ptransfer ("received", bytes, &start, &stop);
1117     return;
1118 abort:
1119
1120     /* abort using RFC959 recommended IP,SYNC sequence  */
1121
1122     if (oldintp)
1123         signal (SIGPIPE, oldintr);
1124     signal (SIGINT, SIG_IGN);
1125     if (!cpend) {
1126         code = -1;
1127         signal (SIGINT, oldintr);
1128         return;
1129     }
1130     abort_remote(din);
1131     code = -1;
1132     if (data >= 0) {
1133         close (data);
1134         data = -1;
1135     }
1136     if (closefunc != NULL && fout != NULL)
1137         (*closefunc) (fout);
1138     if (din)
1139         fclose (din);
1140     gettimeofday (&stop, (struct timezone *) 0);
1141     if (bytes > 0)
1142         ptransfer ("received", bytes, &start, &stop);
1143     signal (SIGINT, oldintr);
1144 }
1145
1146 static int
1147 parse_epsv (const char *str)
1148 {
1149     char sep;
1150     char *end;
1151     int port;
1152
1153     if (*str == '\0')
1154         return -1;
1155     sep = *str++;
1156     if (sep != *str++)
1157         return -1;
1158     if (sep != *str++)
1159         return -1;
1160     port = strtol (str, &end, 0);
1161     if (str == end)
1162         return -1;
1163     if (end[0] != sep || end[1] != '\0')
1164         return -1;
1165     return htons(port);
1166 }
1167
1168 static int
1169 parse_pasv (struct sockaddr_in *sin, const char *str)
1170 {
1171     int a0, a1, a2, a3, p0, p1;
1172
1173     /*
1174      * What we've got at this point is a string of comma separated
1175      * one-byte unsigned integer values. The first four are the an IP
1176      * address. The fifth is the MSB of the port number, the sixth is the
1177      * LSB. From that we'll prepare a sockaddr_in.
1178      */
1179
1180     if (sscanf (str, "%d,%d,%d,%d,%d,%d",
1181                 &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
1182         printf ("Passive mode address scan failure. "
1183                 "Shouldn't happen!\n");
1184         return -1;
1185     }
1186     if (a0 < 0 || a0 > 255 ||
1187         a1 < 0 || a1 > 255 ||
1188         a2 < 0 || a2 > 255 ||
1189         a3 < 0 || a3 > 255 ||
1190         p0 < 0 || p0 > 255 ||
1191         p1 < 0 || p1 > 255) {
1192         printf ("Can't parse passive mode string.\n");
1193         return -1;
1194     }
1195     memset (sin, 0, sizeof(*sin));
1196     sin->sin_family      = AF_INET;
1197     sin->sin_addr.s_addr = htonl ((a0 << 24) | (a1 << 16) |
1198                                   (a2 << 8) | a3);
1199     sin->sin_port = htons ((p0 << 8) | p1);
1200     return 0;
1201 }
1202
1203 static int
1204 passive_mode (void)
1205 {
1206     int port;
1207
1208     data = socket (myctladdr->sa_family, SOCK_STREAM, 0);
1209     if (data < 0) {
1210         warn ("socket");
1211         return (1);
1212     }
1213     if (options & SO_DEBUG)
1214         socket_set_debug (data);
1215     if (command ("EPSV") != COMPLETE) {
1216         if (command ("PASV") != COMPLETE) {
1217             printf ("Passive mode refused.\n");
1218             goto bad;
1219         }
1220     }
1221
1222     /*
1223      * Parse the reply to EPSV or PASV
1224      */
1225
1226     port = parse_epsv (pasv);
1227     if (port > 0) {
1228         data_addr->sa_family = myctladdr->sa_family;
1229         socket_set_address_and_port (data_addr,
1230                                      socket_get_address (hisctladdr),
1231                                      port);
1232     } else {
1233         if (parse_pasv ((struct sockaddr_in *)data_addr, pasv) < 0)
1234             goto bad;
1235     }
1236
1237     if (connect (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
1238         warn ("connect");
1239         goto bad;
1240     }
1241 #ifdef IPTOS_THROUGHPUT
1242     socket_set_tos (data, IPTOS_THROUGHPUT);
1243 #endif
1244     return (0);
1245 bad:
1246     close (data);
1247     data = -1;
1248     sendport = 1;
1249     return (1);
1250 }
1251
1252
1253 static int
1254 active_mode (void)
1255 {
1256     int tmpno = 0;
1257     socklen_t len;
1258     int result;
1259
1260 noport:
1261     data_addr->sa_family = myctladdr->sa_family;
1262     socket_set_address_and_port (data_addr, socket_get_address (myctladdr),
1263                                  sendport ? 0 : socket_get_port (myctladdr));
1264
1265     if (data != -1)
1266         close (data);
1267     data = socket (data_addr->sa_family, SOCK_STREAM, 0);
1268     if (data < 0) {
1269         warn ("socket");
1270         if (tmpno)
1271             sendport = 1;
1272         return (1);
1273     }
1274     if (!sendport)
1275         socket_set_reuseaddr (data, 1);
1276     if (bind (data, data_addr, socket_sockaddr_size (data_addr)) < 0) {
1277         warn ("bind");
1278         goto bad;
1279     }
1280     if (options & SO_DEBUG)
1281         socket_set_debug (data);
1282     len = sizeof (data_addr_ss);
1283     if (getsockname (data, data_addr, &len) < 0) {
1284         warn ("getsockname");
1285         goto bad;
1286     }
1287     if (listen (data, 1) < 0)
1288         warn ("listen");
1289     if (sendport) {
1290         char addr_str[256];
1291         int inet_af;
1292         int overbose;
1293
1294         if (inet_ntop (data_addr->sa_family, socket_get_address (data_addr),
1295                        addr_str, sizeof(addr_str)) == NULL)
1296             errx (1, "inet_ntop failed");
1297         switch (data_addr->sa_family) {
1298         case AF_INET :
1299             inet_af = 1;
1300             break;
1301 #ifdef HAVE_IPV6
1302         case AF_INET6 :
1303             inet_af = 2;
1304             break;
1305 #endif
1306         default :
1307             errx (1, "bad address family %d", data_addr->sa_family);
1308         }
1309
1310
1311         overbose = verbose;
1312         if (debug == 0)
1313             verbose  = -1;
1314
1315         result = command ("EPRT |%d|%s|%d|",
1316                           inet_af, addr_str, 
1317                           ntohs(socket_get_port (data_addr)));
1318         verbose = overbose;
1319
1320         if (result == ERROR) {
1321             struct sockaddr_in *sin = (struct sockaddr_in *)data_addr;
1322
1323             unsigned int a = ntohl(sin->sin_addr.s_addr);
1324             unsigned int p = ntohs(sin->sin_port);
1325
1326             if (data_addr->sa_family != AF_INET) {
1327                 warnx ("remote server doesn't support EPRT");
1328                 goto bad;
1329             }
1330
1331             result = command("PORT %d,%d,%d,%d,%d,%d", 
1332                              (a >> 24) & 0xff,
1333                              (a >> 16) & 0xff,
1334                              (a >> 8) & 0xff,
1335                              a & 0xff,
1336                              (p >> 8) & 0xff,
1337                              p & 0xff);
1338             if (result == ERROR && sendport == -1) {
1339                 sendport = 0;
1340                 tmpno = 1;
1341                 goto noport;
1342             }
1343             return (result != COMPLETE);
1344         }
1345         return result != COMPLETE;
1346     }
1347     if (tmpno)
1348         sendport = 1;
1349
1350
1351 #ifdef IPTOS_THROUGHPUT
1352     socket_set_tos (data, IPTOS_THROUGHPUT);
1353 #endif
1354     return (0);
1355 bad:
1356     close (data);
1357     data = -1;
1358     if (tmpno)
1359         sendport = 1;
1360     return (1);
1361 }
1362
1363 /*
1364  * Need to start a listen on the data channel before we send the command,
1365  * otherwise the server's connect may fail.
1366  */
1367 int
1368 initconn (void)
1369 {
1370     if (passivemode) 
1371         return passive_mode ();
1372     else
1373         return active_mode ();
1374 }
1375
1376 FILE *
1377 dataconn (const char *lmode)
1378 {
1379     struct sockaddr_storage from_ss;
1380     struct sockaddr *from = (struct sockaddr *)&from_ss;
1381     socklen_t fromlen = sizeof(from_ss);
1382     int s;
1383
1384     if (passivemode)
1385         return (fdopen (data, lmode));
1386
1387     s = accept (data, from, &fromlen);
1388     if (s < 0) {
1389         warn ("accept");
1390         close (data), data = -1;
1391         return (NULL);
1392     }
1393     close (data);
1394     data = s;
1395 #ifdef IPTOS_THROUGHPUT
1396     socket_set_tos (s, IPTOS_THROUGHPUT);
1397 #endif
1398     return (fdopen (data, lmode));
1399 }
1400
1401 void
1402 ptransfer (char *direction, long int bytes,
1403            struct timeval * t0, struct timeval * t1)
1404 {
1405     struct timeval td;
1406     float s;
1407     float bs;
1408     int prec;
1409     char *unit;
1410
1411     if (verbose) {
1412         td.tv_sec = t1->tv_sec - t0->tv_sec;
1413         td.tv_usec = t1->tv_usec - t0->tv_usec;
1414         if (td.tv_usec < 0) {
1415             td.tv_sec--;
1416             td.tv_usec += 1000000;
1417         }
1418         s = td.tv_sec + (td.tv_usec / 1000000.);
1419         bs = bytes / (s ? s : 1);
1420         if (bs >= 1048576) {
1421             bs /= 1048576;
1422             unit = "M";
1423             prec = 2;
1424         } else if (bs >= 1024) {
1425             bs /= 1024;
1426             unit = "k";
1427             prec = 1;
1428         } else {
1429             unit = "";
1430             prec = 0;
1431         }
1432
1433         printf ("%ld bytes %s in %.3g seconds (%.*f %sbyte/s)\n",
1434                 bytes, direction, s, prec, bs, unit);
1435     }
1436 }
1437
1438 void
1439 psabort (int sig)
1440 {
1441
1442     abrtflag++;
1443 }
1444
1445 void
1446 pswitch (int flag)
1447 {
1448     sighand oldintr;
1449     static struct comvars {
1450         int connect;
1451         char name[MaxHostNameLen];
1452         struct sockaddr_storage mctl;
1453         struct sockaddr_storage hctl;
1454         FILE *in;
1455         FILE *out;
1456         int tpe;
1457         int curtpe;
1458         int cpnd;
1459         int sunqe;
1460         int runqe;
1461         int mcse;
1462         int ntflg;
1463         char nti[17];
1464         char nto[17];
1465         int mapflg;
1466         char mi[MaxPathLen];
1467         char mo[MaxPathLen];
1468     } proxstruct, tmpstruct;
1469     struct comvars *ip, *op;
1470
1471     abrtflag = 0;
1472     oldintr = signal (SIGINT, psabort);
1473     if (flag) {
1474         if (proxy)
1475             return;
1476         ip = &tmpstruct;
1477         op = &proxstruct;
1478         proxy++;
1479     } else {
1480         if (!proxy)
1481             return;
1482         ip = &proxstruct;
1483         op = &tmpstruct;
1484         proxy = 0;
1485     }
1486     ip->connect = connected;
1487     connected = op->connect;
1488     if (hostname) {
1489         strlcpy (ip->name, hostname, sizeof (ip->name));
1490     } else
1491         ip->name[0] = 0;
1492     hostname = op->name;
1493     ip->hctl = hisctladdr_ss;
1494     hisctladdr_ss = op->hctl;
1495     ip->mctl = myctladdr_ss;
1496     myctladdr_ss = op->mctl;
1497     ip->in = cin;
1498     cin = op->in;
1499     ip->out = cout;
1500     cout = op->out;
1501     ip->tpe = type;
1502     type = op->tpe;
1503     ip->curtpe = curtype;
1504     curtype = op->curtpe;
1505     ip->cpnd = cpend;
1506     cpend = op->cpnd;
1507     ip->sunqe = sunique;
1508     sunique = op->sunqe;
1509     ip->runqe = runique;
1510     runique = op->runqe;
1511     ip->mcse = mcase;
1512     mcase = op->mcse;
1513     ip->ntflg = ntflag;
1514     ntflag = op->ntflg;
1515     strlcpy (ip->nti, ntin, sizeof (ip->nti));
1516     strlcpy (ntin, op->nti, 17);
1517     strlcpy (ip->nto, ntout, sizeof (ip->nto));
1518     strlcpy (ntout, op->nto, 17);
1519     ip->mapflg = mapflag;
1520     mapflag = op->mapflg;
1521     strlcpy (ip->mi, mapin, MaxPathLen);
1522     strlcpy (mapin, op->mi, MaxPathLen);
1523     strlcpy (ip->mo, mapout, MaxPathLen);
1524     strlcpy (mapout, op->mo, MaxPathLen);
1525     signal(SIGINT, oldintr);
1526     if (abrtflag) {
1527         abrtflag = 0;
1528         (*oldintr) (SIGINT);
1529     }
1530 }
1531
1532 void
1533 abortpt (int sig)
1534 {
1535
1536     printf ("\n");
1537     fflush (stdout);
1538     ptabflg++;
1539     mflag = 0;
1540     abrtflag = 0;
1541     longjmp (ptabort, 1);
1542 }
1543
1544 void
1545 proxtrans (char *cmd, char *local, char *remote)
1546 {
1547     sighand oldintr;
1548     int secndflag = 0, prox_type, nfnd;
1549     char *cmd2;
1550     fd_set mask;
1551
1552     if (strcmp (cmd, "RETR"))
1553         cmd2 = "RETR";
1554     else
1555         cmd2 = runique ? "STOU" : "STOR";
1556     if ((prox_type = type) == 0) {
1557         if (unix_server && unix_proxy)
1558             prox_type = TYPE_I;
1559         else
1560             prox_type = TYPE_A;
1561     }
1562     if (curtype != prox_type)
1563         changetype (prox_type, 1);
1564     if (command ("PASV") != COMPLETE) {
1565         printf ("proxy server does not support third party transfers.\n");
1566         return;
1567     }
1568     pswitch (0);
1569     if (!connected) {
1570         printf ("No primary connection\n");
1571         pswitch (1);
1572         code = -1;
1573         return;
1574     }
1575     if (curtype != prox_type)
1576         changetype (prox_type, 1);
1577     if (command ("PORT %s", pasv) != COMPLETE) {
1578         pswitch (1);
1579         return;
1580     }
1581     if (setjmp (ptabort))
1582         goto abort;
1583     oldintr = signal (SIGINT, abortpt);
1584     if (command ("%s %s", cmd, remote) != PRELIM) {
1585         signal (SIGINT, oldintr);
1586         pswitch (1);
1587         return;
1588     }
1589     sleep (2);
1590     pswitch (1);
1591     secndflag++;
1592     if (command ("%s %s", cmd2, local) != PRELIM)
1593         goto abort;
1594     ptflag++;
1595     getreply (0);
1596     pswitch (0);
1597     getreply (0);
1598     signal (SIGINT, oldintr);
1599     pswitch (1);
1600     ptflag = 0;
1601     printf ("local: %s remote: %s\n", local, remote);
1602     return;
1603 abort:
1604     signal (SIGINT, SIG_IGN);
1605     ptflag = 0;
1606     if (strcmp (cmd, "RETR") && !proxy)
1607         pswitch (1);
1608     else if (!strcmp (cmd, "RETR") && proxy)
1609         pswitch (0);
1610     if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1611         if (command ("%s %s", cmd2, local) != PRELIM) {
1612             pswitch (0);
1613             if (cpend)
1614                 abort_remote ((FILE *) NULL);
1615         }
1616         pswitch (1);
1617         if (ptabflg)
1618             code = -1;
1619         signal (SIGINT, oldintr);
1620         return;
1621     }
1622     if (cpend)
1623         abort_remote ((FILE *) NULL);
1624     pswitch (!proxy);
1625     if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
1626         if (command ("%s %s", cmd2, local) != PRELIM) {
1627             pswitch (0);
1628             if (cpend)
1629                 abort_remote ((FILE *) NULL);
1630             pswitch (1);
1631             if (ptabflg)
1632                 code = -1;
1633             signal (SIGINT, oldintr);
1634             return;
1635         }
1636     }
1637     if (cpend)
1638         abort_remote ((FILE *) NULL);
1639     pswitch (!proxy);
1640     if (cpend) {
1641         FD_ZERO (&mask);
1642         if (fileno(cin) >= FD_SETSIZE)
1643             errx (1, "fd too large");
1644         FD_SET (fileno (cin), &mask);
1645         if ((nfnd = empty (&mask, 10)) <= 0) {
1646             if (nfnd < 0) {
1647                 warn ("abort");
1648             }
1649             if (ptabflg)
1650                 code = -1;
1651             lostpeer (0);
1652         }
1653         getreply (0);
1654         getreply (0);
1655     }
1656     if (proxy)
1657         pswitch (0);
1658     pswitch (1);
1659     if (ptabflg)
1660         code = -1;
1661     signal (SIGINT, oldintr);
1662 }
1663
1664 void
1665 reset (int argc, char **argv)
1666 {
1667     fd_set mask;
1668     int nfnd = 1;
1669
1670     FD_ZERO (&mask);
1671     while (nfnd > 0) {
1672         if (fileno (cin) >= FD_SETSIZE)
1673             errx (1, "fd too large");
1674         FD_SET (fileno (cin), &mask);
1675         if ((nfnd = empty (&mask, 0)) < 0) {
1676             warn ("reset");
1677             code = -1;
1678             lostpeer(0);
1679         } else if (nfnd) {
1680             getreply(0);
1681         }
1682     }
1683 }
1684
1685 char *
1686 gunique (char *local)
1687 {
1688     static char new[MaxPathLen];
1689     char *cp = strrchr (local, '/');
1690     int d, count = 0;
1691     char ext = '1';
1692
1693     if (cp)
1694         *cp = '\0';
1695     d = access (cp ? local : ".", 2);
1696     if (cp)
1697         *cp = '/';
1698     if (d < 0) {
1699         warn ("local: %s", local);
1700         return NULL;
1701     }
1702     strlcpy (new, local, sizeof(new));
1703     cp = new + strlen(new);
1704     *cp++ = '.';
1705     while (!d) {
1706         if (++count == 100) {
1707             printf ("runique: can't find unique file name.\n");
1708             return NULL;
1709         }
1710         *cp++ = ext;
1711         *cp = '\0';
1712         if (ext == '9')
1713             ext = '0';
1714         else
1715             ext++;
1716         if ((d = access (new, 0)) < 0)
1717             break;
1718         if (ext != '0')
1719             cp--;
1720         else if (*(cp - 2) == '.')
1721             *(cp - 1) = '1';
1722         else {
1723             *(cp - 2) = *(cp - 2) + 1;
1724             cp--;
1725         }
1726     }
1727     return (new);
1728 }
1729
1730 void
1731 abort_remote (FILE * din)
1732 {
1733     char buf[BUFSIZ];
1734     int nfnd;
1735     fd_set mask;
1736
1737     /*
1738      * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1739      * after urgent byte rather than before as is protocol now
1740      */
1741     snprintf (buf, sizeof (buf), "%c%c%c", IAC, IP, IAC);
1742     if (send (fileno (cout), buf, 3, MSG_OOB) != 3)
1743         warn ("abort");
1744     fprintf (cout, "%cABOR\r\n", DM);
1745     fflush (cout);
1746     FD_ZERO (&mask);
1747     if (fileno (cin) >= FD_SETSIZE)
1748         errx (1, "fd too large");
1749     FD_SET (fileno (cin), &mask);
1750     if (din) {
1751     if (fileno (din) >= FD_SETSIZE)
1752         errx (1, "fd too large");
1753         FD_SET (fileno (din), &mask);
1754     }
1755     if ((nfnd = empty (&mask, 10)) <= 0) {
1756         if (nfnd < 0) {
1757             warn ("abort");
1758         }
1759         if (ptabflg)
1760             code = -1;
1761         lostpeer (0);
1762     }
1763     if (din && FD_ISSET (fileno (din), &mask)) {
1764         while (read (fileno (din), buf, BUFSIZ) > 0)
1765              /* LOOP */ ;
1766     }
1767     if (getreply (0) == ERROR && code == 552) {
1768         /* 552 needed for nic style abort */
1769         getreply (0);
1770     }
1771     getreply (0);
1772 }