cleanup_map1n.c revision 1.1
1/*	$NetBSD: cleanup_map1n.c,v 1.1 2009/06/23 10:08:43 tron Exp $	*/
2
3/*++
4/* NAME
5/*	cleanup_map1n 3
6/* SUMMARY
7/*	one-to-many address mapping
8/* SYNOPSIS
9/*	#include <cleanup.h>
10/*
11/*	ARGV	*cleanup_map1n_internal(state, addr, maps, propagate)
12/*	CLEANUP_STATE *state;
13/*	const char *addr;
14/*	MAPS	*maps;
15/*	int	propagate;
16/* DESCRIPTION
17/*	This module implements one-to-many table mapping via table lookup.
18/*	Table lookups are done with quoted (externalized) address forms.
19/*	The process is recursive. The recursion terminates when the
20/*	left-hand side appears in its own expansion, or when a maximal
21/*	nesting level is reached.
22/*
23/*	cleanup_map1n_internal() is the interface for addresses in
24/*	internal (unquoted) form.
25/* DIAGNOSTICS
26/*	Recoverable errors: the global \fIcleanup_errs\fR flag is updated.
27/* SEE ALSO
28/*	mail_addr_map(3) address mappings
29/*	mail_addr_find(3) address lookups
30/* LICENSE
31/* .ad
32/* .fi
33/*	The Secure Mailer license must be distributed with this software.
34/* AUTHOR(S)
35/*	Wietse Venema
36/*	IBM T.J. Watson Research
37/*	P.O. Box 704
38/*	Yorktown Heights, NY 10598, USA
39/*--*/
40
41/* System library. */
42
43#include <sys_defs.h>
44#include <string.h>
45
46#ifdef STRCASECMP_IN_STRINGS_H
47#include <strings.h>
48#endif
49
50/* Utility library. */
51
52#include <mymalloc.h>
53#include <msg.h>
54#include <argv.h>
55#include <vstring.h>
56#include <dict.h>
57
58/* Global library. */
59
60#include <mail_params.h>
61#include <mail_addr_map.h>
62#include <cleanup_user.h>
63#include <quote_822_local.h>
64#include <been_here.h>
65
66/* Application-specific. */
67
68#include "cleanup.h"
69
70/* cleanup_map1n_internal - one-to-many table lookups */
71
72ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr,
73			               MAPS *maps, int propagate)
74{
75    ARGV   *argv;
76    ARGV   *lookup;
77    int     count;
78    int     i;
79    int     arg;
80    BH_TABLE *been_here;
81    char   *saved_lhs;
82
83    /*
84     * Initialize.
85     */
86    argv = argv_alloc(1);
87    argv_add(argv, addr, ARGV_END);
88    argv_terminate(argv);
89    been_here = been_here_init(0, BH_FLAG_FOLD);
90
91    /*
92     * Rewrite the address vector in place. With each map lookup result,
93     * split it into separate addresses, then rewrite and flatten each
94     * address, and repeat the process. Beware: argv is being changed, so we
95     * must index the array explicitly, instead of running along it with a
96     * pointer.
97     */
98#define UPDATE(ptr,new)	{ myfree(ptr); ptr = mystrdup(new); }
99#define STR	vstring_str
100#define RETURN(x) { been_here_free(been_here); return (x); }
101
102    for (arg = 0; arg < argv->argc; arg++) {
103	if (argv->argc > var_virt_expan_limit) {
104	    msg_warn("%s: unreasonable %s map expansion size for %s",
105		     state->queue_id, maps->title, addr);
106	    break;
107	}
108	for (count = 0; /* void */ ; count++) {
109
110	    /*
111	     * Don't expand an address that already expanded into itself.
112	     */
113	    if (been_here_check_fixed(been_here, argv->argv[arg]) != 0)
114		break;
115	    if (count >= var_virt_recur_limit) {
116		msg_warn("%s: unreasonable %s map nesting for %s",
117			 state->queue_id, maps->title, addr);
118		break;
119	    }
120	    quote_822_local(state->temp1, argv->argv[arg]);
121	    if ((lookup = mail_addr_map(maps, STR(state->temp1), propagate)) != 0) {
122		saved_lhs = mystrdup(argv->argv[arg]);
123		for (i = 0; i < lookup->argc; i++) {
124		    unquote_822_local(state->temp1, lookup->argv[i]);
125		    if (i == 0) {
126			UPDATE(argv->argv[arg], STR(state->temp1));
127		    } else {
128			argv_add(argv, STR(state->temp1), ARGV_END);
129			argv_terminate(argv);
130		    }
131
132		    /*
133		     * Allow an address to expand into itself once.
134		     */
135		    if (strcasecmp(saved_lhs, STR(state->temp1)) == 0)
136			been_here_fixed(been_here, saved_lhs);
137		}
138		myfree(saved_lhs);
139		argv_free(lookup);
140	    } else if (dict_errno != 0) {
141		msg_warn("%s: %s map lookup problem for %s",
142			 state->queue_id, maps->title, addr);
143		state->errs |= CLEANUP_STAT_WRITE;
144		RETURN(argv);
145	    } else {
146		break;
147	    }
148	}
149    }
150    RETURN(argv);
151}
152