/*
** The cvsgui protocol used by WinCvs
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
** 
** This library 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
** Lesser General Public License for more details.
** 
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/*
 * Author : Alexandre Parenteau <aubonbeurre@hotmail.com> --- November 1999
 */

/*
 * cvsgui.c --- glue code for communicating with cvs over pipes
 */

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

#include <string.h>
#include <stdio.h>

#include "cvsgui_process.h"
#include "cvsgui_protocol.h"

#undef main
#undef getpass
#undef getenv
#undef exit

#ifdef WIN32
	extern char *getpass(const char *prompt);
#endif

pipe_t _cvsgui_readfd = 0;
pipe_t _cvsgui_writefd = 0;

static long outseek;
static long errseek;
static char *outname;
static char *errname;
static FILE *outlog;
static FILE *errlog;

char * cvsguiglue_getenv(const char *env)
{
	char *res = 0L;

	if(_cvsgui_readfd == 0)
		return getenv(env);

	cvsguiglue_flushconsole(1);

	if(env && gp_getenv_write (_cvsgui_writefd, env))
	{
		res = gp_getenv_read(_cvsgui_readfd);;
	}

	return res;
}

char * cvsguiglue_getpass(const char *prompt)
{
	if(_cvsgui_readfd == 0)
		return getpass(prompt);

	return cvsguiglue_getenv("CVS_GETPASS");
}

void cvsguiglue_exit(int code)
{
	if(_cvsgui_writefd != 0)
		gp_quit_write (_cvsgui_writefd, code);
	exit(code);
}

static void reopen_consoles(void)
{
#ifndef WIN32
    outname = tempnam(0L, 0L);
	if(outname == 0L)
	{
		fprintf(stderr, "Unable to open tmp file !\n");
		exit(1);
	}
    errname = tempnam(0L, 0L);
	if(errname == 0L)
	{
		fprintf(stderr, "Unable to open tmp file !\n");
		exit(1);
	}
	outlog = freopen(outname, "w+", stdout);
	if(outlog == 0L)
	{
		fprintf(stderr, "Unable to reopen stdout !\n");
		exit(1);
	}
	errlog = freopen(errname, "w+", stderr);
	if(errlog == 0L)
	{
		fprintf(stderr, "Unable to reopen stderr !\n");
		exit(1);
	}
	outseek = 0;
	errseek = 0;
#endif
}

static void
close_consoles(void)
{
#ifndef WIN32
	if(outlog != 0L)
		fclose(outlog);
	if(errlog != 0L)
		fclose(errlog);
	if(outname != 0L)
	{
		unlink(outname);
		free(outname);
	}
	if(errname != 0L)
	{
		unlink(errname);
		free(errname);
	}
#endif
}

static void
myflush(FILE *log, long *oldpos)
{
	long newpos, pos;
#	define BUF_SIZE 8000
	char buf[BUF_SIZE];
	size_t len;

	pos = fseek(log, *oldpos, SEEK_SET);
	if(pos != 0)
		goto fail;

	while(!feof(log) && !ferror(log))
	{
		len = fread(buf, sizeof(char), BUF_SIZE, log);
		if(len > 0)
		{
			if(log == outlog)
				gp_console_write (_cvsgui_writefd, buf, len, 0);
			if(log == errlog)
				gp_console_write (_cvsgui_writefd, buf, len, 1);
		}
	}

	if(ferror(log))
		goto fail;

	newpos = ftell(log);
	if(newpos < 0)
		goto fail;

	*oldpos = newpos;
	return;
fail:
	fprintf(stderr, "Unable to redirect stdout/stderr !\n");
}

void
cvsguiglue_flushconsole(int closeit)
{
	fflush(stdout);
	fflush(stderr);
#ifndef WIN32
	if(outlog != 0L)
		myflush(outlog, &outseek);
	if(errlog != 0L)
		myflush(errlog, &errseek);
	if(closeit)
		close_consoles();
#endif
}

int main(int argc, char *argv[])
{
	int res;
	char **tmparg = 0L;

	if(argc >= 4 && strcmp(argv[1], "-cvsgui") == 0)
	{
		int i;

		_cvsgui_readfd = (pipe_t)atoi (argv[2]);
		_cvsgui_writefd = (pipe_t)atoi (argv[3]);

		tmparg = (char **)malloc((argc - 2) * sizeof(char *));
		if(tmparg == 0L)
			goto ignore;

		tmparg[0] = argv[0];
		for(i = 4; i < argc; i++)
		{
			tmparg[i - 3] = argv[i];
		}
		tmparg[argc - 3] = 0L;
		argc -= 3;

		cvs_process_init();
		reopen_consoles();
	}

ignore:
	res = cvsguiglue_main(argc, tmparg != 0L ? tmparg :  argv);

	if(tmparg != 0L)
	{
		cvsguiglue_flushconsole(1);
		gp_quit_write (_cvsgui_writefd, res);
		free(tmparg);
	}

	return res;
}
