/* This file is part of gacopyz.
   Copyright (C) 2006-2025 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/>. */

#include <gacopyz_priv.h>

static int __smfi_dbg_level = 0;
static int __smfi_logmask = 0;
static time_t __smfi_timeout = 7210;
static int __smfi_backlog = 1;
static char *__smfi_conn = NULL;

static gacopyz_conn_t milter_conn;

int
smfi_setdbg(int level)
{
	__smfi_dbg_level = level;
	return MI_SUCCESS;
}

int
smfi_setlogmask(int logmask)
{
	__smfi_logmask = logmask;
	return MI_SUCCESS;
}

int
smfi_settimeout(time_t to)
{
	__smfi_timeout = to;
	return MI_SUCCESS;
}

int
smfi_setbacklog(int val)
{
	if (val <= 0)
		return MI_FAILURE;
	__smfi_backlog = val;
	return MI_SUCCESS;
}

int
smfi_set_foreground(int val)
{
	return gacopyz_set_foreground(milter_conn, val);
}

int
smfi_register(struct smfiDesc desc)
{
	struct timeval t;
	if (gacopyz_init(&milter_conn, &desc))
		return MI_FAILURE;
	if (__smfi_logmask)
		gacopyz_set_logmask(milter_conn, __smfi_logmask);
	if (__smfi_dbg_level) {
		int mask;
		gacopyz_get_logmask(milter_conn, &mask);
		gacopyz_set_logmask(milter_conn,
				    mask | SMI_LOG_MASK(SMI_LOG_DEBUG));
	}
	t.tv_usec = 0;
	t.tv_sec = __smfi_timeout;
	gacopyz_set_ctx_timeout(milter_conn, &t);
	return MI_SUCCESS;
}

int
smfi_opensocket(int rmsock)
{
	return gacopyz_open(milter_conn, __smfi_conn,
			     __smfi_backlog, rmsock);
}

int
smfi_setconn(char *conn)
{
	if (!conn || !*conn)
		return MI_FAILURE;
	__smfi_conn = strdup(conn);
	if (!__smfi_conn)
		return MI_FAILURE;
	return MI_SUCCESS;
}

int
smfi_main()
{
	gacopyz_setup_signals();
	if (!milter_conn) {
		gacopyz_log(SMI_LOG_ERR,
			    _("connection not initialized"));
		return MI_FAILURE;
	}
	if (milter_conn->sd == -1
	    && gacopyz_open(milter_conn, __smfi_conn,
			     __smfi_backlog, 0) == -1) {
		return MI_FAILURE;
	}
	return gacopyz_run(milter_conn); 
}

int
smfi_stop()
{
	return gacopyz_stop(milter_conn);
}

int
smfi_setreply(SMFICTX *ctx, char *rcode, char *xcode, char *message)
{
	if (message && strpbrk(message, "\r\n"))
		return MI_FAILURE;
	return gacopyz_setreply(ctx, rcode, xcode, message);
}

int
smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...)
{
	int rc;
	va_list ap;
	va_start(ap, xcode);
	rc = _gacopyz_setmlreply_va(ctx, 32, rcode, xcode, ap);
	va_end(ap);
	return rc;
}

size_t
smfi_setmaxdatasize (size_t s)
{
	return ~((size_t)0);
}

int
smfi_addheader(SMFICTX *ctx, char *headerf, char *headerv)
{
	return gacopyz_add_header(ctx, headerf, headerv);
}

int
smfi_insheader(SMFICTX *ctx, int index, char *headerf, char *headerv)
{
	return gacopyz_insert_header(ctx, index, headerf, headerv);
}

int
smfi_chgheader(SMFICTX *ctx, char *headerf, int index, char *headerv)
{
	return gacopyz_change_header(ctx, index, headerf, headerv);
}

int
smfi_addrcpt(SMFICTX *ctx, char *rcpt)
{
	return gacopyz_add_rcpt(ctx, rcpt);
}

int
smfi_delrcpt(SMFICTX *ctx, char *rcpt)
{
	return gacopyz_del_rcpt(ctx, rcpt);
}

int
smfi_replacebody(SMFICTX *ctx, unsigned char *bodyp, int bodylen)
{
	return gacopyz_replace_body(ctx, bodyp, bodylen);
}

int
smfi_progress(SMFICTX *ctx)
{
	return gacopyz_progress(ctx);
}

int
smfi_quarantine(SMFICTX *ctx, char *reason)
{
	return gacopyz_quarantine(ctx, reason);
}

int
smfi_addrcpt_par(SMFICTX *ctx, char *rcpt, char *args)
{
	return gacopyz_add_rcpt_par(ctx, rcpt, args);
}

int
smfi_chgfrom(SMFICTX *ctx, char *from, char *args)
{
	return gacopyz_chgfrom(ctx, from, args);
}

int
smfi_setsymlist(SMFICTX *ctx, int n, char *macros)
{
	if (n < 0 || n >= gacopyz_stage_max)
		return MI_FAILURE;
	if (!macros || !*macros || ctx->req_macros[n])
		return MI_FAILURE;
	return gacopyz_setsymlist(ctx, n, macros);
}

int
smfi_version(unsigned int *maj, unsigned int *min, unsigned int *pat)
{
	if (maj)
		*maj = SM_LM_VRS_MAJOR(SMFI_VERSION);
	if (min)
		*min = SM_LM_VRS_MINOR(SMFI_VERSION);
	if (pat)
		*pat = SM_LM_VRS_MINOR(SMFI_VERSION);
	return MI_SUCCESS;
}

	
