#ifndef	lint
static char sccsid[] = "@(#)server_rcv.c 1.4 88/12/21";
#endif

#include <stdio.h>
#include "cbratp.h"
#include "romfs.h"

extern fd_set	stopped_fds;

rcv_control(c)
    u_char	c;
{
    free((char *) chan[c]->buf);
    return 0;
}

rcv_open(c)
    u_char	c;
{
    u_char fd;
    u_char type;
    u_char channel;
    register u_char *p = chan[c]->buf;

    switch (chan[c]->len) {
    case 6: /* read and write */
	fd = RPC_TO_LOCAL(*p++);
	channel = *p++;
	type = *p++;
	alloc_channel(channel, type, fd);
	if (type == READ_CHN) {
	    rd_chan[fd] = channel;
	    rd_queue[fd] = cq_alloc();
	    return_int = fd;
	}
	else {
	    wr_chan[fd] = channel;
	    return_int2 = fd;
	}
	/* fall through */
    case 3: /* read or write */
	fd = RPC_TO_LOCAL(*p++);
	channel = *p++;
	type = *p++;
	alloc_channel(channel, type, fd);
	if (type == READ_CHN) {
	    rd_chan[fd] = channel;
	    rd_queue[fd] = cq_alloc();
	    return_int = fd;
	}
	else {
	    wr_chan[fd] = channel;
	    return_int2 = fd;
	}
	break;
    default:
	return_int = return_int2 = -1;
    }

    free((char *) chan[c]->buf);
    return 0;
}

rcv_close(c)
    u_char	c;
{
    if (chan[c]->len != 0)
	return_int = -1;
    else
	return_int = 0;
    free((char *) chan[c]->buf);
    return 0;
}

rcv_lseek(c)
    u_char	c;
{
    return_long = decode_long(chan[c]->buf);
    free((char *) chan[c]->buf);
    return 0;
}

rcv_filesize(c)
    u_char	c;
{
    return_long = decode_long(chan[c]->buf);
    free((char *) chan[c]->buf);
    return 0;
}

rcv_opencon(c)
    u_char	c;
{
    u_char fd;
    u_char *p = chan[c]->buf;

    fd = RPC_TO_LOCAL(*p++);
    switch (chan[c]->len) {
    case 3: /* size of fd + 2 channels : (active open) */
	alloc_channel(*p, READ_CHN, fd);
	rd_chan[fd] = *p++;
	rd_queue[fd] = cq_alloc();
	alloc_channel(*p, WRITE_CHN, fd);
	wr_chan[fd] = *p++;
	return_int = fd;
	break;
    case 2: /* size of fd + 1 channel : (passive open) */
	alloc_channel(*p, READ_CHN, fd);
	rd_chan[fd] = *p;
	return_int = fd;
	break;
    default:
	return_int = -1;
    }

    free((char *) chan[c]->buf);
    return 0;
}

rcv_acceptcon(c)
    u_char	c;
{
    u_char fd;
    register u_char *p = chan[c]->buf;

    switch (chan[c]->len) {
    case 3: /* fd + read/write channels */
	fd = RPC_TO_LOCAL(*p++);
	alloc_channel(*p, READ_CHN, fd);
	rd_chan[fd] = *p++;
	rd_queue[fd] = cq_alloc();
	alloc_channel(*p, WRITE_CHN, fd);
	wr_chan[fd] = *p++;
	return_int = fd;
	break;
    default:
	return_int = -1;
    }
    free((char *) chan[c]->buf);
    return 0;
}

rcv_serveraddr(c)
    u_char	c;
{
    return_int = chan[c]->len;
    return_ptr = (char *)chan[c]->buf;
    return 0;
}

rcv_clientaddr(c)
    u_char	c;
{
    return_int = chan[c]->len;
    return_ptr = (char *)chan[c]->buf;
    return 0;
}

rcv_servername(c)
    u_char	c;
{
    return_int = chan[c]->len;
    return_ptr = (char *)chan[c]->buf;
    return 0;
}

rcv_gethostname(c)
    u_char	c;
{
    return_int = chan[c]->len;
    return_ptr = (char *)chan[c]->buf;
    return 0;
}

rcv_gethostaddr(c)
    u_char	c;
{
    static char hostaddr[100];

    if (chan[c]->len > 4) {
	return_long = decode_long(chan[c]->buf);
	return_int = chan[c]->len - 4;
	bcopy((char *) chan[c]->buf + 4, hostaddr, return_int);
	return_ptr = hostaddr;
    }
    else
	return_int = 0;

    free((char *) chan[c]->buf);
    return 0;
}

rcv_getenv(c)
    u_char	c;
{
    return_int = chan[c]->len;
    return_ptr = (char *)chan[c]->buf;
    return 0;
}

rcv_homedir(c)
    u_char	c;
{
    return_int = chan[c]->len;
    return_ptr = (char *)chan[c]->buf;
    return 0;
}

rcv_cwd(c)
    u_char	c;
{
    return_int = chan[c]->len;
    return_ptr = (char *)chan[c]->buf;
    return 0;
}

rcv_putenv(c)
    u_char	c;
{
    free((char *) chan[c]->buf);
    return 0;
}

rcv_spawn(c)
    u_char	c;
{
    free((char *) chan[c]->buf);
    return 0;
}

extern int io_ready;

rcv_read(c)
    u_char	c;
{
    register struct cqueue *r;
    register u_char *p = chan[c]->buf;
    register int len = chan[c]->len;

    if (r = rd_queue[chan[c]->arg]) {
	if (len > r->bufsize - r->size) {
	    register u_char *t = (u_char *)malloc(r->size + len);

	    if (r->size != 0) {
		if (r->tail <= r->head) {
		    register int above = r->buf + r->bufsize - r->head;

		    bcopy((char *) r->head, (char *) t, above);
		    bcopy((char *) r->buf, (char *) t + above, r->tail - r->buf);
		}
		else
		    bcopy((char *) r->head, (char *) t, r->tail - r->head);
	    }
	    free((char *) r->buf);
	    r->bufsize = r->size + len;
	    r->buf = t;
	    r->head = r->buf;
	    r->tail = r->buf + r->size;
	}
	while (--len >= 0)
	    bputc(r, *p++);
    }
#ifdef	DEBUG
    if(rs232_debug)
	printf("setfd-%d\n", chan[c]->arg);
#endif	/*DEBUG*/
    if (r && r->size > 4096) {
	enqueue(c, &c, 1);
	FD_SET(chan[c]->arg, &stopped_fds);
    }
    FD_SET(chan[c]->arg, &read_fds);
    io_ready = 1;
    free((char *) chan[c]->buf);
    return 0;
}

rcv_write(c)
    u_char	c;
{
    if (chan[c]->len == 0)
	return_int = -1;
    else
	return_int = 0;
    free((char *) chan[c]->buf);
    return 0;
}

rcv_version(c)
    u_char	c;
{
    return_int = chan[c]->len;
    return_ptr = (char *) chan[c]->buf;
    return 0;
}

rcv_pipe(c)
    u_char c;
{
    return(rcv_open(c));
}
