#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> 
#include <string.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

/*State flags*/
#define MS_OK	00001 /*Envelope processed without errors*/
#define MS_ER	00002 /*Errors occupated while processed envelope*/

/*Errors, if -1 well, I think that unknown error happened*/
#define ER_IO	00004 /*in/out error*/
#define ER_NE	00010 /*network error - connect, send/recive, and so on*/
#define ER_ME	00020 /*segmention errors. Unused at this time.
			Now simply writes syslog msg and calls abort()*/
#define ER_PO	00040 /*If filter didn't follows the MILTER protocol*/
#define ER_SI	00100 /*Die by system signal (not done at this time too =)*/

/*Nornal state*/
#define OK_UC   00200 /*passed and unchanged*/
#define OK_HC	00400 /*passed and header(s) changed (del, chan, add)*/
#define OK_BC	01000 /*passed and body changed*/

#define MS_RJ	02000 /*rejected by filter verdict*/
#define MS_QU	04000 /*quarantined by filter verdict*/

#ifndef true
typedef int bool;
# define false  0
# define true   1
#endif /* ! true */

#define MINADDRLEN	4

# define SMFTO_WRITE	0		/* Timeout for sending information */
# define SMFTO_READ	1		/* Timeout waiting for a response */
# define SMFTO_EOM	2		/* Timeout for ACK/NAK to EOM */
# define SMFTO_CONNECT	3		/* Timeout for connect() */

# define SMFTO_NUM_TO	4		/* Total number of timeouts */

/* MTA flags */
# define SMF_REJECT		'R'	/* Reject connection on filter fail */
# define SMF_TEMPFAIL		'T'	/* tempfail connection on failure */

/* states */
# define SMFS_CLOSED		'C'	/* closed for all further actions */
# define SMFS_OPEN		'O'	/* connected to remote milter filter */
# define SMFS_INMSG		'M'	/* currently servicing a message */
# define SMFS_DONE		'D'	/* done with current message */
# define SMFS_CLOSABLE		'Q'	/* done with current connection */
# define SMFS_ERROR		'E'	/* error state */
# define SMFS_READY		'R'	/* ready for action */

#define MAX_HEADER_LEN 1001		/* Actually 998 + CR + LF */
#define MAX_LONGHEADER 8192		/* Overall size of multiline header */

struct milter
{
	char		*mf_name;	/* filter name */
	unsigned long	mf_fvers;	/* filter version */
	unsigned long	mf_fflags;	/* filter flags */
	unsigned long	mf_pflags;	/* protocol flags */
	char		*mf_conn;	/* connection info */
	int		mf_sock;	/* connected socket */
	char		mf_state;	/* state of filter */
	time_t		mf_timeout; /* timeouts */
};

typedef struct milter MILTER;

struct header
{
	char		*h_field;	/* the name of the field */
	char		*h_value;	/* the value of that field */
	struct header	*h_link;	/* the next header */
};
typedef struct header	HDR;

struct envrcpt
{
	char *r_value;
	struct envrcpt *r_link;
};
typedef struct envrcpt	RCPT;

struct envlp {
	char *e_envfrom;
	RCPT *e_rcpts;   /* list of rcpt's  */
	HDR *e_headers;  /* list of headers */
	int e_bfd;       /* descriptor to the body location */
	char *e_bfn;     /* tmp file name of the body source */
	size_t e_msgsize;/* size of the real message */
	int e_state;
};
typedef struct envlp	ENVELOPE;

/* type of connection information: default, external (given by fwtk), internal data (given manualy)*/
#define CONNDEF 1
#define CONNEXT 2
#define CONNINT 3

int milter_inspect_mail(char*, char*, char*, char*, char*, char*, char ***);
int milter_inspect_binary(char*, char*, char*, char*, char*, char*, char ***, char*, char*);
