/*
 *	Network Queueing System (NQS)
 *  This version of NQS is Copyright (C) 1992  John Roman
 *
 *  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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
*  PROJECT:     Network Queueing System
*  AUTHOR:      John Roman
*
*  Modification history:
*
*       Version Who     When            Description
*       -------+-------+---------------+-------------------------
*       V01.00  JRR                     Initial version.
*	V01.10  JRR     10-Apr-91	Fix problem where blank command line
*					caused access violation.
*	V01.30	JRR	10-Apr-91	Don't stop list on empty mid.
*       V01.40  JRR     16-Jan-1992	Added support for RS6000.
*       V01.5   JRR     12-Feb-1992	Fixed declaration of static routines.
*       V01.6   JRR     07-Apr-1992     Added CERN enhancements.
*	V01.7	JRR	17-Jun-1992	Added header.
*	V01.8	JRR	11-Nov-1992	Modified for C prototypes.
*	V01.9	JRR	23-Dec-1992	Added version command.
*			23-Feb-1993	Added Boeing enhancement for Mids.
*			05-Mar-1993	Added Boeing enhancement for files.
*			03-Mar-1994	Fixed up NMAP.
*/
/*++ nmapmgr.c - Network Queueing System substitute Network Mapping manager
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.35.6/npsn_compat/RCS/nmapmgr.c,v $
 *
 * DESCRIPTION:
 *
 *	Provide a very poor version of the real NPSN network mapping
 *	manager program for non-NPSN systems.
 *
 *
 *	Author:
 *	-------
 *	Brent A. Kingsbury, Sterling Software Incorporated.
 *	August 12, 1985.
 *
 *
 * STANDARDS VIOLATIONS:
 *
 */
 
#define VERSION "1.9"

#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>

#if	vms
#include file
#include unixio
#include "nmap.h"			/* Mid_t (all OS's) */
#include <netdb.h>
typedef unsigned short uid_t;	/* User-id type.		*/
typedef unsigned short gid_t;	/* Group-id type.		*/
#else
#include "nqsdirs.h"
#include "nmap.h"			/* Mid_t (all OS's) */
					/* Uid_t and gid_t (if not BSD43) */
#include <netdb.h>
#endif

#ifndef __CEXTRACT__
#if __STDC__

static docmd ( char *cmdbuf );
static long getint ( char *ptr );
static unsigned long getuint ( char *ptr );
static showret ( int code );
static int strequ ( char *str1, char *str2 );

#else /* __STDC__ */

static docmd (/* char *cmdbuf */);
static long getint (/* char *ptr */);
static unsigned long getuint (/* char *ptr */);
static showret (/* int code */);
static int strequ (/* char *str1, char *str2 */);

#endif /* __STDC__ */
#endif /* __CEXTRACT__ */

#define	MAX_LINESIZ	255
#define	MAX_CMD		31

/*** main
 *
 *	main (): The main routine of nmapmgr.
 *
 *
 */
main (argc, argv)
int argc;
char *argv[];
{
	char cmdbuf [MAX_LINESIZ];
	FILE	*fp;
	char	*filename;
	int	echocmd = 0;
	int	status;		    /* status from open_name_map */

        /*
         *  Set up the environment variables necessary for directory
         *  independent installation.  If these variables do not exist,
         *  NQS will use the compiled defaults.  The $NQS_HOME/nqs.config
         *  file is read to create environment variables that define where
         *  major NQS directories reside.  Major directories are as
         *  follows:
         *
         *    NQS_LIBEXE - NQS daemon programs and qmgr help file.
         *    NQS_LIBUSR - NQS user interface programs.
         *    NQS_MAN - NQS man pages directory.
         *    NQS_NMAP - NQS network map directory.
         *    NQS_SPOOL - NQS spooling directories.
         */
        if ( ! buildenv()) {
                fprintf (stderr, "Unable to establish directory ");
                fprintf (stderr, "independent environment.\n");
                exit(1);                /* Exit */
        }
	umask (0);			/* CRITICAL */
	/*
	 * Does the machine database already exist?  If not,  go ahead
	 * and create it.  There isn't much we can do without it.
	 */
	status = open_name_map (O_RDONLY);
	if (status != NMAP_SUCCESS ) {
	    status = nmap_create();
	    if (status == NMAP_EUNEXPECT) {
		printf("NMAPMGR unexpected error creating MID database, \n");
		exit (1);
	    } else if (status == NMAP_ENOPRIV) {
		printf("NMAPMGR error creating MID database -- no privilege.\n");
		exit (1);
	    } else if  (status == NMAP_ECONFLICT) {
		printf ("NMAPMGR error creating MID database -- already exists.\n");
		exit (1);
	    }
	}
	if (argc > 1 && *argv[1] == '@') {
	    filename = argv[1];
	    filename++;
	    if ((fp = fopen(filename, "r")) == NULL ) {
		printf("NMAPMGR error opening input file %s\n", filename);
		exit (1);
	    }
	    echocmd = 1;
	} else {
	    fp = stdin;
	}
	for (;;) {
		printf ("NMAPMGR>: ");
		if (fgets (cmdbuf, MAX_LINESIZ, fp) == NULL) {
			putchar ('\n');
			if (feof (fp)) exit (0);
			printf ("NMAPMGR error reading command input.\n");
			exit (1);
		}
		if (cmdbuf [strlen (cmdbuf)-1] != '\n') {
			printf ("NMAPMGR command line too long.\n");
			exit (1);
		}
		cmdbuf [strlen (cmdbuf)-1] = '\0';	/* Zap '\n' */
		if (strlen(cmdbuf) == 0) continue;
		if (echocmd == 1) printf("%s\n", cmdbuf);
		docmd (cmdbuf);
	}
}


/*** docmd
 *
 *	static docmd (): Do command.
 *
 *
 */
static docmd (cmdbuf)
char *cmdbuf;
{

	struct hostent hostent;
	char *arg [MAX_CMD+1];
	int tokens;
	char *ch;
	int res;
	int nfds;
	Mid_t from_mid;
	uid_t from_uid;
	gid_t from_gid;
	Mid_t to_mid;
	uid_t to_uid;
	gid_t to_gid;
	Mid_t mid;
	uid_t defuid;
	gid_t defgid;
	char name[64];

	/*
 	 *  Break command into tokens.
	 */
	for (tokens = 0; tokens <= MAX_CMD; tokens++) arg [tokens] = NULL;
	tokens = 0;
	ch = cmdbuf;
	while (*ch && tokens < MAX_CMD) {
		while (*ch && isspace (*ch)) ch++;
		if (*ch) {
			arg [tokens++] = ch;	/* Save ptr to arg */
			while (*ch && !(isspace (*ch))) ch++;
			if (*ch) *ch++ = '\0';	/* Null terminate */
		}
	}
        /* Bail out if no data */
        if (tokens == 0)
                return;
	/*
	 *  Perform the command.
	 */
	if (strequ (arg [0], "Add")) {
		if (tokens == 1) printf ("Missing verb modifier.\n");
		else if (strequ (arg [1], "Alias")) {
                        if (tokens >= 4) {
                                showret (nmap_add_alias (arg [2], arg [3]));
                        }
                        else printf ("Missing arguments.\n");
                }
		else if (strequ (arg [1], "Uid")) {
			if (tokens >= 5) {
				if ((from_mid = getuint (arg [2])) >= 0 &&
				    (from_uid = getint (arg [3])) >= 0 &&
				    (to_uid = getint (arg [4])) >= 0) {
					showret (nmap_add_uid (from_mid,
							       from_uid,
							       to_uid));
				}
			}
			else printf ("Missing arguments.\n");
		}
		else if (strequ (arg [1], "Gid")) {
			if (tokens >= 5) {
				if ((from_mid = getuint (arg [2])) >= 0 &&
				    (from_gid = getint (arg [3])) >= 0 &&
				    (to_gid = getint (arg [4])) >= 0) {
					showret (nmap_add_gid (from_mid,
							       from_gid,
							       to_gid));
				}
			}
			else printf ("Missing arguments.\n");
		}
                else if (strequ (arg [1], "Host")) {
                        if (tokens >= 3) {
                                showret (nmap_add_host (arg [2]));
                        }
                        else printf ("Missing argument.\n");
                }
		else if (strequ (arg [1], "Name")) {
			if (tokens >= 4) {
				if ((to_mid = getuint (arg [3])) >= 0) {
					showret (nmap_add_nam (arg [2],to_mid));
				}
			}
			else printf ("Missing arguments.\n");
		}
		else if (strequ (arg [1], "Mid")) {
			if (tokens >= 4) {
				if ((mid = getuint (arg [2])) >= 0) {
					showret (nmap_add_mid (mid, arg [3]));
				}
			}
			else printf ("Missing arguments.\n");
		}
		else printf ("Unrecognized command verb modifier.\n");
	}
	else if (strequ (arg [0], "CHange")) {
		if (tokens == 1) printf ("Missing verb modifier.\n");
		else if (strequ (arg [1], "Name")) {
			if (tokens >= 4) {
				if ((mid = getuint (arg [2])) >= 0) {
					showret (nmap_chg_mid (mid, arg [3]));
				}
			}
			else printf ("Missing arguments.\n");
		}
		else printf ("Unrecognized command verb modifier.\n");
	}
	else if (strequ (arg [0], "CReate")) {
		showret (nmap_create());
	}
	else if (strequ (arg [0], "Delete")) {
		if (tokens == 1) printf ("Missing verb modifier.\n");
		else if (strequ (arg [1], "Uid")) {
			if (tokens >= 4) {
				if ((from_mid = getuint (arg [2])) >= 0 &&
				    (from_uid = getint (arg [3])) >= 0) {
					showret (nmap_del_uid (from_mid,
							       from_uid));
				}
			}
			else printf ("Missing arguments.\n");
		}
		else if (strequ (arg [1], "Gid")) {
			if (tokens >= 4) {
				if ((from_mid = getuint (arg [2])) >= 0 &&
				    (from_gid = getint (arg [3])) >= 0) {
					showret (nmap_del_gid (from_mid,
							       from_gid));
				}
			}
			else printf ("Missing arguments.\n");
		}
		else if (strequ (arg [1], "DEFUid")) {
			if (tokens >= 3) {
				if ((from_mid = getuint (arg [2])) >= 0) {
					showret (nmap_del_defuid (from_mid));
				}
			}
			else printf ("Missing <mid>.\n");
		}
		else if (strequ (arg [1], "DEFGid")) {
			if (tokens >= 3) {
				if ((from_mid = getuint (arg [2])) >= 0) {
					showret (nmap_del_defgid (from_mid));
				}
			}
			else printf ("Missing <mid>.\n");
		}
                else if (strequ (arg [1], "Alias")) {
                        if (tokens >= 3) {
                                showret (nmap_del_nam (arg [2]));
                        }
                        else printf ("Missing <name>.\n");
                }
                else if (strequ (arg [1], "Host")) {
                        if (tokens >= 3) {
                                showret (nmap_del_host (arg [2]));
                        }
                        else printf ("Missing <name>.\n");
                }
		else if (strequ (arg [1], "Name")) {
			if (tokens >= 3) {
				showret (nmap_del_nam (arg [2]));
			}
			else printf ("Missing <name>.\n");
		}
		else if (strequ (arg [1], "Mid")) {
			if (tokens >= 3) {
				if ((mid = getuint (arg [2])) >= 0) {
					showret (nmap_del_mid (mid));
				}
			}
			else printf ("Missing <mid>.\n");
		}
		else printf ("Unrecognized command verb modifier.\n");
	}
	else if (strequ (arg [0], "Exit")) exit (0);
	else if (strequ (arg [0], "Get")) {
		if (tokens == 1) printf ("Missing verb modifier.\n");
		else if (strequ (arg [1], "Uid")) {
			if (tokens >= 4) {
				if ((from_mid = getuint (arg [2])) >= 0 &&
				    (from_uid = getint (arg [3])) >= 0) {
					res = nmap_get_uid (from_mid, from_uid,
							    &to_uid);
					showret (res);
					if (res >= NMAP_SUCCESS) {
						printf ("Mapped uid = %d.\n",
							to_uid);
					}
				}
			}
			else printf ("Missing arguments.\n");
		}
		else if (strequ (arg [1], "Gid")) {
			if (tokens >= 4) {
				if ((from_mid = getuint (arg [2])) >= 0 &&
				    (from_gid = getint (arg [3])) >= 0) {
					res = nmap_get_gid (from_mid, from_gid,
							    &to_gid);
					showret (res);
					if (res >= NMAP_SUCCESS) {
						printf ("Mapped gid = %d.\n",
							to_gid);
					}
				}
			}
			else printf ("Missing arguments.\n");
		}
		else if (strequ (arg [1], "Mid")) {
			if (tokens >= 3) {
				hostent.h_name = arg [2];
				hostent.h_aliases = arg+3;
				res = nmap_get_mid (&hostent, &mid);
				showret (res);
				if (res == NMAP_SUCCESS) {
					printf ("Mid = %u.\n", mid);
				}
			}
			else printf ("Missing <name(s)>.\n");
		}
		else if (strequ (arg [1], "Name")) {
			if (tokens >= 3) {
				if ((mid = getuint (arg [2])) >= 0) {
					arg [0] = nmap_get_nam (mid);
					if (arg [0] == NULL) {
						printf ("No such mid.\n");
					}
					else printf ("Name = %s.\n", arg[0]);
				}
			}
			else printf ("Missing <mid>.\n");
		}
		else printf ("Unrecognized command verb modifier.\n");
	}
	else if (strequ (arg [0], "Help")) {
		putchar ('\n');
		printf ("Commands:\n");
		printf ("  Add Uid <from_mid> <from_uid> <to_uid>\n");
		printf ("  Add Gid <from_mid> <from_gid> <to_gid>\n");
                printf ("  Add Alias <name> <principal-name>\n");
                printf ("  Add Host <principal-name>\n");
		printf ("  Add Name <name> <to_mid>\n");
		printf ("  Add Mid <mid> <principal-name>\n");
		printf ("  CHange Name <mid> <new-name>\n");
		printf ("  CReate\n");
		printf ("  Delete Uid <from_mid> <from_uid>\n");
		printf ("  Delete Gid <from_mid> <from_gid>\n");
		printf ("  Delete DEFUid <from_mid>\n");
		printf ("  Delete DEFGid <from_mid>\n");
                printf ("  Delete Alias <name>\n");
                printf ("  Delete Host <principal-name>\n");
		printf ("  Delete Name <name>\n");
		printf ("  Delete Mid <mid>\n");
		printf ("  Exit\n");
		printf ("  Get Uid <from_mid> <from_uid>\n");
		printf ("  Get Gid <from_mid> <from_gid>\n");
		printf ("  Get Mid <name>\n");
		printf ("  Get Name <mid>\n");
		printf ("  Help\n");
		printf ("  List\n");
		printf ("  Quit\n");
		printf ("  Set Nfds <#-of-file-descrs>\n");
		printf ("  Set DEFUid <from_mid> <defuid>\n");
		printf ("  Set DEFGid <from_mid> <defgid>\n");
                printf ("  Show\n");
                printf ("  Version\n");
		printf (" ^D (to exit nmapmgr.\n");
	}
	else if (strequ (arg [0], "List")) {
	    nmap_show();                    /* I like show better now */
	                                    /* This used to be nmap_list_nam() */
	}
	else if (strequ (arg [0], "Quit")) exit (0);
	else if (strequ (arg [0], "Set")) {
		if (tokens == 1) printf ("Missing verb modifier.\n");
		else if (strequ (arg [1], "Nfds")) {
			if (tokens >= 3) {
				if ((nfds = getint (arg [2])) >= 0) {
					nmap_ctl (NMAP_OPNOFD, nfds);
				}
			}
			else printf ("Missing <#-of-file-descrs>.\n");
		}
		else if (strequ (arg [1], "DEFUid")) {
			if (tokens >= 4) {
				if ((from_mid = getuint (arg [2])) >= 0 &&
				    (defuid = getint (arg [3])) >= 0) {
					showret (nmap_set_defuid (from_mid,
							          defuid));
				}
			}
			else printf ("Missing arguments.\n");
		}
		else if (strequ (arg [1], "DEFGid")) {
			if (tokens >= 4) {
				if ((from_mid = getuint (arg [2])) >= 0 &&
				    (defgid = getint (arg [3])) >= 0) {
					showret (nmap_set_defgid (from_mid,
								  defgid));
				}
			}
			else printf ("Missing arguments.\n");
		}
		else printf ("Unrecognized command verb modifier.\n");
	}
	else if (strequ (arg[0], "Show")) {
	    showret (nmap_show());
	}
	else if (strequ (arg[0], "Version")) {
	    printf("Nmapmgr version: %s\n", VERSION);
	}
	else if (strequ ("#", arg[0])) {
	    /* comment -- ignore */
	}
	else if (tokens >= 1) printf ("Unrecognized command verb: %s\n",
				      arg [0]);
}


/*** strequ
 *
 *	int strequ (str1, str2)
 *	char *str1;
 *	char *str2;
 *
 *	Return 1 if the two null-terminated strings are equal.
 *	Otherwise return 0.  This comparison however uses uppercase
 *	characters in str2 to denote acceptable abbreviations.
 *	Thus:
 *
 *		strequ ("defg", "DEFGid") = 1
 *
 *	while:
 *
 *		strequ ("def", "DEFGid") = 0
 */
static int strequ (str1, str2)
char *str1;
char *str2;
{
	register char ch1;
	register char ch2;

	while (ch1 = *str1++) {
		ch2 = *str2++;
		if (isupper (ch1)) ch1 += 'a' - 'A';
		if (isupper (ch2)) ch2 += 'a' - 'A';
		if (ch1 != ch2) return (0);	/* Strings not equal */
	}
	if (isupper (*str2)) return (0);/* Strings not equal */
	return (1);			/* Strings equal */
}
 

/*** getint
 *
 *	long getint (ptr)
 *	char *ptr;
 *
 *	Return integer value of unsigned sequence of decimal ASCII
 *	digits referenced by ptr.  Print-out an error message and
 *	return a -1 if no sequence of decimal digits exists.
 */
static long getint (ptr)
char *ptr;
{
	register int i;

	if (isdigit (*ptr)) {
		i = 0;
		while (isdigit (*ptr)) {
			i *= 10;
			i += *ptr++ - '0';
		}
		if (i < 0) {
			printf ("Integer overflow.\n");
			return (-1);
		}
		return (i);
	}
	else {
		printf ("Unsigned integer number expected.\n");
		return (-1);
	}
}


/*** getuint
 *
 *      long getuint (ptr)
 *      char *ptr;
 *
 *      Return integer value of unsigned sequence of decimal ASCII
 *      digits referenced by ptr.  Print-out an error message and
 *      return a -1 if no sequence of decimal digits exists.
 */
static unsigned long getuint (ptr)
char *ptr;
{
        register u_long i;

        if (isdigit (*ptr)) {
                i = 0;
                while (isdigit (*ptr)) {
                        i *= 10;
                        i += *ptr++ - '0';
                }
                return (i);
        }
        else {
                printf ("Unsigned integer number expected.\n");
                return (-1);
        }
}

/*** showret
 *
 *	showret (code)
 *	int code;
 *
 *	Identify the return code from the NMAP library module.
 */
static showret (code)
register int code;
{
	switch (code) {
	case NMAP_SUCCESS:
		printf ("NMAP_SUCCESS:  Successful completion.\n");
		break;
	case NMAP_DEFMAP:
		printf ("NMAP_DEFMAP:  Successful completion using ");
		printf ("default mapping.\n");
		break;
	case NMAP_EUNEXPECT:
		printf ("NMAP_EUNEXPECT:  Fatal error in mapping software.\n");
		break;
	case NMAP_ENOPRIV:
		printf ("NMAP_ENOPRIV:  No privilege for operation.\n");
		break;
	case NMAP_ECONFLICT:
		printf ("NMAP_ECONFLICT:  Already exists.\n");
		break;
	case NMAP_ENOMAP:
		printf ("NMAP_ENOMAP:  No such mapping.\n");
		break;
	case NMAP_ENOMID:
		printf ("NMAP_ENOMID:  No such machine.\n");
		break;
	case NMAP_EBADNAME:
		printf ("NMAP_EBADNAME:  Null name, name too long, ");
		printf ("or undefined host.\n");
		break;
	default:
		printf ("Invalid NMAP return code.\n");
		break;
	}
}
