/*
 * 5799-WZQ (C) COPYRIGHT = NONE
 * LICENSED MATERIALS - PROPERTY OF IBM
 */
/* $Header:rvdsend.c 12.0$ */
/* $ACIS:rvdsend.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/rvd/cntrl/RCS/rvdsend.c,v $ */

#ifndef lint
static char *rcsid = "$Header:rvdsend.c 12.0$";
#endif


#ifndef lint
static char *rcsid_rvdsend_c = "$Header:rvdsend.c 12.0$";
#endif lint

/* Copyright 1984 by the Massachusetts Institute of Technology */
/* See permission and disclaimer notice in the file "notice.h" */
#include "notice.h"


/* Send one or more messages to the RVD server.  Intended to be used 
 * for the initial database setup at bootstrap time, as well as for
 * later database updates.
 *
 * Syntax:
 *	rvdsend [[server] file]
 *
 * If the server host is not present, the local host is used.
 * Rvdsend reads a succession of messages (terminated by two newlines) from
 * its standard input and sends each message to the RVD server.  It attempts
 * to read the authorization password from the standard authorization file;
 * if it can't, it prompts the user for a password.
 */

#include	<stdio.h>
#include	<ctype.h>
#include	<sys/types.h>
#include	<sys/socket.h>
#include	<netinet/in.h>
#include	<machineio/vdconst.h>

#include	"rvd_types.h"
#include	"ctl_pkt.h"
#include	"extern.h"
#include	"canon.h"

#define	TIMEOUT		5
#define	NRXMIT		5
#define	BUFLEN		8192	/* Long enough to include an authenticator. */
#define	NAMELEN		128	/* Maximum length of server's hostname. */

#define	SUCCESS		0
#define	NORESPONSE	1
#define	GARBAGE		2
#define	FAILURE		3

rvdsend(argc, argv)
	int	argc;
	char	**argv;
{
	int	len, fd = -1;
	char	sbuf[BUFLEN];
	char	server_name[NAMELEN];
	char	*server;
	int	debug = 0;
	char	*passw;
	boolean	authent_ok;
	boolean	options;
	extern	char	*myname;
	extern	char	*inet_ntoa();

	passw = NULL;
	options = TRUE;
	while (options) {

		/* Enable debugging flag and look for more options.
		 */
		if (argc > 1 && ! strcmp(argv[1], "-d")) {
			++argv;
			--argc;
			++debug;
			continue;
		}

		/* Prompt for a password if the -p option has been specified.
		 * If -p is specified a password is always used, even if the 
		 * authenticator works.
		 */
		if (argc > 1 && ! strcmp(argv[1], "-p")) {
			++argv;
			--argc;
			passw = getpass("Password: ", VD_CAPAB_LEN);
			continue;
		}

		/* Here if neither option was found.
		 */
		if (passw == NULL)
			passw = "";
		options = FALSE; /* Fall out of the option loop. */
	}

	if (argc < 1 || 3 < argc) {
		fprintf(stderr,"usage: %s [-d] [-p] [server] [file]\n", myname);
		exit(1);
	}

	/* File name takes precedence over server name.
	 */
	if (argc > 1)
		if ((fd = open(argv[argc - 1], 0)) < 0) {
			perror(argv[argc - 1]);
			exit(2);
		}

	if (fd != -1) {
		fclose(stdin);
		if (fdopen(fd, "r") != stdin) {
			fprintf(stderr, "%s: can't happen!\n", myname);
			exit(-69);
		}
	}



	/* Pick up the server's name from the command line arguments if it
	 * was specified; otherwise use the local machine as the server.
	 */
	if (argc == 3) {
		server = argv[argc - 2];
	} else {
		if (gethostname(server_name, NAMELEN) != NULL) {
			perror(myname);
			exit(3);
		}
		server = server_name;
	}

	if (debug)
		fprintf(stderr, "connecting to %s\n", server);

	ctl_init(server);

	authent_ok = TRUE;
	while ((len = get_message(stdin, sbuf, BUFLEN)) > 0) {

		/*
		 * assert presence of "operation="
		 */
		if (strncmp(sbuf, "operation=", sizeof("operation=") - 1)) {
			fprintf(stderr, "%s: bad request:\n%s", myname, sbuf);
			continue;
		}
		csprintf(&sbuf[len], "password=%s\n", passw);


		/* Append an authenticator to the message.  If get_auth fails
		 * to create an authenticator then sbuf doesn't change.  Skip
		 * future get_auth calls if it ever fails.
		 */
#ifdef	KERBEROS
		if (authent_ok)
			authent_ok = get_auth(sbuf, server, myname, debug);
#endif	KERBEROS

		/*
		 * send request to server, no response is fatal
		 */
		if (ctl_reqst(sbuf, server, debug) == NORESPONSE)
			exit(-1);
	}

	exit(0);
}


/* Read the next message (until an empty line) from the specified input file
 * into the specified buffer, up to len characters.  Returns the size of the
 * message in bytes, or 0 if end-of-file or error.
 */

get_message(infile, buf, len)
register FILE	*infile;
register char	*buf;
int	len;
{
	register int	c;
	register int	left, l;

	/*
	 * throw away initial whitespace
	 */
	do
		if ((c = getc(infile)) == EOF)
			return(0);
	while (isspace(c));

	ungetc(c, infile);

	left = len;
	while (fgets(buf, left, infile) != NULL && *buf != '\n') {
		left -= (l = strlen(buf));
		buf += l;
	}
	return(len - left);
}

/* Send the request.  Return 0 if no error, 1 if timeout, 2 if failure.
 */

ctl_reqst(sbuf, server, debug)
	char	*sbuf;
{
	char	rbuf[BUFLEN];
	int	i;
	int	len;
	int	slen;
	char	*cp;

	if (debug) {
		fprintf(stderr, "sending:\n%s", sbuf);
		cp = sbuf + strlen(sbuf);
		if (*(cp-1) != '\n')
			fprintf(stderr, "\n");
	}

	/* Calculate the length of the buffer, taking into account
	 * escaped null characters.  (This was necessary for Kerberos.)
	 */
	cp = sbuf + strlen(sbuf);
	while (*(cp-1) == '\\') {
		cp++;
		cp   += strlen(cp);
	}
	slen = cp - sbuf;

	if ((i = ctl_exch(sbuf, slen, rbuf, BUFLEN, TIMEOUT, NRXMIT))
	  == 0) {
		fprintf(stderr, "%s: %s not responding\n", myname, server);
		return(NORESPONSE);
	}

	rbuf[i] = '\0';
	if (debug)
		fprintf(stderr, "received:\n%s", rbuf);

	if (! pkt_parse(rbuf))
		return(GARBAGE);

	if (! strcmp(k[0], "success"))
		return(SUCCESS);
	else {
		printf("%s: %s: %s (%s)\n", myname, server, V(_ERROR),
		  V(_KEYWORD));
		return(FAILURE);
	}
}


ctl_init_send_close(sbuf, server, debug)
{
int	exit_val;

	if (debug)
		fprintf(stderr, "connecting to %s\n", server);

	ctl_init(server);
	exit_val = ctl_reqst(sbuf, server, debug);
	ctl_close();
	return(exit_val);
}
