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