/*
 *	Name:				address.c
 *
 * Description:	Routines for address manipulation
 *
 * Copyright:		1992-1993 by David Jones.
 *
 * Distribution:
 *		This program 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 of the License, or
 *		(at your option) any later version.
 *
 *		This program 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 this program; if not, write to:
 *
 *				The Free Software Foundation		David Jones
 *				675 Mass Ave							6730 Tooney Drive
 *				Cambridge, MA							Orleans, Ontario
 *				02139										K1C 6R4
 *				USA										Canada
 *
 *	Usenet:	gnu@prep.ai.mit.edu					dej@qpoint.ocunix.on.ca
 *	Fidonet:												1:163/109.8
 *
 *		$Log: $
 *
 */

#include <exec/types.h>
#include <string.h>
#include "xferq.h"
#include "xferqint.h"
#include "xferq_pragmas.h"
#include <utility/hooks.h>
#include <proto/utility.h>

char *DefaultDomain, *DefaultZone, *DefaultPoint;

void InitAddress(void)
/*
 *	Does:	Initializes the default address values.  These are hard-coded
 *			now, but will be read from a file eventually.
 */
{

	DefaultDomain = CopyString("Fidonet");
	DefaultZone = CopyString("1");
	DefaultPoint = CopyString("0");
}


struct NetAddress *GetTextAddress(char **strp)
/*
 *	In:	strp				Pointer to string to convert
 *
 * Does:	Attempts to convert an address in TEXT form.
 */
{
char *p, *oldp;
struct NetAddress *na;
char *temp;

	/*
	 *	First character must be a caret.
	 */
	p = *strp;
	if (*p++ != '^') {
		return NULL;
	}
	oldp = p;
	/*
	 * Anything goes for content.
	 */
	if (!GetAddrElement(&p, TRUE)) {
		return NULL;
	}
	/*
	 * OMS needs a null-terminated string so make one.
	 */
	temp = CopyStringN(oldp, p - oldp);
	if (!temp) {
		return NULL;
	}
	/*
	 * Create final address.
	 */
	na = AllocObject(0, XQO_ADDRESS);
	if (na) {
		na->type = XQNT_TEXT;
		na->addr.text = temp;
		*strp = p;
	}
	else {
		XfqDropObject(temp);
	}
	return na;
}


struct NetAddress *GetUucpAddress(char **strp)
/*
 *	In:	strp				Pointer to string to convert
 *
 * Does:	Attempts to convert an address in UUCP form.
 */
{
char *p, *oldp;
struct NetAddress *na;
char *temp;

	p = *strp;
	oldp = p;
	/*
	 * Machine name must be non-numeric and no periods!
	 */
	if (GetAddrElement(&p, FALSE) != ET_ALPHA) {
		return NULL;
	}
	/*
	 * OMS needs a null-terminated string so make one.
	 */
	temp = CopyStringN(oldp, p - oldp);
	if (!temp) {
		return NULL;
	}
	/*
	 * Create final address.
	 */
	na = AllocObject(0, XQO_ADDRESS);
	if (na) {
		na->type = XQNT_UUCP;
		na->addr.machine = temp;
		*strp = p;
	}
	else {
		XfqDropObject(temp);
	}
	return na;
}


struct NetAddress *GetFqdaAddress(char **strp)
/*
 *	In:	strp				Pointer to string to convert
 *
 * Does:	Attempts to convert an address in FQDA form.
 */
{
char *p, *oldp;
struct NetAddress *na;
char *temp;

	p = *strp;
	oldp = p;
	while (TRUE) {
		/*
		 * Each component must be non-numeric and no periods!
		 */
		if (GetAddrElement(&p, FALSE) != ET_ALPHA) {
			return NULL;
		}
		/*
		 *	If parse stopped at a period, then go for more.
		 */
		if (*p != '.') {
			break;
		}
		p++;
	}
	/*
	 * OMS needs a null-terminated string so make one.
	 */
	temp = CopyStringN(oldp, p - oldp);
	if (!temp) {
		return NULL;
	}
	/*
	 * Create final address.
	 */
	na = AllocObject(0, XQO_ADDRESS);
	if (na) {
		na->type = XQNT_FQDA;
		na->addr.fqda = temp;
		*strp = p;
	}
	else {
		XfqDropObject(temp);
	}
	return na;
}


struct NetAddress *GetFidoAddress(char **strp, struct NetAddress *base,
	int mand, int opt)
/*
 *	In:	strp				Pointer to string to parse
 *			base				Base address to use as model
 *			mand				Mandatory flags
 *			opt				Optional flags
 *
 * Does:	Attempts to parse a Fidonet address.
 */
{
char preDelim, postDelim;
struct NetAddress *na;
char *p, *oldp, *elem;
int type;

	postDelim = 0;
	p = *strp;
	if (base) {
		na = DupObject(base);
	}
	else {
		na = AllocObject(0, XQO_ADDRESS);
	}
	if (!na) {
		return NULL;
	}
	na->type = XQNT_FIDO;
	opt &= XQADDR_FIDO;
	mand &= XQADDR_FIDO;
	while (TRUE) {
		preDelim = postDelim;
		oldp = p;
		type = GetAddrElement(&p, FALSE);
		postDelim = *p;
		if (!type) {
			XfqDropObject(na);
			return NULL;
		}
		elem = CopyStringN(oldp, p - oldp);
		if (opt == XQADDR_DOMAIN || postDelim == '#' || preDelim == '@') {
			/*
			 * domain
			 *
			 * Replace the domain name, dropping old one if necessary.
			 * If element type is illegal, then the DropObject(na) drops
			 * the new element too.
			 */
			XfqDropObject(na->addr.fido.domain);
			na->addr.fido.domain = elem;
			if (type != ET_ALPHA || !(opt & XQADDR_DOMAIN)) {
				XfqDropObject(na);
				return NULL;
			}
			mand &= ~XQADDR_DOMAIN;
			if (postDelim == '#') {
				p++;
			}
			else {
				break;
			}
		}
		else if (opt == XQADDR_ZONE || postDelim == ':') {
			/* zone */
			XfqDropObject(na->addr.fido.zone);
			na->addr.fido.zone = elem;
			if (type != ET_NUMBER || !(opt & XQADDR_ZONE)) {
				XfqDropObject(na);
				return NULL;
			}
			mand &= ~XQADDR_ZONE;
			if (postDelim == ':') {
				p++;
			}
			else {
				break;
			}
		}
		else if (opt == XQADDR_NET || postDelim == '/' || preDelim == ':') {
			/* net */
			XfqDropObject(na->addr.fido.net);
			na->addr.fido.net = elem;
			if (type != ET_NUMBER || !(opt & XQADDR_NET)) {
				XfqDropObject(na);
				return NULL;
			}
			mand &= ~XQADDR_NET;
			if (postDelim == '/') {
				p++;
			}
			else {
				break;
			}
		}
		else if (opt == XQADDR_NODE ||  preDelim == '/') {
			/* node */
			XfqDropObject(na->addr.fido.node);
			na->addr.fido.node = elem;
			if (type != ET_NUMBER || !(opt & XQADDR_NODE)) {
				XfqDropObject(na);
				return NULL;
			}
			mand &= ~XQADDR_NODE;
			if (postDelim == '.' || postDelim == '@') {
				p++;
			}
			else {
				break;
			}
		}
		else if (opt == XQADDR_POINT || preDelim == '.') {
			/* point */
			XfqDropObject(na->addr.fido.point);
			na->addr.fido.point = elem;
			if (type != ET_NUMBER || !(opt & XQADDR_POINT)) {
				XfqDropObject(na);
				return NULL;
			}
			mand &= ~XQADDR_POINT;
			if (postDelim == '@') {
				p++;
			}
			else {
				break;
			}
		}
		else {
			XfqDropObject(na);
			return NULL;
		}
	}
	/* end of address */
	if (mand) {
		XfqDropObject(na);
		return NULL;
	}
	else {
		*strp = p;
		CanonAddress(na);
		return na;
	}
}


struct NetAddress *__saveds __asm LIBGetAddress(register __a0 char *string,
	register __a1 struct NetAddress *addr,
	register __a2 struct TagItem *tags)
/*
 *	In:	string	A0		Pointer to string to convert
 *			addr		A1		Template for converted address
 *			tags		A2		Taglist controlling operation
 *
 * Does:	Replaces the elements of addr with new values based on the
 *			input string.  The user flags indicate which types of input
 *			are valid, and may be used to resolve ambiguous situations.
 *
 *			Valid tags are:
 *				XQ_EndPos		Write a pointer to the first illegal char
 *									into data field.
 *				XQ_Mandatory	Data is bitset of mandatory fields
 *				XQ_Optional		Data is bitset of optional fields
 *				XQ_SpaceDelim	TRUE if spaces are permitted.
 */
{
struct NetAddress *na;
int mand, opt;
char *p, *oldp, *atp;
char **endPos;
BOOL spaceDelim;
char *userName;
ULONG *errp;

	mand = GetTagData(XQ_Mandatory, 0, tags);
	opt = GetTagData(XQ_Optional, 0, tags);
	spaceDelim = GetTagData(XQ_SpaceDelim, TRUE, tags);
	
	/*
	 *	atp holds pointer to stuff after username.
	 */
	p = string;
	userName = NULL;
	oldp = p;
	if (GetAddrElement(&p, TRUE) == ET_ALPHA) {
		/*
		 *	Got what might be a user name.  If next char is '@' then
		 * make the user name.
		 */
		atp = p;
		if (spaceDelim && *p == ' ') {
			atp++;
		}
		if (*atp == '@') {
			userName = CopyStringN(oldp, p - oldp);
			if (!userName) {
				return NULL;
			}
			atp++;
			if (spaceDelim && *atp == ' ') {
				atp++;
			}
		}
	}
	if (!userName) {
		atp = string;
	}
	na = NULL;
	p = atp;
	if (addr) {
		switch (addr->type) {
		case XQNT_FIDO:
			na = GetFidoAddress(&p, addr, mand, opt);
			break;
		case XQNT_UUCP:
			na = GetUucpAddress(&p);
			break;
		case XQNT_FQDA:
			na = GetFqdaAddress(&p);
			break;
		case XQNT_TEXT:
			na = GetTextAddress(&p);
			break;
		}
	}
	if (!na) {
		if (opt & XQADDR_FIDO) {
			p = atp;
			na = GetFidoAddress(&p, addr, mand, opt);
		}
		if (!na && (opt & XQADDR_MACHINE)) {
			p = atp;
			na = GetUucpAddress(&p);
		}
		if (!na && (opt & XQADDR_FQDA)) {
			p = atp;
			na = GetFqdaAddress(&p);
		}
		if (!na && (opt & XQADDR_TEXT)) {
			p = atp;
			na = GetTextAddress(&p);
		}
	}
	if (na) {
		na->userName = userName;
	}
	else {
		errp = PeekError();
		if (*errp != XQERROR_NOMEM) {
			*errp = XQERROR_BADADR;
		}
		XfqDropObject(userName);
	}
	endPos = (char **)GetTagData(XQ_EndPos, NULL, tags);
	if (endPos) {
		*endPos = p;
	}
	SetErrorTags(tags);
	return na;
}


LONG StrAECmp(char *left, char *right)
/*
 *	In:	left, right		Pointers to items to compare
 *
 * Does:	Compares two address elements and returns less/greater/equal.
 */
{

	if (!left) {
		return (right != NULL);
	}
	else if (!right) {
		return 1;
	}
	else {
		return Stricmp(left, right);
	}
}


LONG NumAECmp(char *left, char *right)
/*
 *	In:	left, right		Pointers to items to compare
 *
 * Does:	Compares two numeric address elements and returns delta.
 */
{
LONG nleft, nright;

	nleft = nright = 0;
	if (left) {
		GetNumber(left, 10, 5, &nleft);
	}
	if (right) {
		GetNumber(right, 10, 5, &nright);
	}
	return nleft - nright;
}


LONG SimpleCmpAddress(struct NetAddress *left, struct NetAddress *right,
	int mand)
/*
 *	In:	left, right		Pointers to addresses to compare
 *			mand				Bit mask of mandatory items
 *
 * Does:	Compares two addresses and returns a delta based on the
 *			difference.
 */
{
LONG delta;

	delta = left->type - right->type;
	if (delta) {
		return delta;
	}
	switch (left->type) {
	case XQNT_UUCP:
			return StrAECmp(left->addr.machine, right->addr.machine);
	case XQNT_FQDA:
			return StrAECmp(left->addr.fqda, right->addr.fqda);
	case XQNT_TEXT:
			return StrAECmp(left->addr.text, right->addr.text);
	case XQNT_FIDO:
		if (mand & XQADDR_DOMAIN) {
			delta = StrAECmp(left->addr.fido.domain, right->addr.fido.domain);
			if (delta) {
				return delta;
			}
		}
		if (mand & XQADDR_ZONE) {
			delta = NumAECmp(left->addr.fido.zone, right->addr.fido.zone);
			if (delta) {
				return delta;
			}
		}
		if (mand & XQADDR_NET) {
			delta = NumAECmp(left->addr.fido.net, right->addr.fido.net);
			if (delta) {
				return delta;
			}
		}
		if (mand & XQADDR_NODE) {
			delta = NumAECmp(left->addr.fido.node, right->addr.fido.node);
			if (delta) {
				return delta;
			}
		}
		if (mand & XQADDR_POINT) {
			return NumAECmp(left->addr.fido.point, right->addr.fido.point);
		}
		return 0;
	}
}


LONG __saveds __asm LIBCmpAddress(register __a0 void *left,
	register __a1 void *right,
	register __a2 struct TagItem *tags)
/*
 *	In:	left		A0		"Left" address or session
 *			right		A1		"Right" address or session
 *			tags		A2		Taglist controlling operation
 * 
 * Does:	Compares left and right.  Returns:
 *				>0	if left > right
 *				 0	if left = right
 *				<0 if left < right
 *
 *			Either left or right may be a session; in this case equality
 *			is returned if any address in left is equivalent to any address
 *			in right.
 *
 *			Valid tags are:
 *				XQ_Mandatory	Indicates fields that are to be used in
 *									comparison (default all).
 */
{
int mand,result;

	mand = GetTagData(XQ_Mandatory, XQADDR_ALLBUTUSER, tags);
	result = SimpleCmpAddress(left, right, mand);
	return result;
}


struct NetAddress *__saveds __asm LIBMap(
	register __a0 struct NetAddress *addr,
	register __a1 struct TagItem *tags)
/*
 *	In:	addr		A0		Address to map
 *			tags		A1		Taglist controlling operation
 *
 * Does:	Applies maps according to the tags to return a new address.
 *			Valid tags are:
 *				XQ_MapForward	Apply the map in the forward direction
 *				XQ_MapReverse	Apply the map in the reverse direction
 */
{

	return NULL;
}


ULONG __saveds __asm LIBFilter(register __a0 void *object,
	register __a1 struct TagItem *tags)
/*
 *	In:	object	A0		Address or session to filter
 *			tags		A1		Taglist controlling operation
 *
 * Does:	Tests the session or address against the filter condition.
 *			Returns TRUE if it passes, FALSE otherwise.  Valid tags are:
 *
 *				XQ_MapForward	Test against the left part of a map.
 *				XQ_MapReverse	Test against the right part of a map.
 *				XQ_Filter		Test against a filter
 *				XQ_Inclusive	If TRUE, all objects in the session must pass
 *									the filter.  Otherwise, only one need pass.
 */
{

	return FALSE;
}


char *SimplePutAddress(struct NetAddress *na, int mand, int opt,
	BOOL spaceDelim)
/*
 *	In:	na					Address to print
 *			mand				Bit mask of mandatory fields
 *			opt				Bit mask of optional fields
 *			spaceDelim		TRUE to insert spaces in Fido
 *
 * Does:	Creates a string and puts the given address in it.
 */
{
char *str;
int adrLen;
int partLen;

	str = AllocObject(20, XQO_STRING);
	if (!str) {
		return NULL;
	}
	*str = '\0';
	adrLen = 0;
	if (na->userName) {
		partLen = strlen(na->userName);
		str = NeedString(str, partLen + 4);	/* make room for ' @ ' */
		if (!str) {
			return NULL;
		}
		strcpy(str, na->userName);
		adrLen = partLen;
		if (na->addr.machine || na->addr.fqda || na->addr.text ||
			na->addr.fido.domain || na->addr.fido.zone ||
			na->addr.fido.net || na->addr.fido.node || na->addr.fido.point) {
			if (na->type == XQNT_FIDO && spaceDelim) {
				strcpy(str + adrLen, " @ ");
				adrLen += 3;
			}
			else {
				strcpy(str + adrLen, "@");
				adrLen++;
			}
		}
	}
	switch (na->type) {
	case XQNT_TEXT:
		partLen = strlen(na->addr.text);
		str = NeedString(str, partLen + 2);
		if (str) {
			str[partLen] = '^';
			strcpy(str + adrLen, na->addr.text);
		}
		return str;
	case XQNT_FQDA:
		partLen = strlen(na->addr.fqda);
		str = NeedString(str, partLen + 1);
		if (str) {
			strcpy(str + adrLen, na->addr.fqda);
		}
		return str;
	case XQNT_UUCP:
		partLen = strlen(na->addr.machine);
		str = NeedString(str, partLen + 1);
		if (str) {
			strcpy(str + adrLen, na->addr.machine);
		}
		return str;
	case XQNT_FIDO:
		/*
		 *	Determine which fields to print out.  mand's bits are set
		 * to indicate which fields must be printed.
		 */
		if (opt & XQADDR_DOMAIN && na->addr.fido.domain &&
			Stricmp(na->addr.fido.domain, DefaultDomain)) {
			mand |= XQADDR_DOMAIN;
		}
		if (opt & XQADDR_ZONE && na->addr.fido.zone &&
			Stricmp(na->addr.fido.zone, DefaultZone)) {
			mand |= XQADDR_ZONE;
		}
		if (opt & XQADDR_NET && na->addr.fido.net &&
			Stricmp(na->addr.fido.net, "0") &&
			Stricmp(na->addr.fido.net, "-1")) {
			mand |= XQADDR_NET;
		}
		if (opt & XQADDR_NODE && na->addr.fido.node &&
			Stricmp(na->addr.fido.node, "0") &&
			Stricmp(na->addr.fido.node, "-1")) {
			mand |= XQADDR_NODE;
		}
		if (opt & XQADDR_POINT && na->addr.fido.point &&
			Stricmp(na->addr.fido.point, "0")) {
			mand |= XQADDR_POINT;
		}
		if (opt & XQADDR_ATDOMAIN && na->addr.fido.domain &&
			Stricmp(na->addr.fido.domain, DefaultDomain)) {
			mand |= XQADDR_ATDOMAIN;
		}
		/*
		 * Protection: don't attempt to output fields that don't exist.
		 */
		if (!na->addr.fido.domain) {
			mand &= ~(XQADDR_DOMAIN | XQADDR_ATDOMAIN);
		}
		if (!na->addr.fido.zone) {
			mand &= ~XQADDR_ZONE;
		}
		if (!na->addr.fido.net) {
			mand &= ~XQADDR_NET;
		}
		if (!na->addr.fido.node) {
			mand &= ~XQADDR_NODE;
		}
		if (!na->addr.fido.point) {
			mand &= ~XQADDR_POINT;
		}
		/*
		 * Print required fields.
		 */
		if (mand & XQADDR_DOMAIN) {
			partLen = strlen(na->addr.fido.domain);
			str = NeedString(str, partLen + 2);
			if (!str) {
				return NULL;
			}
			strcpy(str + adrLen, na->addr.fido.domain);
			adrLen += partLen;
			if (mand & (XQADDR_ZONE | XQADDR_NET)) {
				str[adrLen++] = '#';
			}
		}
		if (mand & XQADDR_ZONE) {
			partLen = strlen(na->addr.fido.zone);
			str = NeedString(str, partLen + 2);
			if (!str) {
				return NULL;
			}
			strcpy(str + adrLen, na->addr.fido.zone);
			adrLen += partLen;
			if (mand & XQADDR_NET) {
				str[adrLen++] = ':';
			}
		}
		if (mand & XQADDR_NET) {
			partLen = strlen(na->addr.fido.net);
			str = NeedString(str, partLen + 2);
			if (!str) {
				return NULL;
			}
			strcpy(str + adrLen, na->addr.fido.net);
			adrLen += partLen;
			if (mand & XQADDR_NODE) {
				str[adrLen++] = '/';
			}
		}
		if (mand & XQADDR_NODE) {
			partLen = strlen(na->addr.fido.node);
			str = NeedString(str, partLen + 2);
			if (!str) {
				return NULL;
			}
			strcpy(str + adrLen, na->addr.fido.node);
			adrLen += partLen;
			if (mand & XQADDR_POINT) {
				str[adrLen++] = '.';
			}
		}
		if (mand & XQADDR_POINT) {
			partLen = strlen(na->addr.fido.point);
			str = NeedString(str, partLen + 2);
			if (!str) {
				return NULL;
			}
			strcpy(str + adrLen, na->addr.fido.point);
			adrLen += partLen;
			if (mand & XQADDR_ATDOMAIN) {
				str[adrLen++] = '@';
			}
		}
		if (na->addr.fido.domain && (mand & XQADDR_ATDOMAIN)) {
			partLen = strlen(na->addr.fido.domain);
			str = NeedString(str, partLen + 2);
			if (!str) {
				return NULL;
			}
			strcpy(str + adrLen, na->addr.fido.domain);
		}
	}
	return str;
}


struct PutAddrData {
	struct Hook hook;
	char **array;
	char *line;
	struct NetAddress *last;
	struct NetAddress *diff;
	short lineSize, mand, opt;
	BOOL delta, spaceDelim;
};


BOOL __asm PutSessAddress(register __a0 struct Hook *hook,
	register __a2 struct NetAddress *addr,
	register __a1 struct TagItem *tags)
/*
 *	In:	hook		A0		Pointer to hook/data structure
 *			addr		A2		Pointer to address to print
 *			tags		A1		Tag list passed to PutAddress (not used)
 *
 * Does:	Writes one address of the session into the array.
 */
{

	return FALSE;
}
		

char *__saveds __asm LIBPutAddress(register __a0 void *object,
	register __a1 struct TagItem *tags)
/*
 *	In:	object	A0		Pointer to address/session to output
 *			tags		A1		Taglist controlling operation
 *
 * Does:	Returns a string containing a printable form of the address.
 *			Valid tags are:
 *
 *				XQ_Mandatory	Data is fields that must be printed
 *				XQ_Optional		Data is fields that are printed if nonempty
 *				XQ_LineSize		This tag is used when a session is passed in.
 *									All addresses in the session are output in
 *									a single string whose maximum length is given
 *									by this tag.  Function returns array of these
 *									strings.
 *				XQ_Delta			If TRUE, then the differences between the
 *									current and previous addresses are used in
 *									determining if optional fields should be output.
 *				XQ_SpaceDelim	If TRUE, then spaces are output around '@'
 *									separating user name and Fidonet address.
 */
{
struct PutAddrData pad;
char *str;

	pad.mand = GetTagData(XQ_Mandatory, 0, tags);
	pad.opt = GetTagData(XQ_Optional, 0, tags);
	pad.spaceDelim = GetTagData(XQ_SpaceDelim, TRUE, tags);
	
	if (ObjectType(object) == XQO_ADDRESS) {
		str = SimplePutAddress(object, pad.mand, pad.opt, pad.spaceDelim);
		SetErrorTags(tags);
		return str;
	}
	/*
	else {
		pad.delta = GetTagData(XQ_Delta, FALSE, tags);
		pad.lineSize = GetTagData(XQ_LineSize, 79, tags);
		if (pad.delta) {
			pad.diff = AllocObject(XQO_ADDRESS, NULL);
			if (!pad.diff) {
				return NULL;
			}
		}
		pad.hook.h_Entry = PutSessAddress;
		pad.last = NULL;
		pad.array = NULL;
		pad.line = NULL;
		XfqWalkSessionCallBackTags(object,
			XQ_CallBack, &pad.hook,
			TAG_DONE);
		SetErrorTags(tags);
		return (char *)pad.array;
	} */
	Error(XQERROR_BADOBJECT);
	return NULL;
}


BOOL CanonAddress(struct NetAddress *na)
/*
 *	In:	na					User-supplied address
 *
 *	Does:	This function is a kludge that ensures that addresses conform
 *			to certain style guidelines for queue files.  The function
 *			returns an address derived from the given address through the
 *			following transformations:
 *
 *			FIDO			z:n/f -> Fidonet#z:n/f.0
 */
{

	if (na->type == XQNT_FIDO) {
		if (!na->addr.fido.domain || !strcmp(na->addr.fido.domain, "")) {
			na->addr.fido.domain = XfqCopyObject(DefaultDomain);
		}
		if (!na->addr.fido.zone || !strcmp(na->addr.fido.zone, "")) {
			na->addr.fido.zone = XfqCopyObject(DefaultZone);
		}
		if (!na->addr.fido.point || !strcmp(na->addr.fido.point, "")) {
			na->addr.fido.point = XfqCopyObject(DefaultPoint);
		}
	}
	return TRUE;
}


