/* Definitions for mailfromd dynamically loaded modules (mfmods).
   Copyright (C) 2022 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/>. */

#ifndef MAILFROMD_MFMOD_H
# define MAILFROMD_MFMOD_H

#include <mailutils/types.h>

/* Data types */
typedef enum {
	mfmod_string,
	mfmod_number,
	mfmod_message
} mfmod_data_type;

/*
 * MFMOD_PARAM is used to pass arguments to a function in mfmod and
 * obtain return value from it.
 */
typedef struct mfmod_param {
	mfmod_data_type type;
	union {
		char *string;
		long number;
		mu_message_t message;
	};
} MFMOD_PARAM;

/*
 * All exported functions in an mfmod must be declared as follows.
 * Arguments are:
 *   count   - Number of actual parameters in the param array.
 *   param   - Array of parameters (param[count]).
 *   retval  - Storage for return value (if any).
 *
 * The function shall store its return value in *retval and return 0.
 * If it returns string value (mfmod_string), then retval->string must
 * point to a memory chunk allocated via malloc, calloc or similar
 * function.  It will be deallocated using free(1).
 *
 * To indicate abnormal termination (and throw a runtime exception),
 * the function shall return a non-0 value: the value -1 causes
 * mfe_failure exception with a generic descriptive text.  Any other
 * value is interpreted as mailfromd exception code, and retval is
 * consulted.  If its type field is mfmod_string and the string field
 * is non-NULL, its value is used as the exception description and then
 * deallocated using free(1).
 */
typedef int (*MFMOD_FUNC)(long count, MFMOD_PARAM *param, MFMOD_PARAM *retval);

char const *mfmod_data_type_str(int t);
int mfmod_error(MFMOD_PARAM *r, int errcode, char const *fmt, ...);
int mfmod_error_argtype(MFMOD_PARAM *p, MFMOD_PARAM *r, int n, int exptype);

#define ASSERT_ARGCOUNT(r, count, n)					\
	do {								\
		if (count != n)						\
			return mfmod_error(r, mfe_inval,		\
				    "%s", "bad number of arguments");	\
	} while (0)

#define ASSERT_ARGTYPE(p, r, n, t)                                      \
	do {                                                            \
		if (p[n].type != t)					\
			return mfmod_error_argtype(p, r, n, t);		\
	} while (0)


#endif
