/* Routines common to both the FTP client and server * Copyright 1991 Phil Karn, KA9Q */ #include #include "global.h" #include "mbuf.h" #include "socket.h" #include "proc.h" #include "ftp.h" /* Send a file (opened by caller) on a network socket. * Normal return: count of bytes sent * Error return: -1 */ long sendfile(fp,s,mode,hash) FILE *fp; /* File to be sent */ int s; /* Socket to be sent on */ int mode; /* Transfer mode */ int hash; /* Print hash marks every BLKSIZE bytes */ { register struct mbuf *bp; int c,oldf; long total = 0; long hmark = 0; switch(mode){ default: case LOGICAL_TYPE: case IMAGE_TYPE: sockmode(s,SOCK_BINARY); for(;;){ bp = ambufw(BLKSIZE); if((bp->cnt = fread(bp->data,1,BLKSIZE,fp)) == 0){ free_p(bp); break; } total += bp->cnt; if(send_mbuf(s,bp,0,NULLCHAR,0) == -1){ total = -1; break; } while(hash && total >= hmark+1000){ tputc('#'); hmark += 1000; } } break; case ASCII_TYPE: oldf = setflush(s,-1); /* Let the newline mapping code in usputc() do the work */ sockmode(s,SOCK_ASCII); while((c = getc(fp)) != EOF){ #if !defined(UNIX) && !defined(__TURBOC__) if(c == '\r'){ /* Needed only if the OS uses a CR/LF * convention and getc doesn't do * an automatic translation */ continue; } #endif if(usputc(s,(char)c) == -1){ total = -1; break; } total++; while(hash && total >= hmark+1000){ tputc('#'); hmark += 1000; } } usflush(s); setflush(s,oldf); break; } if(hash) tputc('\n'); return total; } /* Receive a file (opened by caller) from a network socket. * Normal return: count of bytes received * Error return: -1 */ long recvfile(fp,s,mode,hash) FILE *fp; int s; int mode; int hash; { int cnt,c; struct mbuf *bp; long total = 0; long hmark = 0; switch(mode){ default: case LOGICAL_TYPE: case IMAGE_TYPE: sockmode(s,SOCK_BINARY); while((cnt = recv_mbuf(s,&bp,0,NULLCHAR,0)) != 0){ if(cnt == -1){ total = -1; break; } total += cnt; while(hash && total >= hmark+1000){ tputc('#'); hmark += 1000; } if(fp != NULLFILE){ if(write_p(fp,bp) == -1){ free_p(bp); total = -1; break; } free_p(bp); } else { send_mbuf(Curproc->output, bp, 0, NULLCHAR, 0); } } break; case ASCII_TYPE: sockmode(s,SOCK_ASCII); while((c = recvchar(s)) != EOF){ if(fp != NULLFILE){ #if !defined(UNIX) && !defined(__TURBOC__) && !defined(AMIGA) if(c == '\n'){ /* Needed only if the OS uses a CR/LF * convention and putc doesn't do * an automatic translation */ putc('\r',fp); } #endif if(putc(c,fp) == EOF){ total = -1; break; } } else { tputc((char)c); } total++; while(hash && total >= hmark+1000){ tputc('#'); hmark += 1000; } } /* Detect an abnormal close */ if(socklen(s,0) == -1) total = -1; break; } if(hash) tputc('\n'); return total; } /* Determine if a file appears to be binary (i.e., non-text). * Return 1 if binary, 0 if ascii text after rewinding the file pointer. * * Used by FTP to warn users when transferring a binary file in text mode. */ int isbinary(fp) FILE *fp; { int c,i; int rval; rval = 0; for(i=0;i<512;i++){ if((c = getc(fp)) == EOF) break; if(c & 0x80){ /* High bit is set, probably not text */ rval = 1; break; } } /* Assume it was at beginning */ fseek(fp,0L,SEEK_SET); return rval; }