#include "common.h"
#include "send.h"

/* Return TRUE if a forwarding loop exists, i.e., the String `system'
 * is found more than 4 times in the return address.
 */
static int
forward_loop(char *addr, char *system)
{
	int len, found;

	found = 0;
	len = strlen(system);
	while(addr = strchr(addr, '!'))
		if (!strncmp(++addr, system, len)
		 && addr[len] == '!' && ++found == 4)
			return 1;
	return 0;
}


/* bind the destinations to the commands to be executed */
dest *
up_bind(dest *destp, message *mp, int checkforward)
{
	int i, li;
	dest *list[2], *bound, *dp;

	bound = nil;
	list[0] = destp;
	list[1] = nil;

	/*
	 *  loop once to check for:
	 *	- forwarding rights
	 *	- addressing loops
	 *	- illegal characters
	 *	- characters that need escaping
	 */
	for (dp = d_rm(&list[0]); dp != 0; dp = d_rm(&list[0])) {
		if(!checkforward)
			dp->authorized = 1;
		dp->addr = escapespecial(dp->addr);
		if (forward_loop(s_to_c(dp->addr), thissys)) {
			dp->status = d_eloop;
			d_same_insert(&bound, dp);
		} else if(forward_loop(s_to_c(mp->sender), thissys)) {
			dp->status = d_eloop;
			d_same_insert(&bound, dp);
		} else if(shellchars(s_to_c(dp->addr))) {
			dp->status = d_syntax;
			d_same_insert(&bound, dp);
		} else
			d_insert(&list[1], dp);
	}
	li = 1;

	/* Loop until all addresses are bound or address loop detected */
	for (i=0; list[li]!=0 && i<32; ++i, li ^= 1) {
		/* Traverse the current list.  Bound items are put on the
		 * `bound' list.  Unbound items are put on the next list to
		 * traverse, `list[li^1]'.
		 */
		for (dp = d_rm(&list[li]); dp != 0; dp = d_rm(&list[li])){
			dest *newlist;

			rewrite(dp, mp);
			if(debug)
				fprint(2, "%s -> %s\n", s_to_c(dp->addr),
					dp->repl1 ? s_to_c(dp->repl1):"");
			switch (dp->status) {
			case d_auth:
				/* authorize address if not already authorized */
				if(!dp->authorized){
					authorize(dp);
					if(dp->status==d_auth)
						d_insert(&list[li^1], dp);
					else
						d_insert(&bound, dp);
				}
				break;
			case d_cat:
				/* address -> local */
				newlist = expand_local(dp);
				if (newlist == 0) {
					/* append to mailbox (or error) */
					d_same_insert(&bound, dp);
				} else if (newlist->status == d_undefined) {
					/* Forward to ... */
					d_insert(&list[li^1], newlist);
				} else {
					/* Pipe to ... */
					d_same_insert(&bound, newlist);
				}
				break;
			case d_pipe:
				/* address -> command */
				d_same_insert(&bound, dp);
				break;
			case d_alias:
				/* address -> rewritten address */
				newlist = s_to_dest(dp->repl1, dp);
				if(newlist != 0)
					d_insert(&list[li^1], newlist);
				else
					d_same_insert(&bound, dp);
				break;
			case d_translate:
				/* pipe to a translator */
				newlist = translate(dp);
				if (newlist != 0)
					d_insert(&list[li^1], newlist);
				else
					d_same_insert(&bound, dp);
				break;
			default:
				/* error */
				d_same_insert(&bound, dp);
				break;
			}
		}
	}

	/* mark remaining comands as "forwarding loops" */
	for (dp = d_rm(&list[li]); dp != 0; dp = d_rm(&list[li])) {
		dp->status = d_loop;
		d_same_insert(&bound, dp);
	}

	return bound;
}
