#include "global.h"
#include "commands.h"
#include "mbuf.h"
#include "netuser.h"
#include "md5.h"
#include "files.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: rtcli.c,v 1.1 1997/09/14 14:37:46 root Exp $";
#endif

#ifdef ENCAP

static int Slock = -1;
static int routesend (int s, char *challenge);

#define RetryInterval		60
#define KeepAliveInterval	60


int
routecli0 (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
	Slock = -1;
	return 0;
}



int
routecli1 (int argc, char *argv[], void *p OPTIONAL)
{
struct mbuf *bp;
char challenge[80], *cp;
int done;
int s;
struct sockaddr_in fsocket;

	/* handle the administrivia on sockets */
	server_disconnect_io ();

	if (Slock != -1)	{
		/* output error message and exit */
		tcmdprintf ("Route client already active! Aborting...\n");
		return 1;
	}

	/* initialize the address/port for the connection from user parameters */
	fsocket.sin_family = AF_INET;
	if (argc < 3)
		fsocket.sin_port = IPPORT_ROUTE;
	else
		fsocket.sin_port = (int16) atoip (argv[2]);

	if ((fsocket.sin_addr.s_addr = resolve (argv[1])) == 0) {
		tcmdprintf (Badhost, argv[1]);
		return 1;
	}

	/* let everyone know we're here! */
	tcmdprintf ("Starting route client to %s on port %d\n", argv[1], fsocket.sin_port);
	log(-1, "open Route Client");

	do	{
		done = 0;

		/* open a new socket */
		if ((s = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
			tcmdprintf (Nosock);
			return 1;
		}

		/* open a connection to the remote site */
		if (connect (s, (char *) &fsocket, SOCKSIZE) == -1)	{
			tcmdprintf ("Route client connection to %s failed! Retry in %d seconds\n", argv[1], RetryInterval);
			log (-1, "Route client connection to %s failed! Retry in %d seconds\n", argv[1], RetryInterval);
			done = 1;
		}
		Slock = s;
		log(-1, "Route Client Connected: %s", argv[1]);

		/* read header string */
		if (!done && (recv_mbuf (s, &bp, 0, NULLCHAR, 0) == -1 || !bp || !bp->data))
			done = 1;

		if (!done && bp && bp->data)	{
			cp = strrchr ((char *)bp->data, '<');
			if (cp == NULLCHAR)	{
				done = 1;
				/* log and abort */
				log (s, "No challenge string received from remote\n");
				done = 1;
			} else	{
				rip (cp);
				strcpy (challenge, cp);
	
				if (routesend (s, challenge) <= 0)	{
					/* none sent, exit */
					log (-1, "No routes to send to remote - aborting...\n");
					done = 1;
					Slock = -1;
				}
			}
		}
	
		/* stay up until killed */
		while (!done && Slock != -1)	{
			kpause (KeepAliveInterval * 1000L);
			/* also check for disconnections from the server.
			   send 'NOOP' commands, and check for "+OK" response.
			 */
			usprintf (s, "NOOP\n");
			if (recv_mbuf (s, &bp, 0, NULLCHAR, 0) == -1 || !bp || !bp->data)
				done = 1;
			else	{
				if (strncmp ((char *)bp->data, "+OK ", 4))
					done = 1;
			}
		}
		close_s (s);
		log(-1, "Route Client Disconnected: %s", argv[1]);
		if (Slock != -1)
			kpause (RetryInterval * 1000L);
	} while (Slock != -1);
	
	log(s, "close Route Client");
	return 0;
}



static int
routesend (int s, char *challenge)
{
FILE *fp;
char buf[80], *rt, *auth, *cp;
MD5_CTX mdContext;
char missive[80];
unsigned char *dp, *ep;
int sent = 0;
struct mbuf *bp;

	/* this function looks up the given route in the 'etc/encap-rt.dat'
	   file. The format of each line in that file is:

	   routestring		authenticationstring

	 */
	if ((fp = fopen (EncapRoutes, READ_TEXT)) == NULLFILE)
		return sent;

	while (fgets (buf, 80, fp))	{
		rip (buf);
		rt = skipwhite (buf);
		if (!*rt || *rt == '#')
			continue;		/* skip comment lines */
		auth = skipnonwhite (rt);
		if (!*auth)
			continue;
		*auth++ = 0;

		auth = skipwhite (auth);
		if (!*auth)
			continue;

		/* now look for trailing white space and remove if found */
		cp = skipnonwhite (auth);
		if (*cp)
			*cp = 0;

		/* now calculate the MD5 string that we SHOULD have received */
		MD5Init (&mdContext);
		MD5Update (&mdContext, (unsigned char *) challenge, strlen (challenge));
		MD5Update (&mdContext, (unsigned char *) rt, strlen (rt));
		MD5Update (&mdContext, (unsigned char *) auth, strlen (auth));
		MD5Final (&mdContext);

		cp = missive;
		dp = mdContext.digest;
		ep = dp + sizeof (mdContext.digest);
		for (; dp < ep; cp += 2)
			(void) sprintf (cp, "%02x", *dp++ & 0xff);
		*cp = '\0';

		usprintf (s, "route %s %s\n", rt, missive);
		sent++;
		
		if (recv_mbuf (s, &bp, 0, NULLCHAR, 0) == -1 || !bp || !bp->data)
			break;
		if (!strncmp ("-ERR ", (char *) bp->data, 5))	{
			(void) fclose (fp);
			return -1;
		}
	}

	(void) fclose (fp);
	return sent;
}

#endif /* ENCAP */
