/*
 * Micro-X -- an X server for DOS
 * Copyright (C) 1994 StarNet Communications Corp.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 * StarNet Communications Corp.
 * 550 Lakeside Dr. #3
 * Sunnyvale CA 94086 US
 * http://www.starnet.com
 * x-dos@starnet.com
 */

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <xti.h>
#include <sys/tk_types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include "funcdef.h"
#include "local.h"
#include "../defs.h"
#include "../funcs.h"

extern unsigned long my_address;

struct nfs_func {
	int (_fastcall *proc)(int, int _near *, void _far *);
} _near nfs_funcs[] = {
	0,
	nfs_init,
	nfs_shutdown,
	nfs_socket,
	nfs_info,
	nfs_accept,
	nfs_drain,
	nfs_release,
	nfs_eof,
	nfs_read,
	nfs_write,
	nfs_recv,
	nfs_sendto,
	nfs_select,
	0
};

unsigned int near n_funcs = sizeof (nfs_funcs) / sizeof (nfs_funcs[0]);

int
main(argc, argv, envp)
int argc;
char **argv;
char **envp;
{
	leave(0);
	return 0;
}

int
rpc_entry(func, arg, len, buf)
int func, arg, len;
void _far *buf;
{
    struct nfs_func near *nfp;
    int i;

    nfp = &nfs_funcs[func];
    if ((unsigned)func >= n_funcs || !nfp->proc) {
	arg = NETERR_BADCALL;
	len = 0;
	return -1;
    }
    i = (nfp->proc)(arg, &len, buf);
    if (i < 0) {
	len = errno;
	arg = convert_error(t_errno);
	/* Fool the optimizer.  Len and arg are both passed by reference. */
	if (len)
	    return -1;
	return -1;
    }
    return i;
}

int _fastcall
nfs_info(arg, len, buf)
int arg, _near *len;
void _far *buf;
{

    ((struct net_info _far *)buf)->ip_address = my_address;
    ((struct net_info _far *)buf)->ip_broadcast = 0;	/* ??? */
    *len = sizeof (struct net_info);
    return 0;
}

int _fastcall
nfs_accept(arg, len, buf)
int arg, _near *len;
void _far *buf;
{
    struct t_call *call;

    call = (struct t_call *)t_alloc(arg, T_CALL, T_ADDR|T_OPT);
    if (!call)
	return -1;
    if (t_listen(arg, call) < 0 ||
	t_accept(arg, arg, call) < 0) {
	t_free((char *)call, T_CALL);
	return -1;
    }
    ((struct net_addr _far *)buf)->socket =
	    ntohs(((struct sockaddr_in *)call->addr.buf)->sin_port);
    ((struct net_addr _far *)buf)->host =
	    ((struct sockaddr_in *)call->addr.buf)->sin_addr.s_addr;
    t_free((char *)call, T_CALL);
    *len = sizeof (struct net_addr);
    return arg;
}

int _fastcall
nfs_release(arg, len, buf)
int arg, _near *len;
void _far *buf;
{
    return t_close(arg);
}

int _fastcall
nfs_eof(arg, len, buf)
int arg, _near *len;
void _far *buf;
{
    return t_sndrel(arg);
}

/*
 * buf contains oflags, of which each bit indicates that a
 * particular socket can accept outgoing data.  Since there is no
 * way to tell this with PC/NFS without actually trying to send
 * data, we don't set bits in that flag.
 * Unfortunately, oflags also tells us when a connection can be
 * accepted with net_accept so we have to query those.
 */
int _fastcall
nfs_select(arg, len, buf)
int arg, _near *len;
void _far *buf;
{
    u_long iflags = ((long _far *)buf)[0];
    u_long oflags = ((long _far *)buf)[1];
    u_long reti, reto;
    u_long mask;
    int i, x, n;

    reti = 0;
    reto = 0;
    n = 0;
    for (i = 0, mask = 1; i < arg; i++, mask <<= 1) {
	if (mask & oflags) {
	    if (t_look(i) != 0) {
		reto |= mask;
		n++;
	    }
	}
	if (mask & iflags) {
	    if ((x = t_look(i)) > 0) {
		reti |= mask;
		n++;
	    } else if (x < 0)
		return -1;
	}
    }
    ((long _far *)buf)[0] = reti;
    ((long _far *)buf)[1] = reto;
    *len = 2 * sizeof (long);
    return n;
}

void
_nullcheck()
{
}
