/* This file is part of Mailfromd.
   Copyright (C) 2005-2020 Sergey Poznyakoff

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <mailutils/mailutils.h>
#include <mailutils/cfg.h>
#include <mailutils/alloc.h>
#include "libmf.h"
#include "mfdb.h"

static int
cb_db_expire_interval(void *data, mu_config_value_t *arg)
{
	time_t *iptr = data;
	struct timeval tv;
	int rc;
	
	rc = config_cb_timeout(&tv, arg);
	*iptr = tv.tv_sec;
	return rc;
}

static int
cb_db_positive_expire_interval(void *data, mu_config_value_t *arg)
{
	struct db_format *fmt = data;
	struct timeval tv;
	int rc;
	
	if (fmt != cache_format) {
		mu_error (_("positive-expire-interval is valid only "
			    "for cache database"));
		return 0;
	}

	rc = config_cb_timeout(&tv, arg);
	if (rc == 0)
		fmt->expire_interval = tv.tv_sec;
	return rc;
}

static int
cb_db_negative_expire_interval(void *data, mu_config_value_t *arg)
{
	struct db_format *fmt = data;
	struct timeval tv;
	int rc = config_cb_timeout(&tv, arg);
	
	if (fmt == cache_format)
		negative_expire_interval = tv.tv_sec;
	else
		mu_error(_("negative-expire-interval is valid only "
			   "for cache database"));
	return rc;
}

int
cb_database_file(void *data, mu_config_value_t *arg)
{
	char **pname = data;
	if (mu_cfg_assert_value_type(arg, MU_CFG_STRING))
		return 1;
	*pname = mu_strdup(arg->v.string);
	return 0;
}
	
struct mu_cfg_param database_section_param[] = {
	{ "file", mu_cfg_callback, NULL,
	  offsetof(struct db_format, dbname), cb_database_file,
	  N_("Name of the database file"),
          N_("name: string") },
	{ "enable", mu_c_bool, NULL, offsetof(struct db_format, enabled), NULL,
	  N_("Enable or disable the database") },
	{ "expire-interval", mu_cfg_callback, NULL,
	  offsetof(struct db_format, expire_interval), cb_db_expire_interval,
	  N_("Set database record expiration interval"),
	  N_("arg: interval") },
	{ "positive-expire-interval", mu_cfg_callback, NULL, 0,
	  cb_db_positive_expire_interval,
	  N_("Set positive expiration interval (for database \"cache\" only)"),
	  N_("arg: interval") },
	{ "negative-expire-interval", mu_cfg_callback, NULL, 0,
	  cb_db_negative_expire_interval,
	  N_("Set negative expiration interval "
	     "(for database id \"cache\")"),
	  N_("arg: interval") },
	{ NULL }
};

static int
database_section_parser (enum mu_cfg_section_stage stage,
			 const mu_cfg_node_t *node,
			 const char *section_label, void **section_data,
			 void *call_data,
			 mu_cfg_tree_t *tree)
{
	switch (stage) {
	case mu_cfg_section_start: {
		struct db_format *fmt;

		if (mu_cfg_assert_value_type(node->label, MU_CFG_STRING))
			return 0;
		fmt = db_format_lookup(node->label->v.string);
		if (fmt == NULL) {
			mu_error(_("unknown database format: %s"),
				 node->label->v.string);
			return 0;
		}
		*section_data = fmt;
	}
		break;

	case mu_cfg_section_end:
		break;
	}
	return 0;
}

int
cb_database_mode(void *data, mu_config_value_t *arg)
{
	unsigned long mode;
	char *end;
	if (mu_cfg_assert_value_type(arg, MU_CFG_STRING))
		return 1;
	mode = strtoul(arg->v.string, &end, 0);
	if (*end || (mode & ~0777)) {
		mu_error("%s", _("invalid file mode"));
		return 1;
	} else
		*(int*)data = mode;
	return 0;
}

void
database_cfg_init()
{
	struct mu_cfg_section *section;
	if (mu_create_canned_section("database", &section) == 0) {
		section->label = N_("id");
		section->parser = database_section_parser;
		section->docstring = N_("Define a database.");
		mu_cfg_section_add_params(section, database_section_param);
	}
#if 0
//  FIXME: If MU had canned params, I could've done something along these
//  lines.  Unfortunately, it doesn't
		
	if (mu_create_canned_param ("database-mode", &param) == 0) {
		param->type = mu_cfg_callback;
		param->callback = cb_database_mode;
		param->docstring =
			N_("Configure file mode for database files");
		param->argname = N_("mode: octal");
	}
#endif
}