/*++
/* NAME
/*	postconf_dbms 3
/* SUMMARY
/*	legacy support for database-defined main.cf parameter names
/* SYNOPSIS
/*	#include <postconf.h>
/*
/*	void	pcf_register_dbms_parameters(param_value, flag_parameter,
/*					local_scope)
/*	const char *param_value;
/*	const char *(flag_parameter) (const char *, int, PCF_MASTER_ENT *);
/*	PCF_MASTER_ENT *local_scope;
/* DESCRIPTION
/*	This module implements legacy support for database configuration
/*	where main.cf parameter names are generated by prepending
/*	the database name to a database-defined suffix.
/*
/*	Arguments:
/* .IP param_value
/*	A parameter value to be searched for "type:table" strings.
/*	When a database type is found that supports legacy-style
/*	configuration, the table name is combined with each of the
/*	database-defined suffixes to generate candidate parameter
/*	names for that database type.
/* .IP flag_parameter
/*	A function that takes as arguments a candidate parameter
/*	name, parameter flags, and a PCF_MASTER_ENT pointer.  The
/*	function will flag the parameter as "used" if it has a
/*	"name=value" entry in the local or global namespace.
/* .IP local_scope
/*	The local namespace.
/* DIAGNOSTICS
/*	No explicit diagnostics.
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*--*/

/* System library. */

#include <sys_defs.h>
#include <string.h>

/* Utility library. */

#include <stringops.h>
#include <split_at.h>
#include <mac_expand.h>
#include <dict.h>

/* Global library. */

#include <mail_conf.h>
#include <dict_proxy.h>
#include <dict_ldap.h>
#include <dict_mysql.h>
#include <dict_pgsql.h>
#include <dict_sqlite.h>
#include <dict_memcache.h>

/* Application-specific. */

#include <postconf.h>

 /*
  * SLMs.
  */
#define STR(x)	vstring_str(x)

#ifdef LEGACY_DBMS_SUPPORT

 /*
  * The legacy database interface automagically instantiates a list of
  * parameters by prepending the table name to database-specific suffixes.
  */

/* See ldap_table(5). */

static const char *pcf_ldap_suffixes[] = {
    "bind", "bind_dn", "bind_pw", "cache", "cache_expiry", "cache_size",
    "chase_referrals", "debuglevel", "dereference", "domain",
    "expansion_limit", "leaf_result_attribute", "query_filter",
    "recursion_limit", "result_attribute", "result_format", "scope",
    "search_base", "server_host", "server_port", "size_limit",
    "special_result_attribute", "terminal_result_attribute",
    "timeout", "version", 0,
};

/* See mysql_table(5). */

static const char *pcf_mysql_suffixes[] = {
    "additional_conditions", "dbname", "domain", "expansion_limit",
    "hosts", "password", "query", "result_format", "select_field",
    "table", "user", "where_field", 0,
};

/* See pgsql_table(5). */

static const char *pcf_pgsql_suffixes[] = {
    "additional_conditions", "dbname", "domain", "expansion_limit",
    "hosts", "password", "query", "result_format", "select_field",
    "select_function", "table", "user", "where_field", 0,
};

/* See sqlite_table(5). */

static const char *pcf_sqlite_suffixes[] = {
    "additional_conditions", "dbpath", "domain", "expansion_limit",
    "query", "result_format", "select_field", "table", "where_field",
    0,
};

/* See memcache_table(5). */

static const char *pcf_memcache_suffixes[] = {
    "backup", "data_size_limit", "domain", "flags", "key_format",
    "line_size_limit", "max_try", "memcache", "retry_pause",
    "timeout", "ttl", 0,
};

 /*
  * Bundle up the database types and their suffix lists.
  */
typedef struct {
    const char *db_type;
    const char **db_suffixes;
} PCF_DBMS_INFO;

static const PCF_DBMS_INFO pcf_dbms_info[] = {
    DICT_TYPE_LDAP, pcf_ldap_suffixes,
    DICT_TYPE_MYSQL, pcf_mysql_suffixes,
    DICT_TYPE_PGSQL, pcf_pgsql_suffixes,
    DICT_TYPE_SQLITE, pcf_sqlite_suffixes,
    DICT_TYPE_MEMCACHE, pcf_memcache_suffixes,
    0,
};

/* pcf_register_dbms_parameters - look for database_type:prefix_name */

void    pcf_register_dbms_parameters(const char *param_value,
         const char *(flag_parameter) (const char *, int, PCF_MASTER_ENT *),
				             PCF_MASTER_ENT *local_scope)
{
    const PCF_DBMS_INFO *dp;
    char   *bufp;
    char   *db_type;
    char   *prefix;
    static VSTRING *buffer = 0;
    static VSTRING *candidate = 0;
    const char **cpp;

    /*
     * XXX This does not examine both sides of conditional macro expansion,
     * and may expand the "wrong" conditional macros. This is the best we can
     * do for legacy database configuration support.
     */
    if (buffer == 0)
	buffer = vstring_alloc(100);
    bufp = pcf_expand_parameter_value(buffer, PCF_SHOW_EVAL, param_value,
				      local_scope);

    /*
     * Naive parsing. We don't really know if the parameter specifies free
     * text or a list of databases.
     */
    while ((db_type = mystrtok(&bufp, " ,\t\r\n")) != 0) {

	/*
	 * Skip over "proxy:" maptypes, to emulate the proxymap(8) server's
	 * behavior when opening a local database configuration file.
	 */
	while ((prefix = split_at(db_type, ':')) != 0
	       && strcmp(db_type, DICT_TYPE_PROXY) == 0)
	    db_type = prefix;

	/*
	 * Look for database:prefix where the prefix is not a pathname and
	 * the database is a known type. Synthesize candidate parameter names
	 * from the user-defined prefix and from the database-defined suffix
	 * list, and see if those parameters have a "name=value" entry in the
	 * local or global namespace.
	 */
	if (prefix != 0 && *prefix != '/' && *prefix != '.') {
	    for (dp = pcf_dbms_info; dp->db_type != 0; dp++) {
		if (strcmp(db_type, dp->db_type) == 0) {
		    for (cpp = dp->db_suffixes; *cpp; cpp++) {
			vstring_sprintf(candidate ? candidate :
					(candidate = vstring_alloc(30)),
					"%s_%s", prefix, *cpp);
			flag_parameter(STR(candidate),
				  PCF_PARAM_FLAG_DBMS | PCF_PARAM_FLAG_USER,
				       local_scope);
		    }
		    break;
		}
	    }
	}
    }
}

#endif
