/*************************************************************

 Copyright (C) 2001, Eric Kratzer

 imp3client.c
 Client program for imp3sh named-pipe input/output.

 This software is part of imp3sh and released under the GNU
 GPL. Please see the included 'COPYING' file for more details.


 Description:

   This client will pass any commands given on the command line
   to a local imp3sh session running named-pipe I/O. Any output
   from the passed commands will be routed to stdout of this
   client.


 Example:

 1) Run imp3sh with filenames (to be used as named pipes)
    as args:

    >imp3sh -i ~/tempin -o ~/tempout &

    NOTE: imp3sh will create the named pipes if they do not
          already exist.

 2) Run this client program with named pipes and commands
    as args:

    >imp3client ~/tempin ~/tempout <commands>

    NOTE: After the imp3client program has successfully 
          written the command(s) to the input pipe, it will
          automatically exit after 1 second of inactivity on
	  the output pipe. If you do not want to wait for 
	  output, use the '-n' switch as the first argument.

**************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <string.h>

void print_usage(char *prog)
{
    fprintf(stderr, "Usage: %s [-n] <in_fifo> <out_fifo> <commands>\n",
	    prog);
    exit(1);
}

int main(int argc, char *argv[])
{
    char *infifo, *outfifo, bail, no_output, commands[1024], output[8192];
    int fd, fd2, ret, maxfd, count, len, iln, ndx;
    fd_set read_set, write_set;
    struct timeval tv;

    fd2 = 0;

    if (argc < 4)
	print_usage(*argv);

    if (strcmp(argv[1], "-n") == 0) {
	if (argc < 5)
	    print_usage(*argv);
	infifo = argv[2];
	outfifo = argv[3];
	no_output = 1;
	ndx = 4;
    } else {
	infifo = argv[1];
	outfifo = argv[2];
	no_output = 0;
	ndx = 3;
    }

    if (!no_output) {
	fd2 = open(outfifo, O_RDONLY | O_NONBLOCK);
	if (fd2 == -1) {
	    fprintf(stderr,
		    "Error opening \"%s\" : %s\n", argv[2],
		    strerror(errno));
	    exit(1);
	}
    }

    fd = open(infifo, O_WRONLY);
    if (fd == -1) {
	fprintf(stderr, "Error opening \"%s\" : %s\n", argv[1],
		strerror(errno));
	exit(1);
    }

    *commands = '\0';
    for (count = ndx; count < argc; count++) {
	strcat(commands, argv[count]);
	if ((count + 1) != argc)
	    strcat(commands, " ");
    }
    strcat(commands, "\n");

    len = strlen(commands);
    count = bail = 0;

    while (1) {
	FD_ZERO(&read_set);
	FD_ZERO(&write_set);
	maxfd = 0;

	if (count < len) {
	    FD_SET(fd, &write_set);
	    maxfd = fd + 1;
	} else if (!bail) {
	    close(fd);
	    bail = 1;
	    if (no_output)
		exit(0);
	}

	if (!no_output) {
	    FD_SET(fd2, &read_set);
	    if (fd2 >= maxfd)
		maxfd = fd2 + 1;
	}

	tv.tv_sec = 1;
	tv.tv_usec = 0;

	ret = select(maxfd, &read_set, &write_set, NULL, &tv);

	if (count < len) {

	    if (FD_ISSET(fd, &write_set))
		write(fd, (commands + count++), 1);
	    else {
		close(fd);
		if (!no_output)
		    close(fd2);
		exit(1);
	    }

	}

	if (!no_output) {
	    if (FD_ISSET(fd2, &read_set)) {
		iln = read(fd2, output, 8191);
		if (iln <= 0) {
		    close(fd2);
		    exit(1);
		} else
		    write(1, output, iln);
	    } else if (bail) {
		close(fd2);
		exit(0);
	    }
	}
    }

    return 0;
}
