/*
 * Copyright (c) 1999-2005 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 *
 *	$Id: pmfapi.h,v 1.19 2005/09/13 06:08:16 ca Exp $
 */

/*
**  PMFAPI.H -- Global definitions for policy mail filter library
**	and policy mail filters.
*/

#ifndef PMFAPI_H
#define PMFAPI_H 1

/* libpmilter version */
#define LPMILTER_VERSION_MAJOR	0x0001
#define LPMILTER_VERSION_MINOR	0x00
#define LPMILTER_VERSION_PL	0x00

#define LPMILTER_VERSION	((LPMILTER_VERSION_MAJOR << 24) + \
				(LPMILTER_VERSION_MINOR	<< 8) + \
				LPMILTER_VERSION_PL)

#define SM_PM_VRS_MAJOR(v)	(((v) & 0x7f000000) >> 24)
#define SM_PM_VRS_MINOR(v)	(((v) & 0x007fff00) >> 8)
#define SM_PM_VRS_PLVL(v)	((v) & 0x0000007f)


#ifdef WIN32
# include <winsock2.h>
#endif /* WIN32 */

#include "sm/pmfdef.h"

#ifdef WIN32

/*
**  The following ifdef block is the standard way of creating macros which make
**  exporting from a DLL simpler. All files within this DLL are compiled with
**  the LIBMILTER_EXPORTS symbol defined. LIBMILTER_EXPORTS should not be
**  defined on any project that uses this DLL. This way any other project whose
**  source files include this file see LIBSASL_API functions as being imported
**  from a DLL, wheras this DLL sees symbols defined with this macro as being
**  exported.
**  Under UNIX, life is simpler: we just need to mark library functions
**  as extern.  (Technically, we don't even have to do that.)
*/

# ifdef WIN32_DLL
#  ifdef LIBMILTER_EXPORTS
#   define LIBMILTER_API		__declspec( dllexport )
#  else /* LIBMILTER_EXPORTS */
#   define LIBMILTER_API		__declspec( dllimport )
#  endif /* LIBMILTER_EXPORTS */
# else /* WIN32_DLL */
#  define LIBMILTER_API		extern
# endif /* WIN32_DLL */

#else /* WIN32 */
# define LIBMILTER_API		extern
#endif /* WIN32 */

#ifdef WIN32

/*
**  Disable warning messages for differences in parameter lists.
**  The Microsoft compiler spits out a warning message if a
**  function pointer is assigned to another function pointer,
**  but the formal parameter lists of the functions do not agree.
**  The assignments are compiled without modification though,
**  so it's safe to disable this warning message.
*/

#pragma warning( disable : 4113 )
#endif /* WIN32 */

/* Only need to export C interface if used by C++ source code */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#ifndef SM_NET_H
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/un.h>

/*
**  generic sockaddr structure for sendmail
**  make parts of this conditional, compare sendmail8/sendmail/sendmail.h
*/

union sm_sockaddr_U
{
	struct sockaddr		sa;	/* general version */
	struct sockaddr_un	sunix;	/* UNIX family */
	struct sockaddr_in	sin;	/* INET family */
};

typedef union sm_sockaddr_U	sm_sockaddr_T, *sm_sockaddr_P;

#endif /* SM_NET_H */


/*
**  libmilter functions return SM_PMI_SUCCESS to indicate success;
**  a value < 0 indicates an error.
*/

#define SM_PMI_SUCCESS	0
#define SM_PMI_FAILURE	(-1)

/*
**  Type which callbacks should return to indicate message status.
**  This may take on one of the SMFIS_* values listed below.
*/

typedef int	sfsistat_T;

/*
**  Filter Routine Details
*/

/*
**  PMFI_NEGOTIATE -- check whether server capabilities and functions are
**	acceptable/sufficient
*/

typedef sm_ret_T (*pmfi_negotiate_F)(pmss_ctx_P _pmss_ctx, uint32_t _srv_cap, uint32_t _srv_fct, uint32_t _srv_feat, uint32_t _srv_misc, uint32_t *_pm_cap, uint32_t *_pm_fct, uint32_t *_pm_feat, uint32_t *_pm_misc);

/*
**  PMFI_CONNECT -- SMTP connection
**
**	hostname -- Host domain name, as determined by a reverse lookup
**		on the host address.
**	hostaddr -- Host address, as determined by a getpeername
**		call on the SMTP socket.
*/

typedef sfsistat_T (*pmfi_connect_F)(pmse_ctx_P _pmse_ctx, const char *_hostname, sm_sockaddr_T *_hostaddr);

/*
**  PMFI_HELO -- SMTP HELO/EHLO command
**
**	helohost -- Value passed to HELO/EHLO command, which should be
**		the domain name of the sending host (but is, in practice,
**		anything the sending host wants to send).
*/

typedef sfsistat_T (*pmfi_helo_F)(pmse_ctx_P _pmse_ctx, const char *_helohost);

/*
**  pmfi_mail -- envelope MAIL From
**
**	argv -- Null-terminated SMTP command arguments;
*/

typedef sfsistat_T (*pmfi_mail_F)(pmse_ctx_P _pmse_ctx, const char *_mail, char **_argv);

/*
**  PMFI_RCPT -- envelope recipient
**
**	char **argv -- Null-terminated SMTP command arguments;
*/

typedef sfsistat_T (*pmfi_rcpt_F)(pmse_ctx_P _pmse_ctx, const char *_rcpt, char **_argv);

/*
**  PMFI_DATA -- DATA
*/

typedef sfsistat_T (*pmfi_data_F)(pmse_ctx_P _pmse_ctx);


/*
**  PMFI_UNKNOWN -- unknown/not implemented SMTP command
**
**	cmd -- Null-terminated SMTP command
*/

typedef sfsistat_T (*pmfi_unknown_F)(pmse_ctx_P _pmse_ctx, const char *_cmd);

/*
**  PMFI_BODY -- each message chunk. There may
**  be multiple message chunks passed to the filter. End-of-lines are
**  represented as received from SMTP (normally Carriage-Return/Line-Feed).
**
**	msgp -- Pointer to message data
**	msglen -- Length of message data
*/

typedef sfsistat_T (*pmfi_msg_F)(pmse_ctx_P _pmse_ctx, unsigned char *_msgp, size_t _msglen);

/*
**  PMFI_EOM -- end of message.
*/

typedef sfsistat_T (*pmfi_eom_F)(pmse_ctx_P _pmse_ctx);

/*
**  PMFI_ABORT -- message is aborted outside of the control of
**  the filter, for example, if the SMTP sender issues an RSET command. If
**  pmfi_abort is called, pmfi_eom will not be called and vice versa.
*/

typedef sm_ret_T (*pmfi_abort_F)(pmse_ctx_P _pmse_ctx);

/*
**  PMFI_CLOSE -- end of the connection. This is called on
**  close even if the previous mail transaction was aborted.
*/

typedef sm_ret_T (*pmfi_close_F)(pmse_ctx_P _pmse_ctx);

/* XXX which context? */
typedef sm_ret_T (*pmfi_signal_F)(pmg_ctx_P _pmg_ctx, int _sig);

/*
**  structure describing one milter
*/

struct pmilter_S
{
	char		*pmfi_name;	/* filter name */
	uint32_t	 pmfi_version;	/* version code -- do not change */

	/* what does the milter want by default? */
	uint32_t	 pmfi_dfl_cap;	/* capabilities */
	uint32_t	 pmfi_dfl_fct;	/* functions */
	uint32_t	 pmfi_dfl_feat;	/* features */
	uint32_t	 pmfi_dfl_misc;	/* misc. */

	/* negotiate */
	pmfi_negotiate_F pmfi_negotiate;

	/* connect */
	pmfi_connect_F	 pmfi_connect;

	/* HELO/EHLO */
	pmfi_helo_F	 pmfi_helo;

#if 0
	/* STARTTLS */
	pmfi_starttls_F	 pmfi_starttls;

	/* AUTH */
	pmfi_auth_F	 pmfi_auth;
#endif

	/* MAIL */
	pmfi_mail_F	 pmfi_mail;

	/* RCPT */
	pmfi_rcpt_F	 pmfi_rcpt;

	/* DATA */
	pmfi_data_F	 pmfi_data;

	/* msg block */
	pmfi_msg_F	 pmfi_msg;

	/* end of message */
	pmfi_eom_F	 pmfi_eom;

	/* message aborted */
	pmfi_abort_F	 pmfi_abort;

	/* connection cleanup */
	pmfi_close_F	 pmfi_close;

	/* any unrecognized or unimplemented command filter */
	pmfi_unknown_F	 pmfi_unknown;

	pmfi_signal_F	 pmfi_signal;

	char		 pmfi_unused[64];
};

LIBMILTER_API sm_ret_T sm_pmfi_init(pmg_ctx_P *_pmg_ctx);
LIBMILTER_API sm_ret_T sm_pmfi_version(pmg_ctx_P _pmg_ctx, uint32_t *_major, uint32_t *_minor, uint32_t *_patchlevel);

/* LIBMILTER_API sm_ret_T sm_pmfi_register(pmg_ctx_P _pmg_ctx, pmilter_P _pmilter); */
LIBMILTER_API sm_ret_T sm_pmfi_setconn(pmg_ctx_P _pmg_ctx, const char *_path);

/* XXX why is this needed? */
LIBMILTER_API sm_ret_T sm_pmfi_opensocket(pmg_ctx_P _pmg_ctx, bool _rmsocket);
LIBMILTER_API sm_ret_T sm_pmfi_start(pmg_ctx_P _pmg_ctx, pmilter_P _pmilter);

LIBMILTER_API sm_ret_T sm_pmfi_setbacklog(pmg_ctx_P _pmg_ctx, int _backlog);
LIBMILTER_API sm_ret_T sm_pmfi_setdbg(pmg_ctx_P _pmg_ctx, unsigned int _debuglevel);
LIBMILTER_API sm_ret_T sm_pmfi_settimeout(pmg_ctx_P _pmg_ctx, int _timeout);
LIBMILTER_API sm_ret_T sm_pmfi_stop(pmg_ctx_P _pmg_ctx);

/*
**  set/get pmilter contexts
*/

/* "global" pmilter context: one per process */
LIBMILTER_API sm_ret_T sm_pmfi_set_ctx_g(pmg_ctx_P _pmg_ctx, void *_pmilter_g_ctx);
LIBMILTER_API void *sm_pmfi_get_ctx_g(pmg_ctx_P _pmg_ctx);

/* pmilter context per SMTP server */
LIBMILTER_API sm_ret_T sm_pmfi_set_ctx_ss(pmss_ctx_P _pmss_ctx, void *_pmilter_ss_ctx);
LIBMILTER_API void *sm_pmfi_get_ctx_ss(pmss_ctx_P _pmss_ctx);

/* get "global" context from ss context */
LIBMILTER_API void *sm_pmfi_get_ctx_g_ss(pmss_ctx_P _pmss_ctx);

/* pmilter context per SMTP session */
LIBMILTER_API sm_ret_T sm_pmfi_set_ctx_se(pmse_ctx_P _pmse_ctx, void *_pmilter_se_ctx);
LIBMILTER_API void *sm_pmfi_get_ctx_se(pmse_ctx_P _pmse_ctx);

/* get ss context from session context */
LIBMILTER_API void *sm_pmfi_get_ctx_ss_se(pmse_ctx_P _pmse_ctx);


/*
**  Continue processing message/connection.
*/

#define SMFIS_CONTINUE	SMTP_R_OK

/*
**  Reject the message/connection.
**  No further routines will be called for this message
**  (or connection, if returned from a connection-oriented routine).
*/

#define SMFIS_REJECT	SMTP_R_REJECT

/*
**  Accept the message,
**  but silently discard the message.
**  No further routines will be called for this message.
**  This is only meaningful from message-oriented routines.
*/

#define SMFIS_DISCARD	SMTP_R_DISCARD

/*
**  Accept the message/connection.
**  No further routines will be called for this message
**  (or connection, if returned from a connection-oriented routine;
**  in this case, it causes all messages on this connection
**  to be accepted without filtering).
*/

#define SMFIS_ACCEPT	SMTP_R_SET_QUICK(SMTP_R_OK)	/* XXX correct? */

/*
**  Return a temporary failure, i.e.,
**  the corresponding SMTP command will return a 4xx status code.
**  In some cases this may prevent further routines from
**  being called on this message or connection,
**  although in other cases (e.g., when processing an envelope
**  recipient) processing of the message will continue.
*/

#define SMFIS_TEMPFAIL	SMTP_R_TEMP


/*
**  Additional information is passed in to the vendor filter routines using
**  symbols. Symbols correspond closely to sendmail macros. The symbols
**  defined depend on the context. The value of a symbol is accessed using:
*/

/*
**  Set list of macros that should be sent by MTA
**
**	pmss_ctx -- Opaque context structure
**	where -- Which stage? (PM_SMST_*, see pmfdef.h)
**	macro -- The symbols to send (PMM_*, see pmfdef.h),
**		must end with PMM_END
*/

LIBMILTER_API sm_ret_T sm_pmfi_setmaclist(pmss_ctx_P _pmss_ctx, uint _where, ...);

/*
**  Get value of a symbol.
**
**	pmse_ctx_P ctx -- Opaque context structure
**	macro -- The symbol to access (PMM_*, see pmfdef.h)
**	value -- (pointer to) value of symbol
*/

LIBMILTER_API sm_ret_T sm_pmfi_getmac(pmse_ctx_P _pmse_ctx, uint32_t _macro, char **_pvalue);

/*
**  Set the specific reply code to be used in response to the active
**  command. If not specified, a generic reply code is used.
**
**	pmse_ctx ctx -- Opaque context structure
**	reply -- The text part of the SMTP reply (including error codes).
*/

LIBMILTER_API sm_ret_T sm_pmfi_setreply(pmse_ctx_P _pmse_ctx, const char *_reply);

/*
**  Get status of current SMTP command as set by SMTPS.
**  Currently only available for RCPT (if requested)
**
**	pmse_ctx ctx -- Opaque context structure
**	pstatus -- (pointer to) status (output)
*/

LIBMILTER_API sm_ret_T sm_pmfi_getstatus(pmse_ctx_P _pmse_ctx, sfsistat_T *_pstatus);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* ! PMFAPI_H */
