/* Stuff common to both the FTP server and client */
#include <stdio.h>
#include "machdep.h"
#include "mbuf.h"
#include "netuser.h"
#include "timer.h"
#include "tcp.h"
#include "ftp.h"
#include "session.h"

#ifdef	AMIGA
#define	UNIX	1	/* UNIX semantics work for Amiga in this module */
#endif

/* FTP data channel receive upcall handler */
void
r_ftpd(tcb,cnt)
struct tcb *tcb;
int16 cnt;
{
	register struct ftp *ftp;
	struct mbuf *bp;
#ifdef	UNIX
	char c;
#endif

	ftp = (struct ftp *)tcb->user;
	if(ftp->state != RECEIVING_STATE){
		close_tcp(tcb);
		return;
	}
	/* This will likely also generate an ACK with window rotation */
	recv_tcp(tcb,&bp,cnt);

#ifdef	UNIX
	while(pullup(&bp,&c,1) == 1){
		if(ftp->type == IMAGE_TYPE || c != '\r')
			putc(c,ftp->fp);
	}
#else
	while(bp != NULLBUF){
		if(bp->cnt != 0)
			fwrite(bp->data,1,(unsigned)bp->cnt,ftp->fp);
		bp = free_mbuf(bp);
	}
#endif
}
/* FTP data channel transmit upcall handler */
void
t_ftpd(tcb,cnt)
struct tcb *tcb;
int16 cnt;
{
	struct ftp *ftp;
	struct mbuf *bp;
	char *cp;
	int c;
#ifndef	CPM
#ifndef	AMIGA
	char *cdsave,*pwd();
#endif
#endif

	ftp = (struct ftp *)tcb->user;
	if(ftp->state != SENDING_STATE){
		close_tcp(tcb);
		return;
	}
	if((bp = alloc_mbuf(cnt)) == NULLBUF){
		/* Hard to know what to do here */
		return;
	}
	cp = bp->data;
	while(cnt > 1 && (c = getc(ftp->fp)) != EOF){
#ifdef	CPM
		if(ftp->type == ASCII_TYPE && c == CTLZ)
			break;	/* CTLZ is CP/M's text EOF marker */
#endif
#ifdef	UNIX
		if(ftp->type == ASCII_TYPE && c == '\n'){
			*cp++ = '\r';
			bp->cnt++;
			cnt--;
		}
#endif
		*cp++ = c;
		bp->cnt++;
		cnt--;
	}
	if(bp->cnt != 0)
		send_tcp(tcb,bp);
	else
		free_p(bp);

	if(cnt > 1){	/* EOF seen */
#ifndef	CPM
#ifndef	AMIGA
		cdsave = pwd();		/* Save current directory */
		chdir(ftp->cd);		/* Switch to user's directory*/
#endif
#endif
		fclose(ftp->fp);
#ifndef	CPM
#ifndef	AMIGA
		chdir(cdsave);		/* And back */
		free(cdsave);
#endif
#endif
		ftp->fp = NULLFILE;
		close_tcp(tcb);
	}
}
/* Allocate an FTP control block */
struct ftp *
ftp_create(bufsize)
unsigned bufsize;
{
	void ftp_delete();
	char *calloc(),*malloc();
	register struct ftp *ftp;

	if((ftp = (struct ftp *)calloc(1,sizeof (struct ftp))) == NULLFTP)
		return NULLFTP;
	if(bufsize != 0 && (ftp->buf = malloc(bufsize)) == NULLCHAR){
		ftp_delete(ftp);
		return NULLFTP;
	}
	ftp->state = COMMAND_STATE;
	ftp->type = ASCII_TYPE;	/* Default transfer type */
	return ftp;
}
/* Free resources, delete control block */
void
ftp_delete(ftp)
register struct ftp *ftp;
{
	if(ftp->fp != NULLFILE)
		fclose(ftp->fp);
	if(ftp->data != NULLTCB)
		del_tcp(ftp->data);
	if(ftp->username != NULLCHAR)
		free(ftp->username);
	if(ftp->buf != NULLCHAR)
		free(ftp->buf);
#ifndef	AMIGA
	if(ftp->cd != NULLCHAR)
		free(ftp->cd);
#endif
	if(ftp->session != NULLSESSION)
		ftp->session->type = FREE;
	free((char *)ftp);
}

#ifndef	AMIGA
/* Call getcwd(), but stick a backslash on the front (!) */
#define CWDLEN	256		/* max path len */

char *
pwd()
{
	char *buf,*malloc(),*getcwd();

	if((buf = malloc(CWDLEN+1)) == NULLCHAR)
		return NULLCHAR;
	buf[0] = '\\';
	if(getcwd(buf+1,CWDLEN) == NULLCHAR){
		free(buf);
		return NULLCHAR;
	}
	return buf;
}
#endif
