From 88e1ffcde1bfd289fe67de1aea6cbd9c6cd0ca24 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Julio=20S=C3=A1nchez=20Fern=C3=A1ndez?=
 <jsanchez@openldap.org>
Date: Thu, 23 Mar 2000 16:19:01 +0000
Subject: [PATCH] The approach used was not powerfull enough to deal with
 things like nested groups or the laser mail routing draft.  Mostly, this is
 because a flag saying the attribute type is 'final' is not flexible enough. 
 The old 'final' flag is gone and replaced by a priority level.

Change 'forward' to 'route' to be consistent with the laser wording.

Add new 'domain' spec in the configuration file to describe what are
the local domains so that we do not loop when doing the laser thing.

We were escaping asterisks in filters.  This seems incorrect.  Removed.
---
 clients/mail500/main.c | 105 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 87 insertions(+), 18 deletions(-)

diff --git a/clients/mail500/main.c b/clients/mail500/main.c
index 56d016ced7..d3e24b06c9 100644
--- a/clients/mail500/main.c
+++ b/clients/mail500/main.c
@@ -128,7 +128,7 @@ char	*sendmailargs[] = { MAIL500_SENDMAIL, "-oMrLDAP", "-odi", "-oi", "-f", NULL
 typedef struct attr_semantics {
 	char	*as_name;
 	int	as_m_valued;	/* Is multivalued? */
-	int	as_final;	/* If true, no further expansion is tried. */
+	int	as_priority;	/* Priority level of this attribut type */
 	int	as_syntax;	/* How to interpret values */
 	int	as_m_entries;	/* Can resolve to several entries? */
 	int	as_kind;	/* Recipient, sender, etc. */
@@ -149,11 +149,13 @@ typedef struct attr_semantics {
 #define AS_KIND_ERRORS		2	/* For ErrorsTo and similar */
 #define AS_KIND_REQUEST		3
 #define AS_KIND_OWNER		4
-#define AS_KIND_FORWARD_TO_HOST	5	/* Expand at some other host */
+#define AS_KIND_ROUTE_TO_HOST	5	/* Expand at some other host */
 #define AS_KIND_ALLOWED_SENDER	6	/* Can send to group */
 #define AS_KIND_MODERATOR	7
+#define AS_KIND_ROUTE_TO_ADDR	8	/* Rewrite recipient address as */
 
 AttrSemantics **attr_semantics = NULL;
+int current_priority = 0;
 
 typedef struct subst {
 	char	sub_char;
@@ -162,6 +164,7 @@ typedef struct subst {
 
 char	**groupclasses = NULL;
 char	**def_attr = NULL;
+char	**mydomains = NULL;		/* FQDNs not to route elsewhere */
 
 static void load_config( char *filespec );
 static void split_address( char *address, char **localpart, char **domainpart);
@@ -519,6 +522,7 @@ add_attr_semantics( char *s )
 	AttrSemantics *as;
 
 	as = calloc( 1, sizeof( AttrSemantics ) );
+	as->as_priority = current_priority;
 	p = s;
 	while ( isspace ( *p ) )
 		p++;
@@ -540,8 +544,6 @@ add_attr_semantics( char *s )
 			as->as_m_valued = 1;
 		} else if ( !strcasecmp( p, "multiple-entries" ) ) {
 			as->as_m_entries = 1;
-		} else if ( !strcasecmp( p, "final" ) ) {
-			as->as_final = 1;
 		} else if ( !strcasecmp( p, "local-native-mailbox" ) ) {
 			as->as_syntax = AS_SYNTAX_NATIVE_MB;
 		} else if ( !strcasecmp( p, "rfc822" ) ) {
@@ -575,8 +577,10 @@ add_attr_semantics( char *s )
 			}
 		} else if ( !strcasecmp( p, "host" ) ) {
 			as->as_kind = AS_SYNTAX_HOST;
-		} else if ( !strcasecmp( p, "forward-to-host" ) ) {
-			as->as_kind = AS_KIND_FORWARD_TO_HOST;
+		} else if ( !strcasecmp( p, "route-to-host" ) ) {
+			as->as_kind = AS_KIND_ROUTE_TO_HOST;
+		} else if ( !strcasecmp( p, "route-to-address" ) ) {
+			as->as_kind = AS_KIND_ROUTE_TO_ADDR;
 		} else if ( !strcasecmp( p, "recipient" ) ) {
 			as->as_kind = AS_KIND_RECIPIENT;
 		} else if ( !strcasecmp( p, "errors" ) ) {
@@ -655,6 +659,12 @@ load_config( char *filespec )
 		} else if ( !strncmp(line, "group-classes", p-line) ) {
 			p += strspn(p, " \t");
 			add_single_to( &groupclasses, p );
+		} else if ( !strncmp(line, "priority", p-line) ) {
+			p += strspn(p, " \t");
+			current_priority = atoi(p);
+		} else if ( !strncmp(line, "domain", p-line) ) {
+			p += strspn(p, " \t");
+			add_single_to( &mydomains, p );
 		} else {
 			syslog( LOG_ALERT,
 				"Unparseable config definition at line %d",
@@ -812,7 +822,6 @@ search_ldap_url(
 	char		*p, *s, *d;
 	int		i;
 	char		filter[1024];
-	char		realfilter[1024];
 	LDAPMessage	*e, *res;
 	int		rc;
 	char		**attrlist;
@@ -911,14 +920,6 @@ search_ldap_url(
 		filter[ sizeof( filter ) - 1 ] = '\0';
 	}
 
-	for ( s = filter, d = realfilter; *s; s++, d++ ) {
-		if ( *s == '*' ) {
-			*d++ = '\\';
-		}
-		*d = *s;
-	}
-	*d = '\0';
-
 	if ( ludp->lud_attrs ) {
 		attrlist = ludp->lud_attrs;
 	} else {
@@ -927,7 +928,7 @@ search_ldap_url(
 	res = NULL;
 	/* TBC: we don't read the host, dammit */
 	rc = ldap_search_st( ld, ludp->lud_dn, ludp->lud_scope,
-			     realfilter, attrlist, 0,
+			     filter, attrlist, 0,
 			     &timeout, &res );
 
 	/* some other trouble - try again later */
@@ -1075,6 +1076,23 @@ url_list_search(
 	return( resolved );
 }
 
+static int
+is_my_domain(
+	char * domain
+)
+{
+	char **d;
+
+	if ( d == NULL )
+		return 0;
+	for ( d = mydomains; *d; d++ ) {
+		if ( !strcmp(*d,domain) ) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /*
  * The entry engine processes an entry.  Normally, each entry will resolve
  * to one or more values that will be added to the 'to' argument.  This
@@ -1106,11 +1124,22 @@ entry_engine(
 	char	buf[1024];
 	char	*localpart, *domainpart;
 	Subst	substs[2];
+	int	cur_priority = 0;
+	char	*route_to_host = NULL;
+	char	*route_to_address = NULL;
+	char	*nvals[2];
 
 	for ( i=0; attr_semantics[i] != NULL; i++ ) {
 		AttrSemantics	*as = attr_semantics[i];
 		int		nent;
 
+		if ( as->as_priority < cur_priority ) {
+			/*
+			 * We already got higher priority information,
+			 * so no further work to do, ignore the rest.
+			 */
+			break;
+		}
 		vals = ldap_get_values( ld, e, as->as_name );
 		if ( !vals || vals[0] == NULL ) {
 			continue;
@@ -1122,6 +1151,7 @@ entry_engine(
 		}
 		switch ( as->as_kind ) {
 		case AS_KIND_RECIPIENT:
+			cur_priority = as->as_priority;
 			if ( ! ( type & ( USER | GROUP_MEMBERS ) ) )
 				break;
 			switch ( as->as_syntax ) {
@@ -1188,6 +1218,7 @@ entry_engine(
 			break;
 
 		case AS_KIND_ERRORS:
+			cur_priority = as->as_priority;
 			/* This is a group with special processing */
 			if ( type & GROUP_ERRORS ) {
 				switch (as->as_kind) {
@@ -1225,6 +1256,7 @@ entry_engine(
 			break;
 
 		case AS_KIND_REQUEST:
+			cur_priority = as->as_priority;
 			/* This is a group with special processing */
 			if ( type & GROUP_REQUEST ) {
 				add_to( current_to, current_nto, vals );
@@ -1233,6 +1265,7 @@ entry_engine(
 			break;
 
 		case AS_KIND_OWNER:
+			cur_priority = as->as_priority;
 			/* This is a group with special processing */
 			if ( type & GROUP_REQUEST ) {
 				add_to( current_to, current_nto, vals );
@@ -1240,16 +1273,52 @@ entry_engine(
 			}
 			break;
 
+		case AS_KIND_ROUTE_TO_HOST:
+			if ( !is_my_domain( vals[0] ) ) {
+				cur_priority = as->as_priority;
+				route_to_host = strdup( vals[0] );
+			}
+			break;
+
+		case AS_KIND_ROUTE_TO_ADDR:
+			if ( strcmp( vals[0], address ) ) {
+				cur_priority = as->as_priority;
+				route_to_address = strdup( vals[0] );
+			}
+			break;
+
 		default:
 			syslog( LOG_ALERT,
 				"Invalid kind %d", as->as_kind );
 			/* Error, TBC */
 		}
 		ldap_value_free( vals );
-		if ( as->as_final ) {
-			return( resolved );
+	}
+	if ( route_to_host ) {
+		char *p;
+		if ( !route_to_address ) {
+			route_to_address = strdup( address );
+		}
+		/* This makes use of the percent hack, but there's no choice */
+		p = strchr( route_to_address, '@' );
+		if ( p ) {
+			*p = '%';
 		}
+		sprintf( buf, "%s@%s", route_to_address, route_to_host );
+		nvals[0] = buf;
+		nvals[1] = NULL;
+		add_to( current_to, current_nto, nvals );
+		resolved = 1;
+		free( route_to_host );
+		free( route_to_address );
+	} else if ( route_to_address ) {
+		nvals[0] = route_to_address;
+		nvals[1] = NULL;
+		add_to( current_to, current_nto, nvals );
+		resolved = 1;
+		free( route_to_address );
 	}
+		  
 	return( resolved );
 }
 
-- 
GitLab