/*
 *  This file is part of ixemul.library for the Amiga.
 *  Copyright (C) 1996 Jeff Shepherd
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  $Id:$
 *
 *  $Log:$
 */


/*
 * Copyright (c) 1988 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/* interface with ixnet.library - just call the library (if its open) */
/* sometimes do some local things if ixnet.library isn't open */
#define KERNEL
#include "ixemul.h"
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

struct hostent *
gethostbyname(char *name) {
    extern struct hostent *NET_gethostbyname(char *);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct hostent *)NET_gethostbyname(name);
    }
    else
	return NULL;
}

struct hostent *
gethostbyaddr(const char *addr, int len, int type) {
    extern struct hostent *NET_gethostbyaddr(const char *, int, int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct hostent *)NET_gethostbyaddr(addr,len,type);
    }
    else
	return NULL;
}


void
sethostent(int stayopen) {
    extern void NET_sethostent(int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	NET_sethostent(stayopen);
    }
}

void
endhostent(void) {
    extern void NET_endhostent(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	NET_endhostent();
    }
}

struct netent *
getnetbyname(const char *name) {
    extern struct netent *NET_getnetbyname(const char *);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct netent *)NET_getnetbyname(name);
    }
    else
	return NULL;
}

struct netent *
getnetbyaddr(long net, int type) {
    extern struct netent *NET_getnetbyaddr(long, int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct netent *)NET_getnetbyaddr(net, type);
    }
    else
	return NULL;
}

void
setnetent(int f) {
    extern void NET_setnetent(int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	NET_setnetent(f);
    }
}


void
endnetent(void) {
    extern void NET_endnetent(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	NET_endnetent();
    }
}

struct netent *
getnetent(void) {
    extern struct netent *NET_getnetent(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct netent *)NET_getnetent();
    }
    else
	return NULL;
}

#define MAXALIASES 35
#include <stdio.h>
#include <netdb.h>
static FILE *servf = NULL;
static char line[BUFSIZ+1];
static struct servent serv;
static char *serv_aliases[MAXALIASES];
static int _serv_stayopen = 0;

void
setservent(int f) {
    extern void NET_setservent(int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	NET_setservent(f);
    }
    else {
	if (servf == NULL) {
	    servf = fopen(_PATH_SERVICES, "r" );
	    if (!servf)
		return;
	}
	else
	    rewind(servf);
	_serv_stayopen |= f;
    }
}


void
endservent(void) {
    extern void NET_endservent(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	NET_endservent();
    }
    else {
	if (servf) {
	    fclose(servf);
	    servf = NULL;
	}
	_serv_stayopen = 0;
    }
}


struct servent *
getservent(void) {
    extern struct servent *NET_getservent(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct servent *)NET_getservent();
    }
    else {
	char *p;
	register char *cp, **q;

	if (servf == NULL && (servf = fopen(_PATH_SERVICES, "r" )) == NULL) {
	    return (NULL);
	}
again1:
	if ((p = fgets(line, BUFSIZ, servf)) == NULL)
	    return (NULL);
	if (*p == '#')
	    goto again1;

	cp = strpbrk(p, "#\n");
	if (cp == NULL)
	    goto again1;

	*cp = '\0';
	serv.s_name = p;
	p = strpbrk(p, " \t");
	if (p == NULL)
	    goto again1;

	*p++ = '\0';
	while (*p == ' ' || *p == '\t')
	    p++;

	cp = strpbrk(p, ",/");
	if (cp == NULL)
	    goto again1;

	*cp++ = '\0';
	serv.s_port = htons((u_short)atoi(p));
	serv.s_proto = cp;
	q = serv.s_aliases = serv_aliases;
	cp = strpbrk(cp, " \t");
	if (cp != NULL)
	    *cp++ = '\0';

	while (cp && *cp) {
	    if (*cp == ' ' || *cp == '\t') {
		cp++;
		continue;
	    }
	    if (q < &serv_aliases[MAXALIASES - 1])
		*q++ = cp;
	    cp = strpbrk(cp, " \t");
	    if (cp != NULL)
		*cp++ = '\0';
	}
	*q = NULL;
	return (&serv);
    }
}

struct servent *
getservbyname(const char *name, const char *proto) {
    extern struct servent *NET_getservbyname(const char *, const char *);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct servent *)NET_getservbyname(name,proto);
    }
    else {
	register struct servent *p;
	register char **cp;

	setservent(_serv_stayopen);
	while ((p = getservent())) {
	    if (strcmp(name, p->s_name) == 0)
		goto gotservname;

	    for (cp = p->s_aliases; *cp; cp++)
		if (strcmp(name, *cp) == 0)
		    goto gotservname;

	    continue;
gotservname:
	    if (proto == 0 || strcmp(p->s_proto, proto) == 0)
		break;
	}
	if (!_serv_stayopen)
	    endservent();

	return (p);
    }
}

struct servent *
getservbyport(int port, const char * proto) {
    extern struct servent *NET_getservbyport(int, const char *);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct servent *)NET_getservbyport(port,proto);
    }
    else {
	register struct servent *p;

	setservent(_serv_stayopen);
	while ((p = getservent())) {
	    if (p->s_port != port)
		continue;

	    if (proto == 0 || strcmp(p->s_proto, proto) == 0)
		break;
	}
	if (!_serv_stayopen)
	    endservent();

	return (p);
    }
}

struct ttyent *
getttynam(const char *tty) {
    extern struct ttyent *NET_getttynam(const char *);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct ttyent *)NET_getttynam(tty);
    }
    else
	return NULL;
}

struct ttyent *
getttyent(void) {
    extern struct ttyent *NET_getttyent(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct ttyent *)NET_getttyent();
    }
    else
	return NULL;
}

int
setttyent(void) {
    extern int NET_setttyent(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_setttyent();
    }
    else
	return 0;
}

int
endttyent(void) {
    extern int NET_endttyent(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_endttyent();
    }
    else
	return 0;
}

int
ttyslot(void) {
    extern int NET_ttyslot(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_ttyslot();
    }
    else
	return 0;
}

char *
ttyname(int fd) {
    extern char *NET_ttyname(int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (char *)NET_ttyname(fd);
    }
    else
	return getenv("TERM");
}


long gethostid(void) {
    extern long NET_gethostid(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (long)NET_gethostid();
    }
    else
	return 0xaabbccdd;
}

void
herror(const char *s) {
    extern void NET_herror(const char *);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	NET_herror(s);
    }
}

static FILE *protof = NULL;
static char line[BUFSIZ+1];
static struct protoent proto;
static char *proto_aliases[MAXALIASES];
static int _proto_stayopen = 0;

struct protoent *
getprotobynumber(int proto) {
    extern struct protoent *NET_getprotobynumber(int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct protoent *)NET_getprotobynumber(proto);
    }
    else {
	register struct protoent *p;

	setprotoent(_proto_stayopen);
	while ((p = getprotoent()))
	    if (p->p_proto == proto)
		break;

	if (!_proto_stayopen)
	    endprotoent();
	return (p);
    }
}

struct protoent *
getprotobyname(const char *name) {
    extern struct protoent *NET_getprotobyname(const char *);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct protoent *)NET_getprotobyname(name);
    }
    else {
	register struct protoent *p;
	register char **cp;

	setprotoent(_proto_stayopen);
	while ((p = getprotoent())) {
	    if (strcmp(p->p_name, name) == 0)
		break;
	    for (cp = p->p_aliases; *cp != 0; cp++)
		if (strcmp(*cp, name) == 0)
		    goto found;
	}
found:
	if (!_proto_stayopen)
	    endprotoent();
	return (p);
    }
}

void
setprotoent(int f) {
    extern void NET_setprotoent(int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	NET_setprotoent(f);
    }
    else {
	if (protof == NULL)
	    protof = fopen(_PATH_PROTOCOLS, "r" );
	else
	    rewind(protof);
	_proto_stayopen |= f;
    }
}

void
endprotoent(void) {
    extern void NET_endprotoent(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	NET_endprotoent();
    }
    else {
	if (protof) {
	    fclose(protof);
	    protof = NULL;
	}
	_proto_stayopen = 0;
    }
}

struct protoent *
getprotoent(void) {
    extern struct protoent *NET_getprotoent(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct protoent *)NET_getprotoent();
    }
    else {
	char *p;
	register char *cp, **q;

	if (protof == NULL && (protof = fopen(_PATH_PROTOCOLS, "r" )) == NULL) {
		return (NULL);
	}
again3:

	if ((p = fgets(line, BUFSIZ, protof)) == NULL)
	    return (NULL);

	if (*p == '#')
	    goto again3;

	cp = strpbrk(p, "#\n");
	if (cp == NULL)
	    goto again3;

	*cp = '\0';
	proto.p_name = p;
	cp = strpbrk(p, " \t");
	if (cp == NULL)
	    goto again3;

	*cp++ = '\0';
	while (*cp == ' ' || *cp == '\t')
	    cp++;

	p = strpbrk(cp, " \t");
	if (p != NULL)
	    *p++ = '\0';

	proto.p_proto = atoi(cp);
	q = proto.p_aliases = proto_aliases;
	if (p != NULL) {
	    cp = p;
	    while (cp && *cp) {
		if (*cp == ' ' || *cp == '\t') {
		    cp++;
		    continue;
		}

		if (q < &proto_aliases[MAXALIASES - 1])
		    *q++ = cp;

		cp = strpbrk(cp, " \t");
		if (cp != NULL)
		    *cp++ = '\0';
	    }
	}
	*q = NULL;
	return (&proto);
    }
}

int rcmd(char **ahost, int rport, const char *locuser, const char *remuser,
    const char *cmd, int *fd2p) {
    extern int NET_rcmd(char **, int, const char *, const char *, const char *, int *);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_rcmd(ahost,rport,locuser,remuser,cmd,fd2p);
    }
    else
	return -1;
}

int
rresvport(int *alport) {
    extern int NET_rresvport(int *);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_rresvport(alport);
    }
    else
	return -1;
}


/* not sure if I want to put the full version here or not */
/* see ixnet/getpass.c for the full version */
char *
getpass(const char *prompt) {
    extern char *NET_getpass(const char *);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_getpass(prompt);
    }
    else
	return NULL;
}

static int     _logname_valid;	       /* known to setlogin() */
static char logn[MAXLOGNAME + 1] = "unknown";

int
_getlogin (char *s, int size) {
    char *cp = getenv ("USER");

    if (! cp)
	cp = getenv ("LOGNAME");

    if (! cp)
	cp = logn;

    strncpy (s, cp, size);
    return 0;
}

char *
getlogin(void) {
    extern char *NET_getlogin(void);
    static char logname[MAXLOGNAME + 1];
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (char *)NET_getlogin();
    }
    else {
	if (_logname_valid == 0) {
	    if (_getlogin(logname, sizeof(logname) - 1) < 0)
		return ((char *)NULL);

	    _logname_valid = 1;
	}
	return (*logname ? logname : (char *)NULL);
    }
}


int
setlogin (const char *s) {
    extern int NET_setlogin(const char *);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_setlogin(s);
    }
    else {
	strncpy (logn, s, MAXLOGNAME);
	_logname_valid = 0;
	return 0;
    }
}


int dn_expand(const u_char *msg, const u_char *eomorig, const u_char *comp_dn,
    u_char *exp_dn, int length) {

    extern int NET_dn_expand(const u_char *, const u_char *, const u_char *, u_char *, int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_dn_expand(msg,eomorig,comp_dn,exp_dn,length);
    }
    else {
	return -1;
    }
}

int
dn_comp(const u_char *exp_dn, u_char *comp_dn, int length,
    u_char **dnptrs, u_char **lastdnptr) {

    extern int NET_dn_comp(const u_char *, u_char *, int, u_char **, u_char **);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_dn_comp(exp_dn, comp_dn,length, dnptrs,lastdnptr);
    }
    else {
	return -1;
    }
}

int
res_init(void) {
    extern int NET_res_init(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_res_init();
    }
    else {
	return 0;
    }
}

struct rrec;

int
res_mkquery(int op, const char *dname, int class, int type, const char *data,
    int datalen, const struct rrec *newrr, char *buf, int buflen) {

    extern int NET_res_mkquery(int, const char *, int, int, const char *, int, const struct rrec *, char *, int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_res_mkquery(op, dname, class, type, data,
	    datalen, newrr, buf, buflen);
    }
    else {
	return -1;
    }
}

int
res_query(char *name, int class, int type, u_char *answer, int anslen) {
    extern int NET_res_query(char *, int, int, u_char *, int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_res_query(name, class, type, answer, anslen);
    }
    else
	return -1;
}

int
res_search(char *name, int class, int type, u_char *answer, int anslen) {
    extern int NET_res_search(char *, int, int, u_char *, int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_res_search(name, class, type, answer, anslen);
    }
    else
	return -1;
}


int
res_querydomain(char *name, char *domain, int class, int type, u_char *answer,
    int anslen) {

    extern int NET_res_querydomain(char *, char *, int, int, u_char *, int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_res_querydomain(name, domain, class, type, answer, anslen);
    }
    else
	return -1;
}

int
res_send(const char *buf, int buflen, char *answer, int anslen) {
    extern int NET_res_send(const char *, int, char *, int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_res_send(buf, buflen, answer, anslen);
    }
    else
	return -1;
}


