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