
/*
 *  SCOPY.C
 *
 *  DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
 *
 *  COPY SERVER
 *
 *  The current version only accepts one connection at a time.	This server
 *  handles uploading/downloading of data.
 *
 *  Receive:
 *	    'W' NLEN NAME FILELEN       -receive file
 *	    'X' NLEN NAME   0           -create and CD into directory
 *	    'Y'  0          0           -restore previous directory
 *	    'C' NLEN NAME   0           -set destination directory
 *
 *  length in 68000 longword format.
 */

#include <stdio.h>
#include <fcntl.h>
#include "servers.h"

int Enable_Abort;
char Buf[1024];

typedef struct FileInfoBlock FIB;
typedef struct Process PROC;

extern struct MsgPort *DListen();
extern PROC *FindTask();
extern char *AllocMem();

_main()
{
    struct MsgPort *port;
    PROC    *myproc = FindTask(NULL);
    long    chan;
    long    savedir;
    long    mask, rmask;

    Enable_Abort = 0;

    port = DListen(PORT_FILECOPY);
    WaitPort(&myproc->pr_MsgPort);
    ReplyMsg(GetMsg(&myproc->pr_MsgPort));
    savedir = Lock("", SHARED_LOCK);            /* duplicate current dir    */
    if (!savedir)
	_exit(1);
    savedir = CurrentDir(savedir);              /* CD dup, returns original */
    mask = SIGBREAKF_CTRL_C|(1 << port->mp_SigBit);
    for (;;) {
	rmask = Wait(mask);
	if (rmask & SIGBREAKF_CTRL_C)
	    break;
	while (chan = DAccept(port)) {
	    fflush(stdout);
	    putdir(chan, "");
	    DClose(chan);
	}
    }
    UnLock(CurrentDir(savedir));
    DUnListen(port);
}

static char Name[128];

putdir(chan, dirname)
char *dirname;
{
    FIB *fib;
    long lock;
    long oldlock;
    long len;
    int ret = -1;
    unsigned char co, nl, rc;

    fib = (FIB *)AllocMem(sizeof(FIB), MEMF_PUBLIC);
    if ((lock = Lock(dirname, SHARED_LOCK)) == NULL) {
	if (lock = CreateDir(dirname)) {
	    UnLock(lock);
	    lock = Lock(dirname, SHARED_LOCK);
	}
    }
    if (lock == NULL || !Examine(lock,fib) || fib->fib_DirEntryType < 0) {
	if (lock)
	    UnLock(lock);
	rc = 'N';
	DWrite(chan, &rc, 1);
	FreeMem(fib, sizeof(FIB));
	return(1);
    }
    rc = 'Y';
    DWrite(chan, &rc, 1);
    oldlock = CurrentDir(lock);
    while (DRead(chan, &co, 1) == 1) {
	if (DRead(chan, &nl, 1) != 1 || DRead(chan, Name, nl) != nl)
	    break;
	if (DRead(chan, &len, 4) != 4)
	    break;
	switch(co) {
	case 'C':
	    {
		char co = 'N';
		long lock = Lock(Name, SHARED_LOCK);    /* CD to dir */
		if (!lock) {
		    if (lock = CreateDir(Name)) {       /* or create */
			UnLock(lock);
			lock = Lock(Name, SHARED_LOCK);
		    }
		}
		if (lock) {
		    co = 'Y';
		    UnLock(CurrentDir(lock));
		}
		DWrite(chan, &co, 1);
	    }
	    break;
	case 'W':
	    if (putfile(chan, Name, len) < 0) {
		ret = -1;
		goto fail;
	    }
	    break;
	case 'X':
	    if (putdir(chan, Name) < 0) {
		ret = -1;
		goto fail;
	    }
	    break;
	case 'Y':
	    ret = 1;
	    co = 'Y';
	    DWrite(chan, &co, 1);
	    goto fail;
	default:
	    co = 'N';
	    DWrite(chan, &co, 1);
	    break;
	}
    }
fail:
    UnLock(CurrentDir(oldlock));
    FreeMem(fib, sizeof(FIB));
    return(ret);
}

putfile(chan, name, len)
char *name;
{
    long fh = Open(name, 1006);
    long n, r;
    char rc;

    if (fh == NULL) {
	rc = 'N';
	DWrite(chan, &rc, 1);
	return(0);
    }
    rc = 'Y';
    DWrite(chan, &rc, 1);
    while (len) {
	r = (len > sizeof(Buf)) ? sizeof(Buf) : len;
	n = DRead(chan, Buf, r);
	if (n != r)
	    break;
	if (Write(fh, Buf, n) != n)
	    break;
	len -= n;
    }
    Close(fh);
    if (len) {
	unlink(name);
	return(-1);
    }
    rc = 'Y';
    DWrite(chan, &rc, 1);
    return(0);
}


