#ifndef lint
static char *RCSid = "$Header: servercmd.c,v 1.17 89/09/26 19:51:38 mr-frog Exp $";
#endif /* not lint */

/*
 * servercmd.c
 *
 * Change the state depending on the command from the server.
 *
 * Dave Pare, 1989
 */

#include "misc.h"
#include "proto.h"
#include "queue.h"
#include "ioqueue.h"

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

int
servercmd(ioq, auxfi)
	struct	ioqueue *ioq;
	FILE *auxfi;
{
	char	buf[1024];
	char	*p;
	int	code;
	int	i;

	while (ioq_gets(ioq, buf, sizeof(buf))) {
		p = buf;
		while (*p && !isspace(*p))
			p++;
		*p++ = 0;
		if (isalpha(*buf))
			code = 10 + (*buf - 'a');
		else
			code = *buf - '0';
		switch (code) {
		case C_PROMPT:
			prompt(p, auxfi);
			break;
		case C_REDIR:
			doredir(p);
			break;
		case C_PIPE:
			dopipe(p);
			break;
		case C_FLUSH:
			/*
			 * A prompt, but not a command-line one.
			 * As such, don't redir it.
			 */
			for (i = 0; *p; p++, i++) {
				buf[i] = *p;
				if (*p == '%')
					buf[++i] = '%';
			}
			buf[i] = 0;
			p = buf;
			printf(p);
			fflush(stdout);
			if (auxfi) {
			    fprintf(auxfi, p);
			    fflush(auxfi);
			}
			break;
		case C_EXECUTE:
			doexecute(p, auxfi);
			break;
		default:
			output(code, p, auxfi);
			break;
		}
	}
}

FILE	*redir_fp;
FILE	*pipe_fp;
int	exec_fd;

prompt(line, auxfi)
	char	*line;
	FILE	*auxfi;
{
	int	nbtu;
	int	nmin;

	if (redir_fp) {
		(void) fclose(redir_fp);
		redir_fp = 0;
	} else if (pipe_fp) {
		(void) pclose(pipe_fp);
		pipe_fp = 0;
	} else if (exec_fd > 0) {
		close(exec_fd);
		close(0);
		exec_fd = -1;
		open("/dev/tty", O_RDONLY, 0);
	}
	if (sscanf(line, "%d %d", &nbtu, &nmin) != 2) {
		fprintf(stderr, "prompt: bad server prompt %s\n", line);
	}
	printf("\n[%d:%d] Command : ", nbtu, nmin);
	(void) fflush(stdout);
	if (auxfi) {
	    fprintf(auxfi, "\n[%d:%d] Command : ", nbtu, nmin);
	    (void)fflush(auxfi);
	}
}

/*
 * opens redir_fp if successful
 */
doredir(p)
	char	*p;
{
	char	*how;
	char	*name;
	int	mode;
	int	fd;

	if (redir_fp) {
		(void) fclose(redir_fp);
		redir_fp = 0;
	}
	how = p++;
	if (*p && ((*p == '>') || (*p == '!')))
		p++;
	while (*p && isspace(*p))
		p++;
	name = p;
	while (*p && !isspace(*p))
		p++;
	*p = 0;
	mode = O_WRONLY | O_CREAT;
	if (how[1] == '>')
		mode |= O_APPEND;
	else if (how[1] == '!')
		mode |= O_TRUNC;
	else
		mode |= O_EXCL;
	if (*name == 0) {
		fprintf(stderr, "Null file name after redirect\n");
		return;
	}
	if ((fd = open(name, mode, 0600)) < 0) {
		fprintf(stderr, "Redirect open failed\n");
		perror(name);
	} else {
		redir_fp = fdopen(fd, "w");
	}
}

/*
 * opens "pipe_fp" if successful
 */
dopipe(p)
	char	*p;
{
	extern	FILE *popen();

	if (*p == '|')
		p++;
	while (*p && isspace(*p))
		p++;
	if (*p == 0) {
		fprintf(stderr, "Null program name after redirect\n");
		return;
	}
	if ((pipe_fp = popen(p, "w")) == 0) {
		fprintf(stderr, "Pipe open failed\n");
		perror(p);
	}
}

doexecute(p, auxfi)
	char	*p;
	FILE 	*auxfi;
{
	extern	int sock;
	int	fd;

	while (*p && isspace(*p))
		p++;
	if (p == 0) {
		fprintf(stderr, "Null file to execute\n");
		return;
	}
	if ((fd = open(p, O_RDONLY, 0)) < 0) {
		fprintf(stderr, "Can't open execute file\n");
		perror(p);
		return;
	}
	/* copies 4k at a time to the socket */
	termio(fd, sock, auxfi);
	sendeof(sock);
	close(fd);
}

char	*SO;
char	*SE;

output(code, buf, auxfi)
	int	code;
	char	*buf;
	FILE    *auxfi;
{
	switch (code) {
	case C_NOECHO:
		_noecho(0);
		break;
	case C_FLUSH:
		(void) fflush(stdout);
		if (auxfi)
		    (void) fflush(auxfi);
		break;
	case C_ABORT:
		printf("Aborted\n");
		if (auxfi)
		    fprintf(auxfi, "Aborted\n");
		break;
	case C_CMDERR:
	case C_BADCMD:
		printf("Error; ");
		if (auxfi)
		    fprintf(auxfi, "Error; ");
		break;
	case C_EXIT:
		printf("Exit: ");
		if (auxfi)
		    fprintf(auxfi, "Exit: ");
		break;
	default:
		break;
	}
	if (auxfi) {
		fprintf(auxfi, "%s", buf);
		if (code == C_FLUSH)
		    (void) fflush(auxfi);
		else
		    (void) putc('\n', auxfi);
	}

	if (redir_fp)
		fprintf(redir_fp, "%s\n", buf);
	else if (pipe_fp)
		fprintf(pipe_fp, "%s\n", buf);
	else {
		if (SO && SE)
			screen(buf);
		else
			fputs(buf, stdout);
		if (code == C_FLUSH)
			(void) fflush(stdout);
		else
			(void) putc('\n', stdout);
	}
}

screen(buf)
	register char *buf;
{
	register char *sop;
	register char c;

	while (c = *buf++) {
		if (c & 0x80) {
			for (sop = SO; putc(*sop, stdout); sop++)
				;
			(void) putc(c & 0x7f, stdout);
			for (sop = SE; putc(*sop, stdout); sop++)
				;
		} else
			(void) putc(c, stdout);
	}
}
