/* CVS legacy :ext: interface
    Copyright (C) 2004 Tony Hoyle and March-Hare Software Ltd

    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
*/
#include "stdafx.h"

#include <config.h>
#include <cvstools.h>

static void writethread(void *p);

static cvsroot root;
static int trace;

static int extnt_output(const char *str, size_t len)
{
	return printf("M %-*.*s",len,len,str);
}

static int extnt_error(const char *str, size_t len)
{
	return printf("E %-*.*s",len,len,str);
}

static int extnt_trace(int level, const char *str)
{
	OutputDebugString(str);
	OutputDebugString("\r\n");
	printf("%s\n",str);
	return 0;
}

void usage()
{
	fprintf(stderr,"Usage: extnt.exe hostname [-l username] [-p protocol] [-d directory] [command..]\n");
	fprintf(stderr,"\t-l username\tUsername to use (default current user).\n");
	fprintf(stderr,"\t-p protocol\tProtocol to use(default sspi).\n");
	fprintf(stderr,"\t-d directory\tDirectory part of root string.\n");
	fprintf(stderr,"\t-P password\tPassword to use.\n");
	fprintf(stderr,"\nUnspecified parameters are also read from [<hostname>] section in extnt.ini.\n");
	exit(-1);
}

/* Standard :ext: invokes with <hostname> -l <username> cvs server */
int main(int argc, char *argv[])
{
	CProtocolLibrary lib;
	char protocol[1024],hostname[1024],directory[1024],password[1024];
	char *section, *username = NULL, *repos = NULL, *prot = NULL, *passw = NULL;
	char buf[8000];

	if(argc<2)
		usage();

	section = argv[1];

	if(section[0]=='-')
		usage(); /* Options come *after* hostname */

	argv+=2;
	argc-=2;

	while(argc && argv[0][0]=='-')
	{
		if(argc<2)
			usage();
		int a=1;
		switch(argv[0][1])
		{
		case 'l':
			username=argv[1]; a++;
			break;
		case 'd':
			repos=argv[1]; a++;
			break;
		case 'p':
			prot=argv[1]; a++;
			break;
		case 'P':
			passw=argv[1]; a++;
			break;
		case 't':
			trace++;
			CServerIo::loglevel(trace);
			break;
		default:
			usage();
		}
		argv+=a;
		argc-=a;
	}

	// Any remaining arguments (usually 'cvs server') are ignored

	CServerIo::init(extnt_output,extnt_output,extnt_error,extnt_trace);

    WSADATA data;

    if (WSAStartup (MAKEWORD (1, 1), &data))
    {
		fprintf (stderr, "cvs: unable to initialize winsock\n");
		return -1;
    }

	setmode(0,O_BINARY);
	setmode(1,O_BINARY);
	setvbuf(stdin,NULL,_IONBF,0);
	setvbuf(stdout,NULL,_IONBF,0);

	lib.SetupServerInterface(&root,0);

	_snprintf(buf,sizeof(buf),"%s/extnt.ini",CGlobalSettings::GetConfigDirectory());

	if(prot)
		strcpy(protocol,prot);
	else
		GetPrivateProfileString(section,"protocol","sspi",protocol,sizeof(protocol),buf);
	GetPrivateProfileString(section,"hostname",section,hostname,sizeof(hostname),buf);
	if(repos)
		strcpy(directory,repos);
	else
		GetPrivateProfileString(section,"directory","",directory,sizeof(directory),buf);
	
	if(passw)
		strcpy(password,passw);
	else
		GetPrivateProfileString(section,"password","",password,sizeof(password),buf);

	root.method=protocol;
	root.hostname=hostname;
	root.directory=directory;
	root.username=username;
	root.password=password;

	if(!directory[0])
	{
		printf("error 0 [extnt] directory not specified in [%s] section of extnt.ini\n",section);
		return -1;
	}

	const struct protocol_interface *proto = lib.LoadProtocol(protocol);
	if(!proto)
	{
		printf("error 0 [extnt] Couldn't load procotol %s\n",protocol);
		return -1;
	}

	switch(proto->connect(proto, 0))
	{
	case CVSPROTO_SUCCESS: /* Connect succeeded */
		{
			char line[1024];
			int l = proto->read_data(proto,line,1024);
			line[l]='\0';
			if(!strcmp(line,"I HATE YOU\n"))
			{
				printf("error 0 [extnt] connect aborted: server %s rejeced access to %s\n",hostname,directory);
				return -1;
			}
			if(!strncmp(line,"cvs [",5))
			{
				printf("error 0 %s",line);
				return -1;
			}
			if(strcmp(line,"I LOVE YOU\n"))
			{
				printf("error 0 [extnt] Unknown response '%s' from protocol\n", line);
				return -1;
			}
			break;
		}
	case CVSPROTO_SUCCESS_NOPROTOCOL: /* Connect succeeded, don't wait for 'I LOVE YOU' response */
		break;
	case CVSPROTO_FAIL: /* Generic failure (errno set) */
		printf("error 0 [extnt] Connection failed\n");
		return -1;
	case CVSPROTO_BADPARMS: /* (Usually) wrong parameters from cvsroot string */
		printf("error 0 [extnt] Bad parameters\n");
		return -1;
	case CVSPROTO_AUTHFAIL: /* Authorization or login failed */
		printf("error 0 [extnt] Authentication failed\n");
		return -1;
	case CVSPROTO_NOTIMP: /* Not implemented */
		printf("error 0 [extnt] Not implemented\n");
		return -1;
	}

	_beginthread(writethread,0,(void*)proto);
	do
	{
		int len = proto->read_data(proto,buf,sizeof(buf));
		if(len==-1)
		{
			exit(-1); /* dead bidirectionally */
		}
		if(len)
			write(1,buf,len);
		Sleep(50);
	} while(1);

    return 0;
}

void writethread(void *p)
{
	const struct protocol_interface *proto = (const struct protocol_interface *)p;
	char buf[8000];

	do
	{
		int len = read(0,buf,sizeof(buf));
		/* stdin returns 0 when its input pipe goes dead */
		if(len<1)
		{
			exit(0); /* Dead bidirectionally */
		}
		proto->write_data(proto,buf,len);
		Sleep(50);
	} while(1);
}


syntax highlighted by Code2HTML, v. 0.9.1