
/*
 *  SCOPY.C	V1.1
 *
 *  DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
 *
 *  COPY SERVER FOR PUTFILES (DOWNLOADS, i.e. receives files)
 *
 *  The current version only accepts one connection at a time.	This server
 *  handles downloading of data.  This server will eventually be replaced
 *  by the SGCOPY server.  Currently the SGCOPY server only handles
 *  uploads.
 *
 *  NOTE:   The DNET_WRITE enviroment variable must be 9 or higher or this
 *	    server will refuse connections.
 *
 *  Receive:
 *	    'V' NLEN NAME FILELEN       -receive compressed file    (V1.1)
 *	    '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 "defs.h"

char Buf[8192];
char Buf2[8192];

int putdir ARGS((void *, char *));
int putfile ARGS((void *, char *, int));

int
brk()
{
    return(0);
}

void
#ifdef LATTICE
_main(str)
#else
_main(len,str)
#endif
char *str;
{
    struct MsgPort *port;
    PROC    *myproc = (PROC *)FindTask(NULL);
    void    *chan;
    long    savedir;
    long    mask, rmask;

    onbreak(brk);

    if (strncmp(str, "__dnet", 6) != 0) {
	Version("SCopy", VERSION, SCOPY_VERSION);
	_exit(0);
    }

    port = DListen(PORT_FILECOPY);
    {
	struct Message *msg;
	char *dir;

	WaitPort(&myproc->pr_MsgPort);
	msg = GetMsg(&myproc->pr_MsgPort);
	dir = (msg->mn_Node.ln_Name) ? msg->mn_Node.ln_Name : "";
	savedir = Lock(dir, SHARED_LOCK);   /* duplicate current dir    */
	ReplyMsg(msg);
    }
    if (!savedir) {
	DUnListen(port);
	_exit(1);
    }
    savedir = CurrentDir(savedir);              /* CD dup, returns original */
    mask = SIGBREAKF_CTRL_C|(1 << port->mp_SigBit);
    for (;;) {
	long dupdir = DupLock(myproc->pr_CurrentDir);
	rmask = Wait(mask);
	if (rmask & SIGBREAKF_CTRL_C) {
	    UnLock(CurrentDir(dupdir));
	    break;
	}
	while (chan = DAccept(port)) {
	    if (GetEnvVal(DNET_WRITE) >= 9)
		putdir(chan, "");
	    else
		DWrite(chan, "S", 1);
	    DClose(chan);
	}
	UnLock(CurrentDir(dupdir));
    }
    UnLock(CurrentDir(savedir));                /* restore original         */
    DUnListen(port);
}

static char Name[128];

int
putdir(chan, dirname)
void *chan;
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);
}

int
putfile(chan, name, len)
void *chan;
char *name;
int len;
{
    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);
}

