/*****************************************************************************
 *
 * File ..................: common/ftn.c
 * Purpose ...............: Fidonet Technology Network functions
 * Last modification date : 14-Sep-1999
 *
 *****************************************************************************
 * Copyright (C) 1997-1999
 *   
 * Michiel Broek		FIDO:		2:2801/16
 * Beekmansbos 10		Internet:	mbroek@ux123.pttnwb.nl
 * 1971 BV IJmuiden
 * the Netherlands
 *
 * This file is part of MBSE BBS.
 *
 * This BBS is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * MBSE BBS 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
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MBSE BBS; see the file COPYING.  If not, write to the Free
 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *****************************************************************************/

#include "../include/libs.h"
#include "../include/structs.h"
#include "../include/records.h"
#include "common.h"


#ifndef MAXUSHORT
#define MAXUSHORT 65535
#endif


void tidy_faddr(faddr *addr)
{
	if (addr == NULL) 
		return;
	if (addr->name) 
		free(addr->name);
	if (addr->domain) 
		free(addr->domain);
	free(addr);
}



faddr *parsefnode(char *s)
{
	faddr	addr, *tmp;
	char	*buf, *str, *p, *q, *n;
	int	good = 1;

	if (s == NULL) 
		return NULL;

	str = buf = xstrcpy(s);

	while (isspace(*str)) 
		str++;
	if (*(p=str+strlen(str)-1) == '\n') 
		*(p--) ='\0';
	while (isspace(*p)) 
		*(p--) = '\0';

	p=str + strlen(str) - 1;
	if (((*str == '(') && (*p == ')')) ||
	    ((*str == '\"') && (*p == '\"')) ||
	    ((*str == '\'') && (*p == '\'')) ||
	    ((*str == '<') && (*p == '>')) ||
	    ((*str == '[') && (*p == ']')) ||
	    ((*str == '{') && (*p == '}')))
	{
		str++;
		*p = '\0';
	}

	memset(&addr, 0, sizeof(faddr));
	if ((p = strrchr(str,' '))) {
		n = str;
		str = p + 1;
		while (isspace(*p)) 
			*(p--) = '\0';
		if (!strcasecmp(p - 2," of")) 
			*(p-2) = '\0';
		p -= 3;
		while (isspace(*p) || (*p == ',')) 
			*(p--) = '\0';
		if (strlen(n) > MAXNAME) 
			n[MAXNAME] = '\0';
		if (*n != '\0') 
			addr.name = xstrcpy(n);
	}

	if ((p = strrchr(str, '@'))) 
		*(p++) = '\0';
	else 
		if ((p = strrchr(str,'%'))) 
			*(p++) = '\0';
		else 
			p = NULL;

	if (p && ((q = strchr(p,'.')))) 
		*q = '\0';

	addr.point = 0;
	addr.node = 0;
	addr.net = 0;
	addr.zone = 0;
	addr.domain = xstrcpy(p);

	if ((p = strchr(str, ':'))) {
		*(p++) = '\0';
		if (strspn(str, "0123456789") == strlen(str))
			addr.zone = atoi(str);
		else 
			if (strcmp(str,"*") == 0)
				addr.zone = -1;
			else 
				good = 0;
		str = p;
	}

	if ((p = strchr(str, '/'))) {
		*(p++) = '\0';
		if (strspn(str, "0123456789") == strlen(str))
			addr.net = atoi(str);
		else 
			if (strcmp(str, "*") == 0)
				addr.net = -1;
			else 
				good = 0;
		str = p;
	}

	if ((p=strchr(str, '.'))) {
		*(p++) = '\0';
		if (strspn(str, "0123456789") == strlen(str))
			addr.node = atoi(str);
		else 
			if (strcmp(str, "*") == 0)
				addr.node = -1;
			else 
				good = 0;
		str = p;
	} else {
		if (strspn(str, "0123456789") == strlen(str))
			addr.node = atoi(str);
		else 
			if (strcmp(str, "*") == 0)
				addr.node = -1;
			else 
				good = 0;
		str = NULL;
	}

	if (str) {
		if (strspn(str, "0123456789") == strlen(str))
			addr.point = atoi(str);
		else 
			if (strcmp(str, "*") == 0)
				addr.point = -1;
			else 
				good = 0;
	}

	if (buf) 
		free(buf);

	if (good) {
		tmp = (faddr *)xmalloc(sizeof(addr));
		tmp->name   = NULL;
		tmp->domain = addr.domain;
		tmp->point  = addr.point;
		tmp->node   = addr.node;
		tmp->net    = addr.net;
		tmp->zone   = addr.zone;
		return tmp;
	} else {
		if (addr.name) 
			free(addr.name);
		if (addr.domain) 
			free(addr.domain);
		return NULL;
	}
}



char *ascinode(faddr *a, int fl)
{
	static char	buf[128], *f, *t;
//	dom_trans	*dt;
//	static char	*q;
//	fa_list		*tmpl;
	int		skip;

	if (a == NULL) {
		strcpy(buf,"<none>");
		return buf;
	}

	buf[0]='\0';
	if ((fl & 0x80) && (a->name))
	{
		if ((strchr(a->name,'.')) || (strchr(a->name,'@')) ||
		    (strchr(a->name,'\'')) || (strchr(a->name,',')) ||
		    (strchr(a->name,'<')) || (strchr(a->name,'>')))
			sprintf(buf+strlen(buf),"\"%s\" <",a->name);
		else
			sprintf(buf+strlen(buf),"%s <",a->name);
	}

	if ((fl & 0x40) && (a->name))
	{
		f=a->name;
		t=buf+strlen(buf);
		skip=0;
		while (*f)
		{
			switch (*f)
			{
			case '.':
			case ' ':	if (!skip) *t++='.'; skip=1; break;
			case '@':	skip=0; *t++='%'; break;
			case '"':
			case '>':
			case '<':
			case '\'':	skip=0; *t++='\\'; *t++=*f; break;
			default:	skip=0; *t++=*f; break;
			}
			f++;
		}
		*t++='@';
		*t++='\0';
	}

	if ((fl & 0x01) && (a->point))
		sprintf(buf+strlen(buf),"p%u.",a->point);
	if (fl & 0x02)
		sprintf(buf+strlen(buf),"f%u.",a->node);
	if (fl & 0x04)
		sprintf(buf+strlen(buf),"n%u.",a->net);
	if ((fl & 0x08) && (a->zone))
		sprintf(buf+strlen(buf),"z%u.",a->zone);
	buf[strlen(buf)-1]='\0';

	if (fl & 0x10) {
		if (a->domain)
			sprintf(buf+strlen(buf),".%s",a->domain);
	}

	if (fl & 0x20) {
		if (a->domain) {
			if ((fl & 0x10) == 0)
				sprintf(buf+strlen(buf),".%s",a->domain);
		} else {
//			for (tmpl=nllist;tmpl;tmpl=tmpl->next)
//				if (tmpl->addr->zone == a->zone) break;
//			if (tmpl && tmpl->addr->domain)
//				sprintf(buf+strlen(buf),".%s",
//					tmpl->addr->domain);
//			else
				sprintf(buf+strlen(buf),".fidonet");
		}

/*		for (dt=domtrans;dt;dt=dt->next) {
			q=buf+strlen(buf)-strlen(dt->ftndom);
			if ((q >= buf) && (strcasecmp(dt->ftndom,q) == 0))
			{
				strcpy(q,dt->intdom);
				break;
			}
		}
		if (dt == NULL) sprintf(buf+strlen(buf),".ftn"); */
	}

	if ((fl & 0x80) && (a->name))
		sprintf(buf+strlen(buf),">");

	return buf;
}



/*
 * Return ASCII string for node, the bits in 'fl' set the
 * output format.
 */
char *ascfnode(faddr *a, int fl)
{
	static char buf[128];

	if (a == NULL)
	{
		strcpy(buf, "<none>");
		return buf;
	}

	buf[0] = '\0';
	if ((fl & 0x40) && (a->name))
		sprintf(buf+strlen(buf),"%s of ",a->name);
	if ((fl & 0x08) && (a->zone))
		sprintf(buf+strlen(buf),"%u:",a->zone);
	if (fl & 0x04)
		sprintf(buf+strlen(buf),"%u/",a->net);
	if (fl & 0x02)
		sprintf(buf+strlen(buf),"%u",a->node);
	if ((fl & 0x01) && (a->point))
		sprintf(buf+strlen(buf),".%u",a->point);
	if ((fl & 0x10) && (a->domain))
		sprintf(buf+strlen(buf),"@%s",a->domain);
	return buf;
}



int metric(faddr *a1, faddr *a2)
{
	if ((a1->domain != NULL) &&
	    (a2->domain != NULL) &&
	    (strcasecmp(a1->domain,a2->domain) != 0))
		return METRIC_DOMAIN;
	if ((a1->zone != 0) && (a2->zone != 0) &&
	    (a1->zone != a2->zone)) return METRIC_ZONE;
	if (a1->net   != a2->net)   return METRIC_NET;
	if (a1->node  != a2->node)  return METRIC_NODE;
	if (a1->point != a2->point) return METRIC_POINT;
	return METRIC_EQUAL;
}



/*
 * Convert mbse style to ifcico style.
 */
faddr *fido2faddr(fidoaddr aka)
{
	faddr	*fa;
	char	*temp;

	temp = xstrcpy(aka.domain);
	fa = (faddr *)xmalloc(sizeof(faddr));
	fa->name   = NULL;
	fa->domain = temp;
	fa->zone   = aka.zone;
	fa->net    = aka.net;
	fa->node   = aka.node;
	fa->point  = aka.point;

	return fa;
}



/*
 * Convert ifcico style to mbse style
 */
fidoaddr *faddr2fido(faddr *aka)
{
	fidoaddr *Sys;

	Sys = (fidoaddr *)xmalloc(sizeof(fidoaddr));
	memset(Sys, 0, sizeof(Sys));
	Sys->zone  = aka->zone;
	Sys->net   = aka->net;
	Sys->node  = aka->node;
	Sys->point = aka->point;
	if (aka->domain != NULL)
		sprintf(Sys->domain, "%s", aka->domain);

	return Sys;
}



faddr *bestaka_s(faddr *addr)
{
	faddr	*best;
	int	i, minmetric, wt;

	best = fido2faddr(CFG.aka[0]);
	if (addr == NULL) 
		return best;
	minmetric = metric(addr, best);

	for (i = 0; i < 40; i++) {
		if (CFG.akavalid[i]) {
			wt = metric(addr, fido2faddr(CFG.aka[i]));

			if ((wt < minmetric) &&
			    ((best->point != 0) || (minmetric > METRIC_NODE)))
			/* In the same network, use node address even when routing
			   to the node where we have a point address */
			{
				minmetric = wt;
				best = fido2faddr(CFG.aka[i]);
			}
		}
	}
//	Syslog('s', "bestaka_s for %s is %s", xstrcpy(ascfnode(addr, 0x1f)), xstrcpy(ascfnode(best, 0x1f)));
	return best;
}



int is_local(faddr *addr)
{
	int	i;

	for (i = 0; i < 40; i++) {
		if ((CFG.akavalid[i]) &&
		    (metric(fido2faddr(CFG.aka[i]), addr) == METRIC_EQUAL))
			return TRUE;
	}
	return FALSE;
}


