/*
 *
 *	Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology
 *    	Developed by the MIT Student Information Processing Board (SIPB).
 *    	For copying information, see the file mit-copyright.h in this release.
 *
 */
/*
 *
 * resolve_module () --
 *	Can you say "Put all the configuration into one file?"  Can you
 *	say "Concentrated kludgery?"  I knew you could.  This procedure
 *	resolves a module name into port number, hostname, service; it
 *      is allowed to use any trick in the book -- it can depend on hostnames,
 *	have hard coded constants (hopefully recorded in config files, etc.).
 *	Note that if service name contains a '/' as the first character, then
 *	the remote function is executed as a subprocess.
 * 
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>
#include <ctype.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <discuss/interface.h>
#include <discuss/rpc_et.h>
#include <discuss/config.h>

#ifdef KERBEROS
#include <krb.h>
static void ExpandHost (char *, char *, char *);
extern char *krb_realmofhost(char *);
#endif /* KERBEROS */

#ifndef SNAME_SZ
#define SNAME_SZ 40
#endif
#ifndef REALM_SZ
#define REALM_SZ 40
#endif
#ifndef MAX_HSTNM
#define	MAX_HSTNM 100
#endif

#ifndef SERVERDIR
#define SERVERDIR "/usr/athena/etc"
#endif

void resolve_module (modname, port, hostp, servp, result)
    char *modname;		/* name to translate */
    int *port;			/* resultant port number */
    char **hostp;		/* ptr to hostname (static) */
    char **servp;		/* service_id */
    int *result;		/* std error code */
{
    static char service_id [SNAME_SZ+REALM_SZ];
    static char hostname [MAX_HSTNM];
    static char server_path [128];
    char realm [REALM_SZ];
    static int service_port = 0;

    char *myhnamep = NULL;
    struct servent *sp;
    struct hostent *hp;

    *hostp = NULL;
    *servp = NULL;
    *port = 0;
    *result = 0;

    /* The module name could be of the form "discuss@hostname", where
     * hostname is the host to contact.  If the hostname is omitted,
     * the current host is assumed */
    if (!strncmp (modname, "discuss", 7)) {
	if (modname [7] == '@') { /* got hostname */
	    myhnamep = &modname [8];
	    hp = gethostbyname (myhnamep); /* make it primary */
	    if (!hp) {
		extern int h_errno;
		int h = h_errno;
		switch (h) {
		case HOST_NOT_FOUND:
		    *result = RPC_HOST_UNKNOWN;
		    break;
		case TRY_AGAIN:
		    *result = RPC_NS_TIMEOUT;
		    break;
		case NO_RECOVERY:
		    *result = RPC_NS_ERROR;
		    break;
		case NO_ADDRESS:
		    *result = RPC_NO_ADDR;
		    break;
		default:
		    *result = RPC_NS_ERROR;
		}
		return;
	    }
	    strcpy (hostname, hp -> h_name);
	    myhnamep = hostname;
	} else if (modname [7] == '\0') { /* Just discuss - use current host */
	    myhnamep = local_host_name ();
	} else {
	    *result = RPC_MOD_UNKNOWN;
	    return;
	}
    } else {
	*result = RPC_MOD_UNKNOWN;
	return;
    }

    /* Now we have the host name, and all we have to do is create the
     * service id & port number.  If this is local, we use the subprocess,
     * for better authentication */
    if (!namcmp (myhnamep, local_host_name ())) {
        strcpy (server_path, SERVERDIR);
	strcat (server_path, "/disserve");
	*port = 0;
	*servp = server_path;
	*hostp = myhnamep;
	*result = 0;
	return;
    }

    /* otherwise, we have to generate the port number */
    if (service_port == 0) {
	sp = getservbyname (SERVICE_NAME, "tcp");
	if (!sp) {
	     service_port = htons (SERVICE_PORT);
	} else {
	     service_port = sp -> s_port;
	}
    }

    *port = service_port;

    /* generate the service name, but concatenating "discuss.instance@realm"
     * desired realm. */
#ifndef KERBEROS
    strcpy (service_id, "discuss@");
    strcpy (&service_id[8], local_realm());
#else
    strcpy (service_id, "discuss.");
    ExpandHost (myhnamep, &service_id[8], realm);
    strcat(service_id, "@");
    strcat (service_id, realm);
#endif KERBEROS
    *hostp = myhnamep;
    *servp = service_id;
    *result = 0;
}

#ifdef KERBEROS
/*
 *
 * ExpandHost -- takes a user string alias for a host, and converts it
 *		 to the official Kerberos principal name, plus the realm
 *		 that it lies in.
 *
 */
static void ExpandHost (primary_name, krb_host, krb_realm )
    char *primary_name,*krb_realm;
    char *krb_host;
{
    char *sp, *dp;

    strcpy(krb_realm, krb_realmofhost(primary_name));
    if (*krb_realm == '\0')
	strcpy (krb_realm, local_realm());

    /* lower case Kerberos host name */
    sp = primary_name;
    dp = krb_host;
    do {
	if (isupper(*sp)) *dp=tolower(*sp);
	else *dp = *sp;
    } while (dp++,*sp && (*sp++ != '.'));
    *(--dp) = 0;
}
#endif
