/* file.c
 *
 * This file is part of ftp.
 *
 *
 * 01/25/96 Initial Release	Michael Temari, <temari@ix.netcom.com>
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>

#include "ftp.h"
#include "file.h"
#include "net.h"

_PROTOTYPE(static char *dir, (char *path, int full));
_PROTOTYPE(static int asciisend, (int fd, int fdout));
_PROTOTYPE(static int binarysend, (int fd, int fdout));
_PROTOTYPE(static int asciirecv, (int fd, int fdin));
_PROTOTYPE(static int binaryrecv, (int fd, int fdin));

static char buffer[8192];
static char line2[512];

static char *dir(path, full)
char *path;
int full;
{
char cmd[128];
static char name[32];

   tmpnam(name);

   if(full)
	sprintf(cmd, "ls -l %s > %s", path, name);
   else
	sprintf(cmd, "ls %s > %s", path, name);

   system(cmd);

   return(name);
}

static int asciisend(fd, fdout)
int fd;
int fdout;
{
int s, len;
char *p, *pp;
long total=0L;

   if(atty) {
	printf("Sent ");
	fflush(stdout);
   }

   while((s = read(fd, buffer, sizeof(buffer))) > 0) {
	total += (long)s;
	p = buffer;
	while(s > 0) {
		if((pp = memchr(p, '\n', s)) == (char *)NULL) {
			write(fdout, p, s);
			break;
		}
		len = pp - p;
		if(len > 0)
			write(fdout, p, len);
		write(fdout, "\r\n", 2);
		p = pp + 1;
		s = s - len - 1;
	}
	if(atty) {
		printf("%8ld bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
		fflush(stdout);
	}
   }
   if(atty) {
	printf("\n");
	fflush(stdout);
   }

   return(s);
}

static int binarysend(fd, fdout)
int fd;
int fdout;
{
int s;
long total=0L;

   if(atty) {
	printf("Sent ");
	fflush(stdout);
   }

   while((s = read(fd, buffer, sizeof(buffer))) > 0) {
	write(fdout, buffer, s);
	total += (long)s;
	if(atty) {
		printf("%8ld bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
		fflush(stdout);
	}
   }
   if(atty) {
	printf("\n");
	fflush(stdout);
   }

   return(s);
}

int sendfile(fd, fdout)
int fd;
int fdout;
{
int s;

   switch(type) {
	case TYPE_A:
		s = asciisend(fd, fdout);
		break;
	default:
		s = binarysend(fd, fdout);
   }

   if(s < 0)
	return(-1);
   else
	return(0);
}

static int asciirecv(fd, fdin)
int fd;
int fdin;
{
int s, len;
int gotcr;
char *p, *pp;
long total=0L;

   if(isatty && fd > 2) {
	printf("Received ");
	fflush(stdout);
   }
   gotcr = 0;
   while((s = read(fdin, buffer, sizeof(buffer))) > 0) {
	p = buffer;
	total += (long)s;
	if(gotcr) {
		gotcr = 0;
		if(*p != '\n')
			write(fd, "\r", 1);
	}
	while(s > 0) {
		if((pp = memchr(p, '\r', s)) == (char *)NULL) {
			write(fd, p, s);
			break;
		}
		len = pp - p;
		if(len > 0)
			write(fd, p, len);
		p = pp + 1;
		s = s - len - 1;
		if(s == 0) {
			gotcr = 1;
			break;
		}
		if(*p != '\n')
			write(fd, "\r", 1);
	}
	if(atty && fd > 2) {
		printf("%8ld bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
		fflush(stdout);
	}
   }
   if(gotcr)
	write(fd, "\r", 1);
   if(atty && fd > 2) {
	printf("\n");
	fflush(stdout);
   }
   return(s);
}

static binaryrecv(fd, fdin)
int fd;
int fdin;
{
int s;
long total=0L;

   if(atty && fd > 2) {
	printf("Received ");
	fflush(stdout);
   }
   while((s = read(fdin, buffer, sizeof(buffer))) > 0) {
	write(fd, buffer, s);
	total += (long)s;
	if(atty && fd > 2) {
		printf("%8ld bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
		fflush(stdout);
	}
   }
   if(atty && fd > 2) {
	printf("\n");
	fflush(stdout);
   }
   return(s);
}

int recvfile(fd, fdin)
int fd;
int fdin;
{
int s;

   switch(type) {
	case TYPE_A:
		s = asciirecv(fd, fdin);
		break;
	default:
		s = binaryrecv(fd, fdin);
   }

   if(s < 0)
	return(-1);
   else
	return(0);
}

int DOascii()
{
int s;

   if(DOcmdcheck())
	return(0);

   s = DOcommand("TYPE", "A");

   type = TYPE_A;

   return(s);
}

int DObinary()
{
int s;

   if(DOcmdcheck())
	return(0);

   s = DOcommand("TYPE", "I");

   type = TYPE_I;

   return(s);
}

int DOpwd()
{
int s;

   if(DOcmdcheck())
	return(0);

   s = DOcommand("PWD", "");

   if(s == 500 || s == 502)
	s = DOcommand("XPWD", "");

   return(s);
}

int DOcd()
{
char *path;
int s;

   if(DOcmdcheck())
	return(0);

   path = cmdargv[1];

   if(cmdargc < 2) {
	readline("Path: ", line2, sizeof(line2));
	path = line2;
   }

   if(!strcmp(path, ".."))
   	s = DOcommand("CDUP", "");
   else
   	s = DOcommand("CWD", path);

   if(s == 500 || s == 502) {
	if(!strcmp(path, ".."))
		s = DOcommand("XCUP", "");
	else
		s = DOcommand("XCWD", path);
   }

   return(s);
}

int DOmkdir()
{
char *path;
int s;

   if(DOcmdcheck())
	return(0);

   path = cmdargv[1];

   if(cmdargc < 2) {
	readline("Directory: ", line2, sizeof(line2));
	path = line2;
   }

   s = DOcommand("MKD", path);

   if(s == 500 || s == 502)
	s = DOcommand("XMKD", path);

   return(s);
}

int DOrmdir()
{
char *path;
int s;

   if(DOcmdcheck())
	return(0);

   path = cmdargv[1];

   if(cmdargc < 2) {
	readline("Directory: ", line2, sizeof(line2));
	path = line2;
   }

   s = DOcommand("RMD", path);

   if(s == 500 || s == 502)
	s = DOcommand("XRMD", path);

   return(s);
}

int DOdelete()
{
char *file;

   if(DOcmdcheck())
	return(0);

   file = cmdargv[1];

   if(cmdargc < 2) {
	readline("File: ", line2, sizeof(line2));
	file = line2;
   }

   return(DOcommand("DELE", file));
}

int DOmdtm()
{
char *file;

   if(DOcmdcheck())
	return(0);

   file = cmdargv[1];

   if(cmdargc < 2) {
	readline("File: ", line2, sizeof(line2));
	file = line2;
   }

   return(DOcommand("MDTM", file));
}

int DOsize()
{
char *file;

   if(DOcmdcheck())
	return(0);

   file = cmdargv[1];

   if(cmdargc < 2) {
	readline("File: ", line2, sizeof(line2));
	file = line2;
   }

   return(DOcommand("SIZE", file));
}

int DOstat()
{
char *file;

   if(cmdargc < 2)
	if(!linkopen) {
		printf("You must \"OPEN\" a connection first.\n");
		return(0);
	} else
		return(DOcommand("STAT", ""));

   if(DOcmdcheck())
	return(0);

   file = cmdargv[1];

   if(cmdargc < 2) {
	readline("File: ", line2, sizeof(line2));
	file = line2;
   }

   return(DOcommand("STAT", file));
}

int DOlist()
{
char *path;
char *local;
int fd;
int s;

   if(DOcmdcheck())
	return(0);

   path = cmdargv[1];

   if(cmdargc < 2)
	path = "";

   if(cmdargc < 3)
	local = "";
   else
	local = cmdargv[2];

   if(*local == '\0')
	fd = 1;
   else
	fd = open(local, O_WRONLY | O_CREAT | O_TRUNC, 0666);

   if(fd < 0) {
	printf("Could not open local file %s. Error %s\n", local, strerror(errno));
	return(0);
   }

   s = DOdata("LIST", path, RETR, fd);

   if(fd > 2)
	close(fd);

   return(s);
}

int DOnlst()
{
char *path;
char *local;
int fd;
int s;

   if(DOcmdcheck())
	return(0);

   path = cmdargv[1];

   if(cmdargc < 2)
	path = "";

   if(cmdargc < 3)
	local = "";
   else
	local = cmdargv[2];

   if(*local == '\0')
	fd = 1;
   else
	fd = open(local, O_WRONLY | O_CREAT | O_TRUNC, 0666);

   if(fd < 0) {
	printf("Could not open local file %s. Error %s\n", local, strerror(errno));
	return(0);
   }

   s = DOdata("NLST", path, RETR, fd);

   if(fd > 2)
	close(fd);

   return(s);
}

int DOretr()
{
char *file, *localfile;
int fd;
int s;

   if(DOcmdcheck())
	return(0);

   file = cmdargv[1];

   if(cmdargc < 2) {
	readline("Remote File: ", line2, sizeof(line2));
	file = line2;
   }

   if(cmdargc < 3)
	localfile = file;
   else
	localfile = cmdargv[2];

   fd = open(localfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);

   if(fd < 0) {
	printf("Could not open local file %s. Error %s\n", localfile, strerror(errno));
	return(0);
   }

   s = DOdata("RETR", file, RETR, fd);

   close(fd);

   return(s);
}

int DOMretr()
{
char *files;
int fd, s;
FILE *fp;
char name[32];

   if(DOcmdcheck())
	return(0);

   files = cmdargv[1];

   if(cmdargc < 2) {
	readline("Files: ", line2, sizeof(line2));
	files = line2;
   }

   tmpnam(name);

   fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666);

   if(fd < 0) {
	printf("Could not open local file %s. Error %s\n", name, strerror(errno));
	return(0);
   }

   s = DOdata("NLST", files, RETR, fd);

   close(fd);

   if(s == 226) {
	fp = fopen(name, "r");
	unlink(name);
	if(fp == (FILE *)NULL) {
		printf("Unable to open file listing.\n");
		return(0);
	}
	while(fgets(line2, sizeof(line2), fp) != (char *)NULL) {
		line2[strlen(line2)-1] = '\0';
		printf("Retrieving file: %s\n", line2); fflush(stdout);
		fd = open(line2, O_WRONLY | O_CREAT | O_TRUNC, 0666);
		if(fd < 0)
			printf("Unable to open local file %s\n", line2);
		else {
			s = DOdata("RETR", line2, RETR, fd);
			close(fd);
			if(s < 0) break;
		}
	}
	fclose(fp);
   } else
	unlink(name);

   return(s);
}

int DOappe()
{
char *file, *remotefile;
int fd;
int s;

   if(DOcmdcheck())
	return(0);

   file = cmdargv[1];

   if(cmdargc < 2) {
	readline("Local File: ", line2, sizeof(line2));
	file = line2;
   }

   if(cmdargc < 3)
	remotefile = file;
   else
	remotefile = cmdargv[2];

   fd = open(file, O_RDONLY);

   if(fd < 0) {
	printf("Could not open local file %s. Error %s\n", file, strerror(errno));
	return(0);
   }

   s = DOdata("APPE", remotefile, STOR, fd);

   close(fd);

   return(s);
}

int DOstor()
{
char *file, *remotefile;
int fd;
int s;

   if(DOcmdcheck())
	return(0);

   file = cmdargv[1];

   if(cmdargc < 2) {
	readline("Local File: ", line2, sizeof(line2));
	file = line2;
   }

   if(cmdargc < 3)
	remotefile = file;
   else
	remotefile = cmdargv[2];

   fd = open(file, O_RDONLY);

   if(fd < 0) {
	printf("Could not open local file %s. Error %s\n", file, strerror(errno));
	return(0);
   }

   s = DOdata("STOR", remotefile, STOR, fd);

   close(fd);

   return(s);
}

int DOstou()
{
char *file, *remotefile;
int fd;
int s;

   if(DOcmdcheck())
	return(0);

   file = cmdargv[1];

   if(cmdargc < 2) {
	readline("Local File: ", line2, sizeof(line2));
	file = line2;
   }

   if(cmdargc < 3)
	remotefile = file;
   else
	remotefile = cmdargv[2];

   fd = open(file, O_RDONLY);

   if(fd < 0) {
	printf("Could not open local file %s. Error %s\n", file, strerror(errno));
	return(0);
   }

   s = DOdata("STOU", remotefile, STOR, fd);

   close(fd);

   return(s);
}

int DOMstor()
{
char *files;
char *name;
int fd, s;
FILE *fp;

   if(DOcmdcheck())
	return(0);

   files = cmdargv[1];

   if(cmdargc < 2) {
	readline("Files: ", line2, sizeof(line2));
	files = line2;
   }

   name = dir(files, 0);

   fp = fopen(name, "r");

   if(fp == (FILE *)NULL) {
	printf("Unable to open listing file.\n");
	return(0);
   }

   while(fgets(line2, sizeof(line2), fp) != (char *)NULL) {
	line2[strlen(line2)-1] = '\0';
	printf("Sending file: %s\n", line2); fflush(stdout);
	fd = open(line2, O_RDONLY);
	if(fd < 0)
		printf("Unable to open local file %s\n", line2);
	else {
		s = DOdata("STOR", line2, STOR, fd);
		close(fd);
		if(s < 0) break;
	}
   }
   fclose(fp);
   unlink(name);

   return(s);
}
