1/*++
2/* NAME
3/*	postconf_lookup 3
4/* SUMMARY
5/*	parameter lookup routines
6/* SYNOPSIS
7/*	#include <postconf.h>
8/*
9/*	const char *pcf_lookup_parameter_value(mode, name, local_scope, node)
10/*	int	mode;
11/*	const char *name;
12/*	PCF_MASTER_ENT *local_scope;
13/*	PCF_PARAM_NODE *node;
14/*
15/*	char    *pcf_expand_parameter_value(buf, mode, value, local_scope)
16/*	VSTRING *buf;
17/*	int	mode;
18/*	const char *value;
19/*	PCF_MASTER_ENT *local_scope;
20/* DESCRIPTION
21/*	These functions perform parameter value lookups.  The order
22/*	of decreasing precedence is:
23/* .IP \(bu
24/*	Search name=value parameter settings in master.cf.  These
25/*	lookups are disabled with the PCF_SHOW_DEFS flag.
26/* .IP \(bu
27/*	Search name=value parameter settings in main.cf.  These
28/*	lookups are disabled with the PCF_SHOW_DEFS flag.
29/* .IP \(bu
30/*	Search built-in default parameter settings. These lookups
31/*	are disabled with the PCF_SHOW_NONDEF flag.
32/* .PP
33/*	pcf_lookup_parameter_value() looks up the value for the
34/*	named parameter, and returns null if the name was not found.
35/*
36/*	pcf_expand_parameter_value() expands $name in the specified
37/*	parameter value. This function ignores the PCF_SHOW_NONDEF
38/*	flag.  The result value is a pointer to storage in a
39/*	user-supplied buffer, or in a buffer that is overwritten
40/*	with each call.
41/*
42/*	Arguments:
43/* .IP buf
44/*	Null buffer pointer, or pointer to user-supplied buffer.
45/* .IP mode
46/*	Bit-wise OR of zero or one of the following (other flags
47/*	are ignored):
48/* .RS
49/* .IP PCF_SHOW_DEFS
50/*	Search built-in default parameter settings only.
51/* .IP PCF_SHOW_NONDEF
52/*	Search local (master.cf) and global (main.cf) name=value
53/*	parameter settings only.
54/* .RE
55/* .IP name
56/*	The name of a parameter to be looked up.
57/* .IP value
58/*	The parameter value where $name should be expanded.
59/* .IP local_scope
60/*	Pointer to master.cf entry with local name=value settings,
61/*	or a null pointer (i.e. no local parameter lookup).
62/* .IP node
63/*	Global default value for the named parameter, or a null
64/*	pointer (i.e. do the global default lookup anyway).
65/* DIAGNOSTICS
66/*	Problems are reported to the standard error stream.
67/* LICENSE
68/* .ad
69/* .fi
70/*	The Secure Mailer license must be distributed with this software.
71/* AUTHOR(S)
72/*	Wietse Venema
73/*	IBM T.J. Watson Research
74/*	P.O. Box 704
75/*	Yorktown Heights, NY 10598, USA
76/*--*/
77
78/* System library. */
79
80#include <sys_defs.h>
81#include <string.h>
82
83/* Utility library. */
84
85#include <msg.h>
86#include <mymalloc.h>
87#include <vstring.h>
88#include <dict.h>
89#include <stringops.h>
90#include <mac_expand.h>
91
92/* Global library. */
93
94#include <mail_conf.h>
95
96/* Application-specific. */
97
98#include <postconf.h>
99
100#define STR(x) vstring_str(x)
101
102/* pcf_lookup_parameter_value - look up specific parameter value */
103
104const char *pcf_lookup_parameter_value(int mode, const char *name,
105				               PCF_MASTER_ENT *local_scope,
106				               PCF_PARAM_NODE *node)
107{
108    const char *value = 0;
109
110    /*
111     * Local name=value entries in master.cf take precedence over global
112     * name=value entries in main.cf. Built-in defaults have the lowest
113     * precedence.
114     */
115    if ((mode & PCF_SHOW_DEFS) != 0
116	|| ((local_scope == 0 || local_scope->all_params == 0
117	     || (value = dict_get(local_scope->all_params, name)) == 0)
118	    && (value = dict_lookup(CONFIG_DICT, name)) == 0
119	    && (mode & PCF_SHOW_NONDEF) == 0)) {
120	if (node != 0 || (node = PCF_PARAM_TABLE_FIND(pcf_param_table, name)) != 0)
121	    value = pcf_convert_param_node(PCF_SHOW_DEFS, name, node);
122    }
123    return (value);
124}
125
126 /*
127  * Data structure to pass private state while recursively expanding $name in
128  * parameter values.
129  */
130typedef struct {
131    int     mode;
132    PCF_MASTER_ENT *local_scope;
133} PCF_EVAL_CTX;
134
135/* pcf_lookup_parameter_value_wrapper - macro parser call-back routine */
136
137static const char *pcf_lookup_parameter_value_wrapper(const char *key,
138						            int unused_type,
139						              char *context)
140{
141    PCF_EVAL_CTX *cp = (PCF_EVAL_CTX *) context;
142
143    return (pcf_lookup_parameter_value(cp->mode, key, cp->local_scope,
144				       (PCF_PARAM_NODE *) 0));
145}
146
147/* pcf_expand_parameter_value - expand $name in parameter value */
148
149char   *pcf_expand_parameter_value(VSTRING *buf, int mode, const char *value,
150				           PCF_MASTER_ENT *local_scope)
151{
152    const char *myname = "pcf_expand_parameter_value";
153    static VSTRING *local_buf;
154    int     status;
155    PCF_EVAL_CTX eval_ctx;
156
157    /*
158     * Initialize.
159     */
160    if (buf == 0) {
161	if (local_buf == 0)
162	    local_buf = vstring_alloc(10);
163	buf = local_buf;
164    }
165
166    /*
167     * Expand macros recursively.
168     *
169     * When expanding $name in "postconf -n" parameter values, don't limit the
170     * search to only non-default parameter values.
171     *
172     * When expanding $name in "postconf -d" parameter values, do limit the
173     * search to only default parameter values.
174     */
175#define DONT_FILTER (char *) 0
176
177    eval_ctx.mode = (mode & ~PCF_SHOW_NONDEF);
178    eval_ctx.local_scope = local_scope;
179    status = mac_expand(buf, value, MAC_EXP_FLAG_RECURSE, DONT_FILTER,
180		    pcf_lookup_parameter_value_wrapper, (char *) &eval_ctx);
181    if (status & MAC_PARSE_ERROR)
182	msg_fatal("macro processing error");
183    if (msg_verbose > 1) {
184	if (strcmp(value, STR(buf)) != 0)
185	    msg_info("%s: expand %s -> %s", myname, value, STR(buf));
186	else
187	    msg_info("%s: const  %s", myname, value);
188    }
189    return (STR(buf));
190}
191