121739Sdist /* 236942Skarels * Copyright (c) 1985, 1989 Regents of the University of California. 333737Sbostic * All rights reserved. 433737Sbostic * 533737Sbostic * Redistribution and use in source and binary forms are permitted 634901Sbostic * provided that the above copyright notice and this paragraph are 734901Sbostic * duplicated in all such forms and that any documentation, 834901Sbostic * advertising materials, and other materials related to such 934901Sbostic * distribution and use acknowledge that the software was developed 1034901Sbostic * by the University of California, Berkeley. The name of the 1134901Sbostic * University may not be used to endorse or promote products derived 1234901Sbostic * from this software without specific prior written permission. 1334901Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434901Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1536935Skarels * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621739Sdist */ 1721739Sdist 1810296Ssam #ifndef lint 19*37229Skarels static char sccsid[] = "@(#)ftp.c 5.27 (Berkeley) 03/23/89"; 2033737Sbostic #endif /* not lint */ 2110296Ssam 2236940Skarels #include <sys/param.h> 2310296Ssam #include <sys/stat.h> 2410296Ssam #include <sys/ioctl.h> 2510296Ssam #include <sys/socket.h> 2613614Ssam #include <sys/time.h> 2736935Skarels #include <sys/file.h> 2810296Ssam 2910296Ssam #include <netinet/in.h> 3012397Ssam #include <arpa/ftp.h> 3126048Sminshall #include <arpa/telnet.h> 3210296Ssam 3310296Ssam #include <stdio.h> 3410296Ssam #include <signal.h> 3510296Ssam #include <errno.h> 3610296Ssam #include <netdb.h> 3726048Sminshall #include <fcntl.h> 3826048Sminshall #include <pwd.h> 3910296Ssam 4036940Skarels #include "ftp_var.h" 4136940Skarels 4210296Ssam struct sockaddr_in hisctladdr; 4310296Ssam struct sockaddr_in data_addr; 4410296Ssam int data = -1; 4526048Sminshall int abrtflag = 0; 4626048Sminshall int ptflag = 0; 4710296Ssam int connected; 4810296Ssam struct sockaddr_in myctladdr; 4926496Sminshall uid_t getuid(); 5037225Skarels off_t restart_point = 0; 5110296Ssam 5210296Ssam FILE *cin, *cout; 5310296Ssam FILE *dataconn(); 5410296Ssam 5525904Skarels char * 5610296Ssam hookup(host, port) 5710296Ssam char *host; 5810296Ssam int port; 5910296Ssam { 6025904Skarels register struct hostent *hp = 0; 6127687Sminshall int s,len; 6225904Skarels static char hostnamebuf[80]; 6310296Ssam 6410296Ssam bzero((char *)&hisctladdr, sizeof (hisctladdr)); 6525904Skarels hisctladdr.sin_addr.s_addr = inet_addr(host); 6625904Skarels if (hisctladdr.sin_addr.s_addr != -1) { 6725904Skarels hisctladdr.sin_family = AF_INET; 6836940Skarels (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf)); 6936940Skarels } else { 7025100Sbloom hp = gethostbyname(host); 7125904Skarels if (hp == NULL) { 7235792Sbostic fprintf(stderr, "ftp: %s: ", host); 7335792Sbostic herror((char *)NULL); 7426048Sminshall code = -1; 7526048Sminshall return((char *) 0); 7625904Skarels } 7725904Skarels hisctladdr.sin_family = hp->h_addrtype; 7825904Skarels bcopy(hp->h_addr_list[0], 7925904Skarels (caddr_t)&hisctladdr.sin_addr, hp->h_length); 8036940Skarels (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf)); 8110296Ssam } 8225904Skarels hostname = hostnamebuf; 8325904Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); 8410296Ssam if (s < 0) { 8510296Ssam perror("ftp: socket"); 8626048Sminshall code = -1; 8710296Ssam return (0); 8810296Ssam } 8910296Ssam hisctladdr.sin_port = port; 9026496Sminshall while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) { 9125904Skarels if (hp && hp->h_addr_list[1]) { 9225904Skarels int oerrno = errno; 9325904Skarels 9425904Skarels fprintf(stderr, "ftp: connect to address %s: ", 9525904Skarels inet_ntoa(hisctladdr.sin_addr)); 9625904Skarels errno = oerrno; 9726496Sminshall perror((char *) 0); 9825904Skarels hp->h_addr_list++; 9925904Skarels bcopy(hp->h_addr_list[0], 10026048Sminshall (caddr_t)&hisctladdr.sin_addr, hp->h_length); 10126496Sminshall fprintf(stdout, "Trying %s...\n", 10225904Skarels inet_ntoa(hisctladdr.sin_addr)); 10326813Skarels (void) close(s); 10426813Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); 10526813Skarels if (s < 0) { 10626813Skarels perror("ftp: socket"); 10726813Skarels code = -1; 10826813Skarels return (0); 10926813Skarels } 11025904Skarels continue; 11125904Skarels } 11210296Ssam perror("ftp: connect"); 11326048Sminshall code = -1; 11410296Ssam goto bad; 11510296Ssam } 11611627Ssam len = sizeof (myctladdr); 11711627Ssam if (getsockname(s, (char *)&myctladdr, &len) < 0) { 11811627Ssam perror("ftp: getsockname"); 11926048Sminshall code = -1; 12010296Ssam goto bad; 12110296Ssam } 12210296Ssam cin = fdopen(s, "r"); 12310296Ssam cout = fdopen(s, "w"); 12411219Ssam if (cin == NULL || cout == NULL) { 12510296Ssam fprintf(stderr, "ftp: fdopen failed.\n"); 12610296Ssam if (cin) 12726496Sminshall (void) fclose(cin); 12810296Ssam if (cout) 12926496Sminshall (void) fclose(cout); 13026048Sminshall code = -1; 13110296Ssam goto bad; 13210296Ssam } 13310296Ssam if (verbose) 13426067Sminshall printf("Connected to %s.\n", hostname); 13527687Sminshall if (getreply(0) > 2) { /* read startup message from server */ 13626048Sminshall if (cin) 13726496Sminshall (void) fclose(cin); 13826048Sminshall if (cout) 13926496Sminshall (void) fclose(cout); 14026048Sminshall code = -1; 14126048Sminshall goto bad; 14226048Sminshall } 14327687Sminshall #ifdef SO_OOBINLINE 14427687Sminshall { 14527687Sminshall int on = 1; 14626048Sminshall 14727687Sminshall if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)) 14827687Sminshall < 0 && debug) { 14927687Sminshall perror("ftp: setsockopt"); 15027687Sminshall } 15127687Sminshall } 15227687Sminshall #endif SO_OOBINLINE 15326048Sminshall 15425904Skarels return (hostname); 15510296Ssam bad: 15626496Sminshall (void) close(s); 15725904Skarels return ((char *)0); 15810296Ssam } 15910296Ssam 16025904Skarels login(host) 16125904Skarels char *host; 16210296Ssam { 16326048Sminshall char tmp[80]; 16435659Sbostic char *user, *pass, *acct, *getlogin(), *getpass(); 16526048Sminshall int n, aflag = 0; 16610296Ssam 16726048Sminshall user = pass = acct = 0; 16826048Sminshall if (ruserpass(host, &user, &pass, &acct) < 0) { 16926048Sminshall code = -1; 17026048Sminshall return(0); 17126048Sminshall } 17226048Sminshall if (user == NULL) { 17326048Sminshall char *myname = getlogin(); 17426048Sminshall 17526048Sminshall if (myname == NULL) { 17626048Sminshall struct passwd *pp = getpwuid(getuid()); 17726048Sminshall 17826448Slepreau if (pp != NULL) 17926048Sminshall myname = pp->pw_name; 18026048Sminshall } 18126048Sminshall printf("Name (%s:%s): ", host, myname); 18226048Sminshall (void) fgets(tmp, sizeof(tmp) - 1, stdin); 18326048Sminshall tmp[strlen(tmp) - 1] = '\0'; 18426448Slepreau if (*tmp == '\0') 18526048Sminshall user = myname; 18626448Slepreau else 18726048Sminshall user = tmp; 18826048Sminshall } 18910296Ssam n = command("USER %s", user); 19026048Sminshall if (n == CONTINUE) { 19126448Slepreau if (pass == NULL) 19235659Sbostic pass = getpass("Password:"); 19310296Ssam n = command("PASS %s", pass); 19426048Sminshall } 19510296Ssam if (n == CONTINUE) { 19626048Sminshall aflag++; 19735659Sbostic acct = getpass("Account:"); 19810296Ssam n = command("ACCT %s", acct); 19910296Ssam } 20010296Ssam if (n != COMPLETE) { 20110296Ssam fprintf(stderr, "Login failed.\n"); 20210296Ssam return (0); 20310296Ssam } 20426448Slepreau if (!aflag && acct != NULL) 20526048Sminshall (void) command("ACCT %s", acct); 20626448Slepreau if (proxy) 20726048Sminshall return(1); 20826048Sminshall for (n = 0; n < macnum; ++n) { 20926048Sminshall if (!strcmp("init", macros[n].mac_name)) { 21026496Sminshall (void) strcpy(line, "$init"); 21126048Sminshall makeargv(); 21226048Sminshall domacro(margc, margv); 21326048Sminshall break; 21426048Sminshall } 21526048Sminshall } 21610296Ssam return (1); 21710296Ssam } 21810296Ssam 21926048Sminshall cmdabort() 22026048Sminshall { 22126048Sminshall extern jmp_buf ptabort; 22226048Sminshall 22326048Sminshall printf("\n"); 22426048Sminshall (void) fflush(stdout); 22526048Sminshall abrtflag++; 22626448Slepreau if (ptflag) 22726048Sminshall longjmp(ptabort,1); 22826048Sminshall } 22926048Sminshall 23026496Sminshall /*VARARGS1*/ 23110296Ssam command(fmt, args) 23210296Ssam char *fmt; 23310296Ssam { 23426048Sminshall int r, (*oldintr)(), cmdabort(); 23510296Ssam 23626048Sminshall abrtflag = 0; 23710296Ssam if (debug) { 23810296Ssam printf("---> "); 23910296Ssam _doprnt(fmt, &args, stdout); 24010296Ssam printf("\n"); 24110296Ssam (void) fflush(stdout); 24210296Ssam } 24311219Ssam if (cout == NULL) { 24411219Ssam perror ("No control connection for command"); 24526048Sminshall code = -1; 24611219Ssam return (0); 24711219Ssam } 24826048Sminshall oldintr = signal(SIGINT,cmdabort); 24910296Ssam _doprnt(fmt, &args, cout); 25010296Ssam fprintf(cout, "\r\n"); 25110296Ssam (void) fflush(cout); 25226048Sminshall cpend = 1; 25326048Sminshall r = getreply(!strcmp(fmt, "QUIT")); 25426448Slepreau if (abrtflag && oldintr != SIG_IGN) 25526048Sminshall (*oldintr)(); 25626048Sminshall (void) signal(SIGINT, oldintr); 25726048Sminshall return(r); 25810296Ssam } 25910296Ssam 260*37229Skarels char reply_string[BUFSIZ]; /* last line of previous reply */ 26136935Skarels 26210296Ssam #include <ctype.h> 26310296Ssam 26410296Ssam getreply(expecteof) 26510296Ssam int expecteof; 26610296Ssam { 26711219Ssam register int c, n; 26826048Sminshall register int dig; 26936935Skarels register char *cp; 27026048Sminshall int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort(); 27126048Sminshall int pflag = 0; 27226048Sminshall char *pt = pasv; 27310296Ssam 27426048Sminshall oldintr = signal(SIGINT,cmdabort); 27510296Ssam for (;;) { 27610296Ssam dig = n = code = 0; 277*37229Skarels cp = reply_string; 27810296Ssam while ((c = getc(cin)) != '\n') { 27927687Sminshall if (c == IAC) { /* handle telnet commands */ 28027687Sminshall switch (c = getc(cin)) { 28127687Sminshall case WILL: 28227687Sminshall case WONT: 28327687Sminshall c = getc(cin); 28436940Skarels fprintf(cout, "%c%c%c",IAC,DONT,c); 28527687Sminshall (void) fflush(cout); 28627687Sminshall break; 28727687Sminshall case DO: 28827687Sminshall case DONT: 28927687Sminshall c = getc(cin); 29036940Skarels fprintf(cout, "%c%c%c",IAC,WONT,c); 29127687Sminshall (void) fflush(cout); 29227687Sminshall break; 29327687Sminshall default: 29427687Sminshall break; 29527687Sminshall } 29627687Sminshall continue; 29727687Sminshall } 29810296Ssam dig++; 29910296Ssam if (c == EOF) { 30026048Sminshall if (expecteof) { 30126048Sminshall (void) signal(SIGINT,oldintr); 30226048Sminshall code = 221; 30310296Ssam return (0); 30426048Sminshall } 30510296Ssam lostpeer(); 30626048Sminshall if (verbose) { 30726048Sminshall printf("421 Service not available, remote server has closed connection\n"); 30826048Sminshall (void) fflush(stdout); 30926048Sminshall } 31033772Scsvsj code = 421; 31133772Scsvsj return(4); 31210296Ssam } 31326048Sminshall if (c != '\r' && (verbose > 0 || 31426048Sminshall (verbose > -1 && n == '5' && dig > 4))) { 31526448Slepreau if (proxflag && 31626448Slepreau (dig == 1 || dig == 5 && verbose == 0)) 31726048Sminshall printf("%s:",hostname); 31826496Sminshall (void) putchar(c); 31926048Sminshall } 32010296Ssam if (dig < 4 && isdigit(c)) 32110296Ssam code = code * 10 + (c - '0'); 32226448Slepreau if (!pflag && code == 227) 32326048Sminshall pflag = 1; 32426448Slepreau if (dig > 4 && pflag == 1 && isdigit(c)) 32526048Sminshall pflag = 2; 32626048Sminshall if (pflag == 2) { 32726448Slepreau if (c != '\r' && c != ')') 32826048Sminshall *pt++ = c; 32926048Sminshall else { 33026048Sminshall *pt = '\0'; 33126048Sminshall pflag = 3; 33226048Sminshall } 33326048Sminshall } 33426048Sminshall if (dig == 4 && c == '-') { 33526448Slepreau if (continuation) 33626048Sminshall code = 0; 33710296Ssam continuation++; 33826048Sminshall } 33910296Ssam if (n == 0) 34010296Ssam n = c; 341*37229Skarels if (cp < &reply_string[sizeof(reply_string) - 1]) 342*37229Skarels *cp++ = c; 34310296Ssam } 34426048Sminshall if (verbose > 0 || verbose > -1 && n == '5') { 34526496Sminshall (void) putchar(c); 34611346Ssam (void) fflush (stdout); 34711346Ssam } 34810296Ssam if (continuation && code != originalcode) { 34910296Ssam if (originalcode == 0) 35010296Ssam originalcode = code; 35110296Ssam continue; 35210296Ssam } 35336935Skarels *cp = '\0'; 35426448Slepreau if (n != '1') 35526048Sminshall cpend = 0; 35626048Sminshall (void) signal(SIGINT,oldintr); 35726448Slepreau if (code == 421 || originalcode == 421) 35826048Sminshall lostpeer(); 35926448Slepreau if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) 36026048Sminshall (*oldintr)(); 36125907Smckusick return (n - '0'); 36210296Ssam } 36310296Ssam } 36410296Ssam 36526048Sminshall empty(mask, sec) 36627687Sminshall struct fd_set *mask; 36726048Sminshall int sec; 36826048Sminshall { 36926048Sminshall struct timeval t; 37026048Sminshall 37126048Sminshall t.tv_sec = (long) sec; 37226048Sminshall t.tv_usec = 0; 37327687Sminshall return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t)); 37426048Sminshall } 37526048Sminshall 37610296Ssam jmp_buf sendabort; 37710296Ssam 37810296Ssam abortsend() 37910296Ssam { 38010296Ssam 38126048Sminshall mflag = 0; 38226048Sminshall abrtflag = 0; 38326048Sminshall printf("\nsend aborted\n"); 38426048Sminshall (void) fflush(stdout); 38510296Ssam longjmp(sendabort, 1); 38610296Ssam } 38710296Ssam 38836940Skarels #define HASHBYTES 1024 38936940Skarels 39037225Skarels sendrequest(cmd, local, remote, printnames) 39110296Ssam char *cmd, *local, *remote; 39237225Skarels int printnames; 39310296Ssam { 39435659Sbostic FILE *fin, *dout = 0, *popen(); 39535659Sbostic int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)(); 39626048Sminshall int abortsend(); 39736942Skarels char buf[BUFSIZ], *bufp; 39836940Skarels long bytes = 0, hashbytes = HASHBYTES; 39911346Ssam register int c, d; 40010296Ssam struct stat st; 40110296Ssam struct timeval start, stop; 40236935Skarels char *mode; 40310296Ssam 40437225Skarels if (verbose && printnames) { 40537225Skarels if (local && *local != '-') 40637225Skarels printf("local: %s ", local); 40737225Skarels if (remote) 40837225Skarels printf("remote: %s\n", remote); 40937225Skarels } 41026048Sminshall if (proxy) { 41126048Sminshall proxtrans(cmd, local, remote); 41226048Sminshall return; 41326048Sminshall } 41410296Ssam closefunc = NULL; 41526048Sminshall oldintr = NULL; 41626048Sminshall oldintp = NULL; 41736935Skarels mode = "w"; 41826048Sminshall if (setjmp(sendabort)) { 41926048Sminshall while (cpend) { 42026048Sminshall (void) getreply(0); 42126048Sminshall } 42226048Sminshall if (data >= 0) { 42326048Sminshall (void) close(data); 42426048Sminshall data = -1; 42526048Sminshall } 42626448Slepreau if (oldintr) 42726048Sminshall (void) signal(SIGINT,oldintr); 42826448Slepreau if (oldintp) 42926048Sminshall (void) signal(SIGPIPE,oldintp); 43026048Sminshall code = -1; 43126048Sminshall return; 43226048Sminshall } 43310296Ssam oldintr = signal(SIGINT, abortsend); 43410296Ssam if (strcmp(local, "-") == 0) 43510296Ssam fin = stdin; 43610296Ssam else if (*local == '|') { 43726048Sminshall oldintp = signal(SIGPIPE,SIG_IGN); 43835659Sbostic fin = popen(local + 1, "r"); 43910296Ssam if (fin == NULL) { 44026048Sminshall perror(local + 1); 44126048Sminshall (void) signal(SIGINT, oldintr); 44226048Sminshall (void) signal(SIGPIPE, oldintp); 44326048Sminshall code = -1; 44426048Sminshall return; 44510296Ssam } 44635659Sbostic closefunc = pclose; 44710296Ssam } else { 44810296Ssam fin = fopen(local, "r"); 44910296Ssam if (fin == NULL) { 45010296Ssam perror(local); 45126048Sminshall (void) signal(SIGINT, oldintr); 45226048Sminshall code = -1; 45326048Sminshall return; 45410296Ssam } 45510296Ssam closefunc = fclose; 45610296Ssam if (fstat(fileno(fin), &st) < 0 || 45710296Ssam (st.st_mode&S_IFMT) != S_IFREG) { 45826496Sminshall fprintf(stdout, "%s: not a plain file.\n", local); 45926048Sminshall (void) signal(SIGINT, oldintr); 46036935Skarels fclose(fin); 46126048Sminshall code = -1; 46226048Sminshall return; 46310296Ssam } 46410296Ssam } 46526048Sminshall if (initconn()) { 46626048Sminshall (void) signal(SIGINT, oldintr); 46726448Slepreau if (oldintp) 46826048Sminshall (void) signal(SIGPIPE, oldintp); 46926048Sminshall code = -1; 47036935Skarels if (closefunc != NULL) 47136935Skarels (*closefunc)(fin); 47226048Sminshall return; 47326048Sminshall } 47426448Slepreau if (setjmp(sendabort)) 47526048Sminshall goto abort; 47636935Skarels 47737225Skarels if (restart_point && 47837225Skarels (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { 47937225Skarels if (fseek(fin, (long) restart_point, 0) < 0) { 48037225Skarels perror(local); 48137225Skarels restart_point = 0; 48237225Skarels if (closefunc != NULL) 48337225Skarels (*closefunc)(fin); 48437225Skarels return; 48537225Skarels } 48637225Skarels if (command("REST %ld", (long) restart_point) 48737225Skarels != CONTINUE) { 48837225Skarels restart_point = 0; 48937225Skarels if (closefunc != NULL) 49037225Skarels (*closefunc)(fin); 49137225Skarels return; 49237225Skarels } 49337225Skarels restart_point = 0; 49437225Skarels mode = "r+w"; 49537225Skarels } 49610296Ssam if (remote) { 49726048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 49826048Sminshall (void) signal(SIGINT, oldintr); 49926448Slepreau if (oldintp) 50026048Sminshall (void) signal(SIGPIPE, oldintp); 50136935Skarels if (closefunc != NULL) 50236935Skarels (*closefunc)(fin); 50326048Sminshall return; 50426048Sminshall } 50510296Ssam } else 50626048Sminshall if (command("%s", cmd) != PRELIM) { 50726048Sminshall (void) signal(SIGINT, oldintr); 50826448Slepreau if (oldintp) 50926048Sminshall (void) signal(SIGPIPE, oldintp); 51036935Skarels if (closefunc != NULL) 51136935Skarels (*closefunc)(fin); 51226048Sminshall return; 51326048Sminshall } 51436935Skarels dout = dataconn(mode); 51526448Slepreau if (dout == NULL) 51626048Sminshall goto abort; 51726496Sminshall (void) gettimeofday(&start, (struct timezone *)0); 51836935Skarels oldintp = signal(SIGPIPE, SIG_IGN); 51911219Ssam switch (type) { 52011219Ssam 52111219Ssam case TYPE_I: 52211219Ssam case TYPE_L: 52311346Ssam errno = d = 0; 52436942Skarels while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) { 52511219Ssam bytes += c; 52636942Skarels for (bufp = buf; c > 0; c -= d, bufp += d) 52736942Skarels if ((d = write(fileno(dout), bufp, c)) <= 0) 52836942Skarels break; 52911651Ssam if (hash) { 53036940Skarels while (bytes >= hashbytes) { 53136940Skarels (void) putchar('#'); 53236940Skarels hashbytes += HASHBYTES; 53336940Skarels } 53426496Sminshall (void) fflush(stdout); 53511651Ssam } 53611219Ssam } 53713213Ssam if (hash && bytes > 0) { 53836940Skarels if (bytes < HASHBYTES) 53936940Skarels (void) putchar('#'); 54026496Sminshall (void) putchar('\n'); 54126496Sminshall (void) fflush(stdout); 54211651Ssam } 54311219Ssam if (c < 0) 54411219Ssam perror(local); 54536942Skarels if (d <= 0) { 54636942Skarels if (d == 0) 54736942Skarels fprintf(stderr, "netout: write returned 0?\n"); 54836942Skarels else if (errno != EPIPE) 54936935Skarels perror("netout"); 55036935Skarels bytes = -1; 55136935Skarels } 55211219Ssam break; 55311219Ssam 55411219Ssam case TYPE_A: 55511219Ssam while ((c = getc(fin)) != EOF) { 55611219Ssam if (c == '\n') { 55711651Ssam while (hash && (bytes >= hashbytes)) { 55826496Sminshall (void) putchar('#'); 55926496Sminshall (void) fflush(stdout); 56036940Skarels hashbytes += HASHBYTES; 56111651Ssam } 56211219Ssam if (ferror(dout)) 56311219Ssam break; 56426496Sminshall (void) putc('\r', dout); 56511219Ssam bytes++; 56611219Ssam } 56726496Sminshall (void) putc(c, dout); 56811219Ssam bytes++; 56926048Sminshall /* if (c == '\r') { */ 57026496Sminshall /* (void) putc('\0', dout); /* this violates rfc */ 57126048Sminshall /* bytes++; */ 57226048Sminshall /* } */ 57311219Ssam } 57411651Ssam if (hash) { 57513213Ssam if (bytes < hashbytes) 57626496Sminshall (void) putchar('#'); 57726496Sminshall (void) putchar('\n'); 57826496Sminshall (void) fflush(stdout); 57911651Ssam } 58011219Ssam if (ferror(fin)) 58111219Ssam perror(local); 58236935Skarels if (ferror(dout)) { 58336935Skarels if (errno != EPIPE) 58436935Skarels perror("netout"); 58536935Skarels bytes = -1; 58636935Skarels } 58711219Ssam break; 58810296Ssam } 58926496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 59010296Ssam if (closefunc != NULL) 59126048Sminshall (*closefunc)(fin); 59210296Ssam (void) fclose(dout); 59326048Sminshall (void) getreply(0); 59426048Sminshall (void) signal(SIGINT, oldintr); 59536935Skarels if (oldintp) 59636935Skarels (void) signal(SIGPIPE, oldintp); 59735699Sbostic if (bytes > 0) 59837225Skarels ptransfer("sent", bytes, &start, &stop); 59910296Ssam return; 60026048Sminshall abort: 60126496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 60226048Sminshall (void) signal(SIGINT, oldintr); 60326448Slepreau if (oldintp) 60426048Sminshall (void) signal(SIGPIPE, oldintp); 60526048Sminshall if (!cpend) { 60626048Sminshall code = -1; 60726048Sminshall return; 60826048Sminshall } 60926048Sminshall if (data >= 0) { 61026048Sminshall (void) close(data); 61126048Sminshall data = -1; 61226048Sminshall } 61326448Slepreau if (dout) 61426048Sminshall (void) fclose(dout); 61526048Sminshall (void) getreply(0); 61626048Sminshall code = -1; 61710296Ssam if (closefunc != NULL && fin != NULL) 61826048Sminshall (*closefunc)(fin); 61935699Sbostic if (bytes > 0) 62037225Skarels ptransfer("sent", bytes, &start, &stop); 62110296Ssam } 62210296Ssam 62310296Ssam jmp_buf recvabort; 62410296Ssam 62510296Ssam abortrecv() 62610296Ssam { 62710296Ssam 62826048Sminshall mflag = 0; 62926048Sminshall abrtflag = 0; 63026048Sminshall printf("\n"); 63126048Sminshall (void) fflush(stdout); 63210296Ssam longjmp(recvabort, 1); 63310296Ssam } 63410296Ssam 63537225Skarels recvrequest(cmd, local, remote, mode, printnames) 63611651Ssam char *cmd, *local, *remote, *mode; 63710296Ssam { 63835659Sbostic FILE *fout, *din = 0, *popen(); 63935659Sbostic int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)(); 64036935Skarels int abortrecv(), oldverbose, oldtype = 0, is_retr, tcrflag, nfnd; 64136944Skarels char *bufp, *gunique(), msg; 64236944Skarels static char *buf; 64336940Skarels static int bufsize; 64436940Skarels long bytes = 0, hashbytes = HASHBYTES; 64526496Sminshall struct fd_set mask; 64611346Ssam register int c, d; 64710296Ssam struct timeval start, stop; 64836940Skarels struct stat st; 64936940Skarels extern char *malloc(); 65010296Ssam 65136935Skarels is_retr = strcmp(cmd, "RETR") == 0; 65237225Skarels if (is_retr && verbose && printnames) { 65337225Skarels if (local && *local != '-') 65437225Skarels printf("local: %s ", local); 65537225Skarels if (remote) 65637225Skarels printf("remote: %s\n", remote); 65737225Skarels } 65836935Skarels if (proxy && is_retr) { 65926048Sminshall proxtrans(cmd, local, remote); 66026048Sminshall return; 66126048Sminshall } 66210296Ssam closefunc = NULL; 66326048Sminshall oldintr = NULL; 66426048Sminshall oldintp = NULL; 66536935Skarels tcrflag = !crflag && is_retr; 66626048Sminshall if (setjmp(recvabort)) { 66726048Sminshall while (cpend) { 66826048Sminshall (void) getreply(0); 66926048Sminshall } 67026048Sminshall if (data >= 0) { 67126048Sminshall (void) close(data); 67226048Sminshall data = -1; 67326048Sminshall } 67426448Slepreau if (oldintr) 67526048Sminshall (void) signal(SIGINT, oldintr); 67626048Sminshall code = -1; 67726048Sminshall return; 67826048Sminshall } 67910296Ssam oldintr = signal(SIGINT, abortrecv); 68026048Sminshall if (strcmp(local, "-") && *local != '|') { 68110296Ssam if (access(local, 2) < 0) { 68226048Sminshall char *dir = rindex(local, '/'); 68310296Ssam 68426048Sminshall if (errno != ENOENT && errno != EACCES) { 68510296Ssam perror(local); 68626048Sminshall (void) signal(SIGINT, oldintr); 68726048Sminshall code = -1; 68826048Sminshall return; 68910296Ssam } 69026048Sminshall if (dir != NULL) 69126048Sminshall *dir = 0; 69226048Sminshall d = access(dir ? local : ".", 2); 69326048Sminshall if (dir != NULL) 69426048Sminshall *dir = '/'; 69526048Sminshall if (d < 0) { 69626048Sminshall perror(local); 69726048Sminshall (void) signal(SIGINT, oldintr); 69826048Sminshall code = -1; 69926048Sminshall return; 70026048Sminshall } 70126048Sminshall if (!runique && errno == EACCES && 70236935Skarels chmod(local, 0600) < 0) { 70326048Sminshall perror(local); 70426048Sminshall (void) signal(SIGINT, oldintr); 70526048Sminshall code = -1; 70626048Sminshall return; 70726048Sminshall } 70826048Sminshall if (runique && errno == EACCES && 70926048Sminshall (local = gunique(local)) == NULL) { 71026048Sminshall (void) signal(SIGINT, oldintr); 71126048Sminshall code = -1; 71226048Sminshall return; 71326048Sminshall } 71410296Ssam } 71526048Sminshall else if (runique && (local = gunique(local)) == NULL) { 71626048Sminshall (void) signal(SIGINT, oldintr); 71726048Sminshall code = -1; 71826048Sminshall return; 71926048Sminshall } 72026048Sminshall } 72126048Sminshall if (initconn()) { 72226048Sminshall (void) signal(SIGINT, oldintr); 72326048Sminshall code = -1; 72426048Sminshall return; 72526048Sminshall } 72626448Slepreau if (setjmp(recvabort)) 72726048Sminshall goto abort; 72836935Skarels if (!is_retr) { 72936935Skarels if (type != TYPE_A) { 73036935Skarels oldtype = type; 73136935Skarels oldverbose = verbose; 73236935Skarels if (!debug) 73336935Skarels verbose = 0; 73436935Skarels setascii(); 73536935Skarels verbose = oldverbose; 73636935Skarels } 73737225Skarels } else if (restart_point) { 73837225Skarels if (command("REST %ld", (long) restart_point) != CONTINUE) 73937225Skarels return; 74026048Sminshall } 74110296Ssam if (remote) { 74226048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 74326048Sminshall (void) signal(SIGINT, oldintr); 74426048Sminshall if (oldtype) { 74526448Slepreau if (!debug) 74626048Sminshall verbose = 0; 74726048Sminshall switch (oldtype) { 74826048Sminshall case TYPE_I: 74926048Sminshall setbinary(); 75026048Sminshall break; 75126048Sminshall case TYPE_E: 75226048Sminshall setebcdic(); 75326048Sminshall break; 75426048Sminshall case TYPE_L: 75526048Sminshall settenex(); 75626048Sminshall break; 75736942Skarels } 75826048Sminshall verbose = oldverbose; 75926048Sminshall } 76026048Sminshall return; 76126048Sminshall } 76226048Sminshall } else { 76326048Sminshall if (command("%s", cmd) != PRELIM) { 76426048Sminshall (void) signal(SIGINT, oldintr); 76526048Sminshall if (oldtype) { 76626448Slepreau if (!debug) 76726048Sminshall verbose = 0; 76826048Sminshall switch (oldtype) { 76926048Sminshall case TYPE_I: 77026048Sminshall setbinary(); 77126048Sminshall break; 77226048Sminshall case TYPE_E: 77326048Sminshall setebcdic(); 77426048Sminshall break; 77526048Sminshall case TYPE_L: 77626048Sminshall settenex(); 77726048Sminshall break; 77836942Skarels } 77926048Sminshall verbose = oldverbose; 78026048Sminshall } 78126048Sminshall return; 78226048Sminshall } 78326048Sminshall } 78426048Sminshall din = dataconn("r"); 78526048Sminshall if (din == NULL) 78626048Sminshall goto abort; 78726448Slepreau if (strcmp(local, "-") == 0) 78810296Ssam fout = stdout; 78910296Ssam else if (*local == '|') { 79026048Sminshall oldintp = signal(SIGPIPE, SIG_IGN); 79135659Sbostic fout = popen(local + 1, "w"); 79226048Sminshall if (fout == NULL) { 79326048Sminshall perror(local+1); 79426048Sminshall goto abort; 79526048Sminshall } 79635659Sbostic closefunc = pclose; 79736940Skarels } else { 79811651Ssam fout = fopen(local, mode); 79926048Sminshall if (fout == NULL) { 80026048Sminshall perror(local); 80126048Sminshall goto abort; 80226048Sminshall } 80310296Ssam closefunc = fclose; 80410296Ssam } 80536940Skarels if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0) 80636940Skarels st.st_blksize = BUFSIZ; 80736940Skarels if (st.st_blksize > bufsize) { 80836940Skarels if (buf) 80936940Skarels (void) free(buf); 81036940Skarels buf = malloc(st.st_blksize); 81136940Skarels if (buf == NULL) { 81236940Skarels perror("malloc"); 81336944Skarels bufsize = 0; 81436940Skarels goto abort; 81536940Skarels } 81636940Skarels bufsize = st.st_blksize; 81736940Skarels } 81826496Sminshall (void) gettimeofday(&start, (struct timezone *)0); 81911219Ssam switch (type) { 82011219Ssam 82111219Ssam case TYPE_I: 82211219Ssam case TYPE_L: 82337225Skarels if (restart_point && 82437225Skarels lseek(fileno(fout), (long) restart_point, L_SET) < 0) { 82537225Skarels perror(local); 82637225Skarels if (closefunc != NULL) 82737225Skarels (*closefunc)(fout); 82837225Skarels return; 82937225Skarels } 83011346Ssam errno = d = 0; 83136940Skarels while ((c = read(fileno(din), buf, bufsize)) > 0) { 83236944Skarels if ((d = write(fileno(fout), buf, c)) != c) 83311219Ssam break; 83411219Ssam bytes += c; 83511651Ssam if (hash) { 83636940Skarels while (bytes >= hashbytes) { 83736940Skarels (void) putchar('#'); 83836940Skarels hashbytes += HASHBYTES; 83936940Skarels } 84026496Sminshall (void) fflush(stdout); 84111651Ssam } 84211219Ssam } 84313213Ssam if (hash && bytes > 0) { 84436940Skarels if (bytes < HASHBYTES) 84536940Skarels (void) putchar('#'); 84626496Sminshall (void) putchar('\n'); 84726496Sminshall (void) fflush(stdout); 84811651Ssam } 84936935Skarels if (c < 0) { 85036935Skarels if (errno != EPIPE) 85136935Skarels perror("netin"); 85236935Skarels bytes = -1; 85336935Skarels } 85436942Skarels if (d < c) { 85536942Skarels if (d < 0) 85636942Skarels perror(local); 85736942Skarels else 85836942Skarels fprintf(stderr, "%s: short write\n", local); 85936942Skarels } 86011219Ssam break; 86111219Ssam 86211219Ssam case TYPE_A: 86337225Skarels if (restart_point) { 86437225Skarels register int i, n, c; 86537225Skarels 86637225Skarels if (fseek(fout, 0L, L_SET) < 0) 86737225Skarels goto done; 86837225Skarels n = restart_point; 86937225Skarels i = 0; 87037225Skarels while (i++ < n) { 87137225Skarels if ((c=getc(fout)) == EOF) 87237225Skarels goto done; 87337225Skarels if (c == '\n') 87437225Skarels i++; 87537225Skarels } 87637225Skarels if (fseek(fout, 0L, L_INCR) < 0) { 87737225Skarels done: 87837225Skarels perror(local); 87937225Skarels if (closefunc != NULL) 88037225Skarels (*closefunc)(fout); 88137225Skarels return; 88237225Skarels } 88337225Skarels } 88411219Ssam while ((c = getc(din)) != EOF) { 88527749Sminshall while (c == '\r') { 88611651Ssam while (hash && (bytes >= hashbytes)) { 88726496Sminshall (void) putchar('#'); 88826496Sminshall (void) fflush(stdout); 88936940Skarels hashbytes += HASHBYTES; 89011651Ssam } 89110296Ssam bytes++; 89226048Sminshall if ((c = getc(din)) != '\n' || tcrflag) { 89336940Skarels if (ferror(fout)) 89436940Skarels goto break2; 89536940Skarels (void) putc('\r', fout); 89636942Skarels if (c == '\0') { 89736942Skarels bytes++; 89836940Skarels goto contin2; 89936942Skarels } 90036942Skarels if (c == EOF) 90136942Skarels goto contin2; 90211219Ssam } 90311219Ssam } 90436940Skarels (void) putc(c, fout); 90511219Ssam bytes++; 90636940Skarels contin2: ; 90710296Ssam } 90836940Skarels break2: 90911651Ssam if (hash) { 91013213Ssam if (bytes < hashbytes) 91126496Sminshall (void) putchar('#'); 91226496Sminshall (void) putchar('\n'); 91326496Sminshall (void) fflush(stdout); 91411651Ssam } 91536944Skarels if (ferror(din)) { 91636935Skarels if (errno != EPIPE) 91736944Skarels perror("netin"); 91836935Skarels bytes = -1; 91936935Skarels } 92036940Skarels if (ferror(fout)) 92136944Skarels perror(local); 92211219Ssam break; 92310296Ssam } 92426448Slepreau if (closefunc != NULL) 92526048Sminshall (*closefunc)(fout); 92626496Sminshall (void) signal(SIGINT, oldintr); 92726448Slepreau if (oldintp) 92826048Sminshall (void) signal(SIGPIPE, oldintp); 92926496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 93010296Ssam (void) fclose(din); 93126048Sminshall (void) getreply(0); 93236935Skarels if (bytes > 0 && is_retr) 93337225Skarels ptransfer("received", bytes, &start, &stop); 93426048Sminshall if (oldtype) { 93526448Slepreau if (!debug) 93626048Sminshall verbose = 0; 93726048Sminshall switch (oldtype) { 93826048Sminshall case TYPE_I: 93926048Sminshall setbinary(); 94026048Sminshall break; 94126048Sminshall case TYPE_E: 94226048Sminshall setebcdic(); 94326048Sminshall break; 94426048Sminshall case TYPE_L: 94526048Sminshall settenex(); 94626048Sminshall break; 94726048Sminshall } 94826048Sminshall verbose = oldverbose; 94926048Sminshall } 95026048Sminshall return; 95126048Sminshall abort: 95226048Sminshall 95327687Sminshall /* abort using RFC959 recommended IP,SYNC sequence */ 95426048Sminshall 95526496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 95626448Slepreau if (oldintp) 95726048Sminshall (void) signal(SIGPIPE, oldintr); 95826048Sminshall (void) signal(SIGINT,SIG_IGN); 95926048Sminshall if (oldtype) { 96026448Slepreau if (!debug) 96126048Sminshall verbose = 0; 96226048Sminshall switch (oldtype) { 96326048Sminshall case TYPE_I: 96426048Sminshall setbinary(); 96526048Sminshall break; 96626048Sminshall case TYPE_E: 96726048Sminshall setebcdic(); 96826048Sminshall break; 96926048Sminshall case TYPE_L: 97026048Sminshall settenex(); 97126048Sminshall break; 97226048Sminshall } 97326048Sminshall verbose = oldverbose; 97426048Sminshall } 97526048Sminshall if (!cpend) { 97626048Sminshall code = -1; 97726048Sminshall (void) signal(SIGINT,oldintr); 97826048Sminshall return; 97926048Sminshall } 98026048Sminshall 98127687Sminshall fprintf(cout,"%c%c",IAC,IP); 98227687Sminshall (void) fflush(cout); 98327687Sminshall msg = IAC; 98427687Sminshall /* send IAC in urgent mode instead of DM because UNIX places oob mark */ 98527687Sminshall /* after urgent byte rather than before as now is protocol */ 98627687Sminshall if (send(fileno(cout),&msg,1,MSG_OOB) != 1) { 98727687Sminshall perror("abort"); 98826048Sminshall } 98927687Sminshall fprintf(cout,"%cABOR\r\n",DM); 99026048Sminshall (void) fflush(cout); 99127687Sminshall FD_ZERO(&mask); 99226496Sminshall FD_SET(fileno(cin), &mask); 99326496Sminshall if (din) { 99426496Sminshall FD_SET(fileno(din), &mask); 99526496Sminshall } 99627687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 99727687Sminshall if (nfnd < 0) { 99827687Sminshall perror("abort"); 99927687Sminshall } 100026048Sminshall code = -1; 100126048Sminshall lostpeer(); 100226048Sminshall } 100326496Sminshall if (din && FD_ISSET(fileno(din), &mask)) { 100436940Skarels while ((c = read(fileno(din), buf, bufsize)) > 0) 100526448Slepreau ; 100626496Sminshall } 100727687Sminshall if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */ 100826048Sminshall if (data >= 0) { 100926496Sminshall (void) close(data); 101026048Sminshall data = -1; 101126048Sminshall } 101225907Smckusick (void) getreply(0); 101325907Smckusick } 101426048Sminshall (void) getreply(0); 101526048Sminshall code = -1; 101626048Sminshall if (data >= 0) { 101726048Sminshall (void) close(data); 101826048Sminshall data = -1; 101926048Sminshall } 102026448Slepreau if (closefunc != NULL && fout != NULL) 102126048Sminshall (*closefunc)(fout); 102226448Slepreau if (din) 102326048Sminshall (void) fclose(din); 102435699Sbostic if (bytes > 0) 102537225Skarels ptransfer("received", bytes, &start, &stop); 102626048Sminshall (void) signal(SIGINT,oldintr); 102710296Ssam } 102810296Ssam 102910296Ssam /* 103010296Ssam * Need to start a listen on the data channel 103110296Ssam * before we send the command, otherwise the 103210296Ssam * server's connect may fail. 103310296Ssam */ 103433224Sbostic int sendport = -1; 103511651Ssam 103610296Ssam initconn() 103710296Ssam { 103810296Ssam register char *p, *a; 103926048Sminshall int result, len, tmpno = 0; 104026993Skarels int on = 1; 104110296Ssam 104211651Ssam noport: 104310296Ssam data_addr = myctladdr; 104411651Ssam if (sendport) 104511651Ssam data_addr.sin_port = 0; /* let system pick one */ 104611651Ssam if (data != -1) 104711651Ssam (void) close (data); 104818287Sralph data = socket(AF_INET, SOCK_STREAM, 0); 104910296Ssam if (data < 0) { 105010296Ssam perror("ftp: socket"); 105126448Slepreau if (tmpno) 105226048Sminshall sendport = 1; 105310296Ssam return (1); 105410296Ssam } 105512397Ssam if (!sendport) 105627687Sminshall if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { 105733224Sbostic perror("ftp: setsockopt (reuse address)"); 105812397Ssam goto bad; 105912397Ssam } 106026496Sminshall if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { 106110296Ssam perror("ftp: bind"); 106210296Ssam goto bad; 106310296Ssam } 106410296Ssam if (options & SO_DEBUG && 106527687Sminshall setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) 106610296Ssam perror("ftp: setsockopt (ignored)"); 106711627Ssam len = sizeof (data_addr); 106811627Ssam if (getsockname(data, (char *)&data_addr, &len) < 0) { 106911627Ssam perror("ftp: getsockname"); 107010296Ssam goto bad; 107110296Ssam } 107226448Slepreau if (listen(data, 1) < 0) 107310296Ssam perror("ftp: listen"); 107411651Ssam if (sendport) { 107511651Ssam a = (char *)&data_addr.sin_addr; 107611651Ssam p = (char *)&data_addr.sin_port; 107710296Ssam #define UC(b) (((int)b)&0xff) 107811651Ssam result = 107911651Ssam command("PORT %d,%d,%d,%d,%d,%d", 108011651Ssam UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 108111651Ssam UC(p[0]), UC(p[1])); 108211651Ssam if (result == ERROR && sendport == -1) { 108311651Ssam sendport = 0; 108426048Sminshall tmpno = 1; 108511651Ssam goto noport; 108611651Ssam } 108711651Ssam return (result != COMPLETE); 108811651Ssam } 108926448Slepreau if (tmpno) 109026048Sminshall sendport = 1; 109111651Ssam return (0); 109210296Ssam bad: 109310296Ssam (void) close(data), data = -1; 109426448Slepreau if (tmpno) 109526048Sminshall sendport = 1; 109610296Ssam return (1); 109710296Ssam } 109810296Ssam 109910296Ssam FILE * 110010296Ssam dataconn(mode) 110110296Ssam char *mode; 110210296Ssam { 110310296Ssam struct sockaddr_in from; 110410296Ssam int s, fromlen = sizeof (from); 110510296Ssam 110626496Sminshall s = accept(data, (struct sockaddr *) &from, &fromlen); 110710296Ssam if (s < 0) { 110810296Ssam perror("ftp: accept"); 110910296Ssam (void) close(data), data = -1; 111010296Ssam return (NULL); 111110296Ssam } 111210296Ssam (void) close(data); 111310296Ssam data = s; 111410296Ssam return (fdopen(data, mode)); 111510296Ssam } 111610296Ssam 111737225Skarels ptransfer(direction, bytes, t0, t1) 111837225Skarels char *direction; 111911651Ssam long bytes; 112010296Ssam struct timeval *t0, *t1; 112110296Ssam { 112210296Ssam struct timeval td; 112316437Sleres float s, bs; 112410296Ssam 112535699Sbostic if (verbose) { 112635699Sbostic tvsub(&td, t1, t0); 112735699Sbostic s = td.tv_sec + (td.tv_usec / 1000000.); 112810296Ssam #define nz(x) ((x) == 0 ? 1 : (x)) 112935699Sbostic bs = bytes / nz(s); 113035699Sbostic printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n", 113135699Sbostic bytes, direction, s, bs / 1024.); 113235699Sbostic } 113310296Ssam } 113410296Ssam 113526496Sminshall /*tvadd(tsum, t0) 113610296Ssam struct timeval *tsum, *t0; 113710296Ssam { 113810296Ssam 113910296Ssam tsum->tv_sec += t0->tv_sec; 114010296Ssam tsum->tv_usec += t0->tv_usec; 114110296Ssam if (tsum->tv_usec > 1000000) 114210296Ssam tsum->tv_sec++, tsum->tv_usec -= 1000000; 114326496Sminshall } */ 114410296Ssam 114510296Ssam tvsub(tdiff, t1, t0) 114610296Ssam struct timeval *tdiff, *t1, *t0; 114710296Ssam { 114810296Ssam 114910296Ssam tdiff->tv_sec = t1->tv_sec - t0->tv_sec; 115010296Ssam tdiff->tv_usec = t1->tv_usec - t0->tv_usec; 115110296Ssam if (tdiff->tv_usec < 0) 115210296Ssam tdiff->tv_sec--, tdiff->tv_usec += 1000000; 115310296Ssam } 115426048Sminshall 115526048Sminshall psabort() 115626048Sminshall { 115726048Sminshall extern int abrtflag; 115826048Sminshall 115926048Sminshall abrtflag++; 116026048Sminshall } 116126048Sminshall 116226048Sminshall pswitch(flag) 116326048Sminshall int flag; 116426048Sminshall { 116526048Sminshall extern int proxy, abrtflag; 116626048Sminshall int (*oldintr)(); 116726048Sminshall static struct comvars { 116826048Sminshall int connect; 116928469Skarels char name[MAXHOSTNAMELEN]; 117026048Sminshall struct sockaddr_in mctl; 117126048Sminshall struct sockaddr_in hctl; 117226048Sminshall FILE *in; 117326048Sminshall FILE *out; 117426048Sminshall int tpe; 117526048Sminshall int cpnd; 117626048Sminshall int sunqe; 117726048Sminshall int runqe; 117826048Sminshall int mcse; 117926048Sminshall int ntflg; 118026048Sminshall char nti[17]; 118126048Sminshall char nto[17]; 118226048Sminshall int mapflg; 118326048Sminshall char mi[MAXPATHLEN]; 118426048Sminshall char mo[MAXPATHLEN]; 118526048Sminshall } proxstruct, tmpstruct; 118626048Sminshall struct comvars *ip, *op; 118726048Sminshall 118826048Sminshall abrtflag = 0; 118926048Sminshall oldintr = signal(SIGINT, psabort); 119026048Sminshall if (flag) { 119126448Slepreau if (proxy) 119226048Sminshall return; 119326048Sminshall ip = &tmpstruct; 119426048Sminshall op = &proxstruct; 119526048Sminshall proxy++; 119626048Sminshall } 119726048Sminshall else { 119826448Slepreau if (!proxy) 119926048Sminshall return; 120026048Sminshall ip = &proxstruct; 120126048Sminshall op = &tmpstruct; 120226048Sminshall proxy = 0; 120326048Sminshall } 120426048Sminshall ip->connect = connected; 120526048Sminshall connected = op->connect; 120628469Skarels if (hostname) { 120728469Skarels (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1); 120828469Skarels ip->name[strlen(ip->name)] = '\0'; 120928469Skarels } else 121028469Skarels ip->name[0] = 0; 121126048Sminshall hostname = op->name; 121226048Sminshall ip->hctl = hisctladdr; 121326048Sminshall hisctladdr = op->hctl; 121426048Sminshall ip->mctl = myctladdr; 121526048Sminshall myctladdr = op->mctl; 121626048Sminshall ip->in = cin; 121726048Sminshall cin = op->in; 121826048Sminshall ip->out = cout; 121926048Sminshall cout = op->out; 122026048Sminshall ip->tpe = type; 122126048Sminshall type = op->tpe; 122226448Slepreau if (!type) 122326048Sminshall type = 1; 122426048Sminshall ip->cpnd = cpend; 122526048Sminshall cpend = op->cpnd; 122626048Sminshall ip->sunqe = sunique; 122726048Sminshall sunique = op->sunqe; 122826048Sminshall ip->runqe = runique; 122926048Sminshall runique = op->runqe; 123026048Sminshall ip->mcse = mcase; 123126048Sminshall mcase = op->mcse; 123226048Sminshall ip->ntflg = ntflag; 123326048Sminshall ntflag = op->ntflg; 123426496Sminshall (void) strncpy(ip->nti, ntin, 16); 123526048Sminshall (ip->nti)[strlen(ip->nti)] = '\0'; 123626496Sminshall (void) strcpy(ntin, op->nti); 123726496Sminshall (void) strncpy(ip->nto, ntout, 16); 123826048Sminshall (ip->nto)[strlen(ip->nto)] = '\0'; 123926496Sminshall (void) strcpy(ntout, op->nto); 124026048Sminshall ip->mapflg = mapflag; 124126048Sminshall mapflag = op->mapflg; 124226496Sminshall (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1); 124326048Sminshall (ip->mi)[strlen(ip->mi)] = '\0'; 124426496Sminshall (void) strcpy(mapin, op->mi); 124526496Sminshall (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1); 124626048Sminshall (ip->mo)[strlen(ip->mo)] = '\0'; 124726496Sminshall (void) strcpy(mapout, op->mo); 124826048Sminshall (void) signal(SIGINT, oldintr); 124926048Sminshall if (abrtflag) { 125026048Sminshall abrtflag = 0; 125126048Sminshall (*oldintr)(); 125226448Slepreau } 125326048Sminshall } 125426048Sminshall 125526048Sminshall jmp_buf ptabort; 125626048Sminshall int ptabflg; 125726048Sminshall 125826048Sminshall abortpt() 125926048Sminshall { 126026048Sminshall printf("\n"); 126126496Sminshall (void) fflush(stdout); 126226048Sminshall ptabflg++; 126326048Sminshall mflag = 0; 126426048Sminshall abrtflag = 0; 126526048Sminshall longjmp(ptabort, 1); 126626048Sminshall } 126726048Sminshall 126826048Sminshall proxtrans(cmd, local, remote) 126926048Sminshall char *cmd, *local, *remote; 127026048Sminshall { 127127687Sminshall int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd; 127226048Sminshall extern jmp_buf ptabort; 127326048Sminshall char *cmd2; 127426496Sminshall struct fd_set mask; 127526048Sminshall 127626448Slepreau if (strcmp(cmd, "RETR")) 127726048Sminshall cmd2 = "RETR"; 127826448Slepreau else 127926048Sminshall cmd2 = runique ? "STOU" : "STOR"; 128026048Sminshall if (command("PASV") != COMPLETE) { 128126048Sminshall printf("proxy server does not support third part transfers.\n"); 128226048Sminshall return; 128326048Sminshall } 128426048Sminshall tmptype = type; 128526048Sminshall pswitch(0); 128626048Sminshall if (!connected) { 128726048Sminshall printf("No primary connection\n"); 128826048Sminshall pswitch(1); 128926048Sminshall code = -1; 129026048Sminshall return; 129126048Sminshall } 129226048Sminshall if (type != tmptype) { 129326048Sminshall oldtype = type; 129426048Sminshall switch (tmptype) { 129526048Sminshall case TYPE_A: 129626048Sminshall setascii(); 129726048Sminshall break; 129826048Sminshall case TYPE_I: 129926048Sminshall setbinary(); 130026048Sminshall break; 130126048Sminshall case TYPE_E: 130226048Sminshall setebcdic(); 130326048Sminshall break; 130426048Sminshall case TYPE_L: 130526048Sminshall settenex(); 130626048Sminshall break; 130726048Sminshall } 130826048Sminshall } 130926048Sminshall if (command("PORT %s", pasv) != COMPLETE) { 131026048Sminshall switch (oldtype) { 131126048Sminshall case 0: 131226048Sminshall break; 131326048Sminshall case TYPE_A: 131426048Sminshall setascii(); 131526048Sminshall break; 131626048Sminshall case TYPE_I: 131726048Sminshall setbinary(); 131826048Sminshall break; 131926048Sminshall case TYPE_E: 132026048Sminshall setebcdic(); 132126048Sminshall break; 132226048Sminshall case TYPE_L: 132326048Sminshall settenex(); 132426048Sminshall break; 132526048Sminshall } 132626048Sminshall pswitch(1); 132726048Sminshall return; 132826048Sminshall } 132926448Slepreau if (setjmp(ptabort)) 133026048Sminshall goto abort; 133126048Sminshall oldintr = signal(SIGINT, abortpt); 133226048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 133326048Sminshall (void) signal(SIGINT, oldintr); 133426048Sminshall switch (oldtype) { 133526048Sminshall case 0: 133626048Sminshall break; 133726048Sminshall case TYPE_A: 133826048Sminshall setascii(); 133926048Sminshall break; 134026048Sminshall case TYPE_I: 134126048Sminshall setbinary(); 134226048Sminshall break; 134326048Sminshall case TYPE_E: 134426048Sminshall setebcdic(); 134526048Sminshall break; 134626048Sminshall case TYPE_L: 134726048Sminshall settenex(); 134826048Sminshall break; 134926048Sminshall } 135026048Sminshall pswitch(1); 135126048Sminshall return; 135226048Sminshall } 135326048Sminshall sleep(2); 135426048Sminshall pswitch(1); 135526048Sminshall secndflag++; 135626448Slepreau if (command("%s %s", cmd2, local) != PRELIM) 135726048Sminshall goto abort; 135826048Sminshall ptflag++; 135926048Sminshall (void) getreply(0); 136026048Sminshall pswitch(0); 136126048Sminshall (void) getreply(0); 136226048Sminshall (void) signal(SIGINT, oldintr); 136326048Sminshall switch (oldtype) { 136426048Sminshall case 0: 136526048Sminshall break; 136626048Sminshall case TYPE_A: 136726048Sminshall setascii(); 136826048Sminshall break; 136926048Sminshall case TYPE_I: 137026048Sminshall setbinary(); 137126048Sminshall break; 137226048Sminshall case TYPE_E: 137326048Sminshall setebcdic(); 137426048Sminshall break; 137526048Sminshall case TYPE_L: 137626048Sminshall settenex(); 137726048Sminshall break; 137826048Sminshall } 137926048Sminshall pswitch(1); 138026048Sminshall ptflag = 0; 138126048Sminshall printf("local: %s remote: %s\n", local, remote); 138226048Sminshall return; 138326048Sminshall abort: 138426048Sminshall (void) signal(SIGINT, SIG_IGN); 138526048Sminshall ptflag = 0; 138626448Slepreau if (strcmp(cmd, "RETR") && !proxy) 138726048Sminshall pswitch(1); 138826448Slepreau else if (!strcmp(cmd, "RETR") && proxy) 138926048Sminshall pswitch(0); 139026048Sminshall if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ 139126048Sminshall if (command("%s %s", cmd2, local) != PRELIM) { 139226048Sminshall pswitch(0); 139326048Sminshall switch (oldtype) { 139426048Sminshall case 0: 139526048Sminshall break; 139626048Sminshall case TYPE_A: 139726048Sminshall setascii(); 139826048Sminshall break; 139926048Sminshall case TYPE_I: 140026048Sminshall setbinary(); 140126048Sminshall break; 140226048Sminshall case TYPE_E: 140326048Sminshall setebcdic(); 140426048Sminshall break; 140526048Sminshall case TYPE_L: 140626048Sminshall settenex(); 140726048Sminshall break; 140826048Sminshall } 140927687Sminshall if (cpend) { 141026048Sminshall char msg[2]; 141126048Sminshall 141226048Sminshall fprintf(cout,"%c%c",IAC,IP); 141326048Sminshall (void) fflush(cout); 141426048Sminshall *msg = IAC; 141526048Sminshall *(msg+1) = DM; 141626448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 141726048Sminshall perror("abort"); 141826048Sminshall fprintf(cout,"ABOR\r\n"); 141926048Sminshall (void) fflush(cout); 142027687Sminshall FD_ZERO(&mask); 142126496Sminshall FD_SET(fileno(cin), &mask); 142227687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 142327687Sminshall if (nfnd < 0) { 142427687Sminshall perror("abort"); 142527687Sminshall } 142626448Slepreau if (ptabflg) 142726048Sminshall code = -1; 142826048Sminshall lostpeer(); 142926048Sminshall } 143026048Sminshall (void) getreply(0); 143126048Sminshall (void) getreply(0); 143226048Sminshall } 143326048Sminshall } 143426048Sminshall pswitch(1); 143526448Slepreau if (ptabflg) 143626048Sminshall code = -1; 143726048Sminshall (void) signal(SIGINT, oldintr); 143826048Sminshall return; 143926048Sminshall } 144027687Sminshall if (cpend) { 144126048Sminshall char msg[2]; 144226048Sminshall 144326048Sminshall fprintf(cout,"%c%c",IAC,IP); 144426048Sminshall (void) fflush(cout); 144526048Sminshall *msg = IAC; 144626048Sminshall *(msg+1) = DM; 144726448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 144826048Sminshall perror("abort"); 144926048Sminshall fprintf(cout,"ABOR\r\n"); 145026048Sminshall (void) fflush(cout); 145127687Sminshall FD_ZERO(&mask); 145226496Sminshall FD_SET(fileno(cin), &mask); 145327687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 145427687Sminshall if (nfnd < 0) { 145527687Sminshall perror("abort"); 145627687Sminshall } 145726448Slepreau if (ptabflg) 145826048Sminshall code = -1; 145926048Sminshall lostpeer(); 146026048Sminshall } 146126048Sminshall (void) getreply(0); 146226048Sminshall (void) getreply(0); 146326048Sminshall } 146426048Sminshall pswitch(!proxy); 146526048Sminshall if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ 146626048Sminshall if (command("%s %s", cmd2, local) != PRELIM) { 146726048Sminshall pswitch(0); 146826048Sminshall switch (oldtype) { 146926048Sminshall case 0: 147026048Sminshall break; 147126048Sminshall case TYPE_A: 147226048Sminshall setascii(); 147326048Sminshall break; 147426048Sminshall case TYPE_I: 147526048Sminshall setbinary(); 147626048Sminshall break; 147726048Sminshall case TYPE_E: 147826048Sminshall setebcdic(); 147926048Sminshall break; 148026048Sminshall case TYPE_L: 148126048Sminshall settenex(); 148226048Sminshall break; 148326048Sminshall } 148427687Sminshall if (cpend) { 148526048Sminshall char msg[2]; 148626048Sminshall 148726048Sminshall fprintf(cout,"%c%c",IAC,IP); 148826048Sminshall (void) fflush(cout); 148926048Sminshall *msg = IAC; 149026048Sminshall *(msg+1) = DM; 149126448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 149226048Sminshall perror("abort"); 149326048Sminshall fprintf(cout,"ABOR\r\n"); 149426048Sminshall (void) fflush(cout); 149527687Sminshall FD_ZERO(&mask); 149626496Sminshall FD_SET(fileno(cin), &mask); 149727687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 149827687Sminshall if (nfnd < 0) { 149927687Sminshall perror("abort"); 150027687Sminshall } 150126448Slepreau if (ptabflg) 150226048Sminshall code = -1; 150326048Sminshall lostpeer(); 150426048Sminshall } 150526048Sminshall (void) getreply(0); 150626048Sminshall (void) getreply(0); 150726048Sminshall } 150826048Sminshall pswitch(1); 150926448Slepreau if (ptabflg) 151026048Sminshall code = -1; 151126048Sminshall (void) signal(SIGINT, oldintr); 151226048Sminshall return; 151326048Sminshall } 151426048Sminshall } 151527687Sminshall if (cpend) { 151626048Sminshall char msg[2]; 151726048Sminshall 151826048Sminshall fprintf(cout,"%c%c",IAC,IP); 151926048Sminshall (void) fflush(cout); 152026048Sminshall *msg = IAC; 152126048Sminshall *(msg+1) = DM; 152226448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 152326048Sminshall perror("abort"); 152426048Sminshall fprintf(cout,"ABOR\r\n"); 152526048Sminshall (void) fflush(cout); 152627687Sminshall FD_ZERO(&mask); 152726496Sminshall FD_SET(fileno(cin), &mask); 152827687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 152927687Sminshall if (nfnd < 0) { 153027687Sminshall perror("abort"); 153127687Sminshall } 153226448Slepreau if (ptabflg) 153326048Sminshall code = -1; 153426048Sminshall lostpeer(); 153526048Sminshall } 153626048Sminshall (void) getreply(0); 153726048Sminshall (void) getreply(0); 153826048Sminshall } 153926048Sminshall pswitch(!proxy); 154026048Sminshall if (cpend) { 154127687Sminshall FD_ZERO(&mask); 154226496Sminshall FD_SET(fileno(cin), &mask); 154327687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 154427687Sminshall if (nfnd < 0) { 154527687Sminshall perror("abort"); 154627687Sminshall } 154726448Slepreau if (ptabflg) 154826048Sminshall code = -1; 154926048Sminshall lostpeer(); 155026048Sminshall } 155126048Sminshall (void) getreply(0); 155226048Sminshall (void) getreply(0); 155326048Sminshall } 155426448Slepreau if (proxy) 155526048Sminshall pswitch(0); 155626048Sminshall switch (oldtype) { 155726048Sminshall case 0: 155826048Sminshall break; 155926048Sminshall case TYPE_A: 156026048Sminshall setascii(); 156126048Sminshall break; 156226048Sminshall case TYPE_I: 156326048Sminshall setbinary(); 156426048Sminshall break; 156526048Sminshall case TYPE_E: 156626048Sminshall setebcdic(); 156726048Sminshall break; 156826048Sminshall case TYPE_L: 156926048Sminshall settenex(); 157026048Sminshall break; 157126048Sminshall } 157226048Sminshall pswitch(1); 157326448Slepreau if (ptabflg) 157426048Sminshall code = -1; 157526048Sminshall (void) signal(SIGINT, oldintr); 157626048Sminshall } 157726048Sminshall 157826048Sminshall reset() 157926048Sminshall { 158026496Sminshall struct fd_set mask; 158126496Sminshall int nfnd = 1; 158226048Sminshall 158327687Sminshall FD_ZERO(&mask); 158430946Scsvsj while (nfnd > 0) { 158526496Sminshall FD_SET(fileno(cin), &mask); 158627687Sminshall if ((nfnd = empty(&mask,0)) < 0) { 158726048Sminshall perror("reset"); 158826048Sminshall code = -1; 158926048Sminshall lostpeer(); 159026048Sminshall } 159127687Sminshall else if (nfnd) { 159226048Sminshall (void) getreply(0); 159326496Sminshall } 159426048Sminshall } 159526048Sminshall } 159626048Sminshall 159726048Sminshall char * 159826048Sminshall gunique(local) 159926048Sminshall char *local; 160026048Sminshall { 160126048Sminshall static char new[MAXPATHLEN]; 160226048Sminshall char *cp = rindex(local, '/'); 160326048Sminshall int d, count=0; 160426048Sminshall char ext = '1'; 160526048Sminshall 160626448Slepreau if (cp) 160726048Sminshall *cp = '\0'; 160826048Sminshall d = access(cp ? local : ".", 2); 160926448Slepreau if (cp) 161026048Sminshall *cp = '/'; 161126048Sminshall if (d < 0) { 161226048Sminshall perror(local); 161326048Sminshall return((char *) 0); 161426048Sminshall } 161526048Sminshall (void) strcpy(new, local); 161626048Sminshall cp = new + strlen(new); 161726048Sminshall *cp++ = '.'; 161826048Sminshall while (!d) { 161926048Sminshall if (++count == 100) { 162026048Sminshall printf("runique: can't find unique file name.\n"); 162126048Sminshall return((char *) 0); 162226048Sminshall } 162326048Sminshall *cp++ = ext; 162426048Sminshall *cp = '\0'; 162526448Slepreau if (ext == '9') 162626048Sminshall ext = '0'; 162726448Slepreau else 162826048Sminshall ext++; 162926448Slepreau if ((d = access(new, 0)) < 0) 163026048Sminshall break; 163126448Slepreau if (ext != '0') 163226048Sminshall cp--; 163326448Slepreau else if (*(cp - 2) == '.') 163426048Sminshall *(cp - 1) = '1'; 163526048Sminshall else { 163626048Sminshall *(cp - 2) = *(cp - 2) + 1; 163726048Sminshall cp--; 163826048Sminshall } 163926048Sminshall } 164026048Sminshall return(new); 164126048Sminshall } 1642