/* This contains all the rpc commands that will be executed
 * by the controller
 */

#include <stdio.h>
#include <conndefs.h>
#include <commands.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/types.h>

extern int 	debug;
extern int	errno;

connection_t conn_list[MAXCHANNELS];

/* Noop -- do nothing! */
rpc_noop(channel, data)
char channel;
char *data;
{
    return;
}


/* create a new channel.  This can ONLY be issued by
 * the xserver program, so only wiretap should ever
 * run this function.
 */
rpc_create(channel, data)
char channel;
char *data;
{
#ifdef XSERVER
    return;
#endif XSERVER
#ifdef WIRETAP
    int s;

    printf("New connection.  Channel %d from %s\n", channel, data);

    if (conn_list[channel].inuse == INUSE) {
	if (debug)
	    printf("Channel %d in use!\n", channel);
	remove_listener(conn_list[channel].fd);
	xdisconnect(channel);
    }

    if ((s = xconnect(channel)) >= 0) {
	if (debug)
	    printf("Connected channel %d on port %d\n", channel, s);
	conn_list[channel].fd = s;
	conn_list[channel].inuse = INUSE;

	add_listener(s);

    } else {			/* Couldnt contact X */
	send_remote_command(CMD_DELETE, channel);
	conn_list[channel].inuse = NOTINUSE;
    }

    return;
#endif WIRETAP
}


/* delete a channel.  This frees the channel up for
 * reuse.  Either side may issue this command.  
 */
rpc_delete(channel, data)
char channel;
char *data;
{
    if (conn_list[channel].inuse == INUSE) {
	remove_listener(conn_list[channel].fd);

	xdisconnect(channel);
	conn_list[channel].inuse = NOTINUSE;

	printf("Deleted channel %d\n", channel);
    }

    return;
}


/* quit.  Clean up and exit.  The server should probably
 * never actually exit, but it should close all connections
 * and wait for a new one.  It should diallow X connections
 * until it has a client connection
 * This should only be issued by wiretap, so only the xserver
 * should have to execute it
 */
rpc_quit(channel, data)
char channel;
char *data;
{
#ifdef WIRETAP
    return;
#endif WIRETAP
#ifdef XSERVER
    int i;

    if (debug)
	printf("Quitting...\n");

    for (i = 1; i < MAXCHANNELS; i++) 
	if (conn_list[channel].inuse == INUSE) {
	    remove_listener(conn_list[channel].fd);
	    xdisconnect(channel);
	    conn_list[channel].inuse = NOTINUSE;
	}

    main_pipe_closed();

    return;
#endif XSERVER
}


data_to_channel(channel, data, len)
char channel;
char data[];
int len;
{
    int num;
    int i;
    char *p = data;

    if (channel == 0) {
	fprintf(stderr, "Cant send to channel zero! Thats special!\n");
	return 1;
    }

    if (conn_list[channel].inuse == INUSE) {

	if (debug)
	    printf("Trying to send %d bytes to channel %d\n", len, channel);

	while (len > 0) {
	    i = write(conn_list[channel].fd, p, len);

	    if (i > 0) {
		len -= i;
		p += i;
	    } else {
		if (debug)
		    printf("NULL write to channel %d.\n", channel);
		delete_remote_channel(channel);
		xdisconnect(channel);
		conn_list[channel].inuse = NOTINUSE;
		remove_listener(conn_list[channel].fd);
		return -1;
	    }
	}

    } else {				/* If no channel, delete it! */
	rpc_delete(channel, "");
	send_remote_command(CMD_DELETE, channel);
    }

    return 1;
}

data_from_channel(channel, data)
char channel;
char data[];
{
    int num;
    int count = 0;
    fd_set readfd;
    static struct timeval timeout = {0,0};

    if (channel == 0) {
	fprintf(stderr, "Cant read from channel zero!  Its special!\n");
	return 0;
    }

    if (conn_list[channel].inuse == INUSE) {

	num = read(conn_list[channel].fd, data, MYBUFSIZ);

	if (num <= 0) {
	    if(debug)
		printf("Bad read from channel %d.\n", channel);	    
	    remove_listener(conn_list[channel].fd);
	    xdisconnect(channel);
	    conn_list[channel].inuse = NOTINUSE;
	    delete_remote_channel(channel);
	    return(0);
	}

	if (debug)
	    printf("Just read %d bytes from channel %d\n", num, channel);

	return(num);
    } else {
	if (debug)
	    printf("Got something from a non-used socket!\n");
	remove_listener(conn_list[channel].fd);
	close(conn_list[channel].fd);
    }
    return(0);
}

delete_remote_channel(channel)
char channel;
{
    send_remote_command(CMD_DELETE, channel);
}


main_pipe_closed()
{
    int sock;

    remove_listener(conn_list[0].fd);
    close(conn_list[0].fd);

    do{
	sleep(20);
	sock = tcp_init();
    } while (sock < 0);

    add_listener(sock);
    conn_list[0].fd = sock;

    return;
}


handler_int()
{
    printf("Quitting. . .\n");
    send_remote_command(CMD_QUIT, 0);
    exit(0);
}
