/************************************************************
** $Id: edit.c,v 0.6 2003/11/09 17:25:21 bcx Exp bcx $
**
** Copyright Bryan Costales and Perforce Software, Inc. 2003
**
** This code is "open source" as defined by version 1.9 of
** the Open Source Definition from:
**
**	http://www.opensource.org/docs/definition.php.
**
** The is the slowedit interface for the milter.
**
*************************************************************/

# define EXTERN extern
# include "slow.h"

extern PRIV *Priv;		/* in test.c */
extern struct smfi_str Ctx;	/* in test.c */

typedef struct {
	char *token;
	int   mode;
} EDITCOMMANDS;

EDITCOMMANDS EditCommands[] = {
# define EDITCOM_ADD		1
	{"add", 	EDITCOM_ADD},		/* add an IP event */
# define EDITCOM_DELETE		2
	{"delete", 	EDITCOM_DELETE},	/* delete an IP and all its events */
# define EDITCOM_ALIAS		3
	{"alias", 	EDITCOM_ALIAS},		/* add an IP alias */
# define EDITCOM_WHITE		4
	{"whitelist", 	EDITCOM_WHITE},		/* whitelist an IP address */
# define EDITCOM_TRIM		5
	{"trim", 	EDITCOM_TRIM},		/* remove an event from an IP */
	{NULL,		0},
};

bool
slowedit(int opt, int argc, char **argv)
{
	int ret, mode;
	EDITCOMMANDS *e;
	char *user;
	extern char *optarg;

	/*
	 * Format of an edit command is "slowedit command switches IP
	 * On entry to this routine, argv[0] is the command.
	 */
	mode = 0;
	for (e = EditCommands; e->token != NULL; ++e)
	{
		if (strcasecmp(argv[opt], e->token) == 0)
		{
			mode = e->mode;
			break;
		}
	}
	if (mode == 0)
	{
		printf("Usage: slowedit ");
		for (e = EditCommands; e->token != NULL; ++e)
			printf("%s%s",
				e == EditCommands ? "" : "|",
				e->token);
		printf("\n");
		return FALSE;
	}

	test_init(TRUE);
	ret = 0;
	user = cuserid(NULL);
	switch(mode)
	{
	    /* add IP event */
	    case EDITCOM_ADD:
		ret = slowadd(user, opt, argc, argv);
		break;

	    case EDITCOM_DELETE:
		ret = slowdelete(user, opt, argc, argv);
		break;

	    case EDITCOM_ALIAS:
		ret = slowalias(user, opt, argc, argv);
		break;

	    case EDITCOM_WHITE:
		ret = slowwhite(user, opt, argc, argv);
		break;

	    case EDITCOM_TRIM:
		ret = slowtrim(user, opt, argc, argv);
		break;
	}
	return ret;
}

bool
slowadd(char *user, int opt, int argc, char **argv)
{
	PRIMARY_DATUM ip;
	char *iptext;
	char *event_str;
	char logprefix[BUFSIZ];

	++opt;
	if ((argc - opt) < 2)
	{
		(void) printf("Usage: slowedit add IPnumber \"event,event,...\"\n");
		return FALSE;
	}
	iptext = try_strdup(__FILE__, __LINE__, argv[opt]);
	++opt;
	event_str = try_strdup(__FILE__, __LINE__, argv[opt]);
	if (slowsetpriv(iptext, event_str) == FALSE)
		return FALSE;

	if (user == NULL)
		sprintf(logprefix, "edit add: ");
	else
		sprintf(logprefix, "%s added: ", user);
	LogPrefix = logprefix;

	if (push_to_db(&Ctx, Priv) != SMFIS_CONTINUE)
		return FALSE;

	(void) free(event_str);
	return TRUE;
}

bool
slowdelete(char *user, int opt, int argc, char **argv)
{
	printf("slowedit delete\n");
	return TRUE;
}

bool
slowalias(char *user, int opt, int argc, char **argv)
{
	printf("slowedit alias\n");
	return TRUE;
}

bool
slowwhite(char *user, int opt, int argc, char **argv)
{
	printf("slowedit white\n");
	return TRUE;
}

bool
slowtrim(char *user, int opt, int argc, char **argv)
{
	printf("slowedit trim\n");
	return TRUE;
}

typedef struct {
	char *event;
	int   index;
} EVENT_LIST;

EVENT_LIST EventList[] = {
# define EVENT_ENVRCPTS		1
	{"er", EVENT_ENVRCPTS},	/* envelope recipients */
# define EVENT_HDRRCPTS		2
	{"hr", EVENT_HDRRCPTS},	/* header recipients */
# define EVENT_HONEYRCPTS	3
	{"ho", EVENT_HONEYRCPTS},	/* honey pot recipients */
# define EVENT_BADRCPTS		4
	{"br", EVENT_BADRCPTS},	/* bad envelope recipients */
# define EVENT_TOOHDR		5
	{"hed", EVENT_TOOHDR},	/* too many header recipients */
# define EVENT_TOOENV		6
	{"env", EVENT_TOOENV},	/* too many envelope recipients */
# define EVENT_HONEY		7
	{"hon", EVENT_HONEY},	/* one or more honey pots rcpts */
# define EVENT_MSGID		8
	{"mid", EVENT_MSGID},	/* bad or missing message-id header */
# define EVENT_FROMH		9
	{"frm", EVENT_FROMH},	/* bad or missing message-id header */
# define EVENT_BADHO		10
	{"bho", EVENT_BADHO},	/* bad or missing message-id header */
# define EVENT_RBL		11
	{"rbl", EVENT_RBL},	/* bad or missing message-id header */
# define EVENT_MILT		12
	{"abo", EVENT_MILT},	/* bad or missing message-id header */
# define EVENT_ADVW		13
	{"pip", EVENT_ADVW},	/* bad or missing message-id header */
# define EVENT_FORGE		14
	{"for", EVENT_FORGE},	/* bad or missing message-id header */
# define EVENT_FROMMX		15
	{"mmx", EVENT_FROMMX},	/* bad or missing message-id header */
# define EVENT_NOTINET		16
	{"net", EVENT_NOTINET},	/* bad or missing message-id header */
	{NULL,	0},
};

int
is_event(char *str)
{
	EVENT_LIST *e;

	for (e = EventList; e->event != NULL; ++e)
	{
		if (strcasecmp(e->event, str) == 0)
			return e->index;
	}
	return 0;
}

bool
slowsetpriv(char *iptext, char *estr)
{
	char **list, **l;
	char **equate;
	char *item;
	int   value;
	int   index;
	
	list = mkargv(estr, ',');
	if (list == NULL)
	{
		(void) printf("slowedit: events missing\n");
		return FALSE;
	}
	if (isdebug(BUG_EDIT))
		print_list("slowsetpriv", list, stdout);

	for (l = list; *l != NULL; l++)
	{
		value = 0;
		if (strchr(*l, '=') != NULL)
		{
			equate = mkargv(*l, '=');
			if (equate == NULL)
				continue;
			item = try_strdup(__FILE__, __LINE__, equate[0]);
			if (equate[1] != NULL)
				value = atoi(equate[1]);
			else
				milterr(Prog, __FILE__, __LINE__, FALSE,
					EINVAL, item,
					"Expected =value");
		}
		else
			item = try_strdup(__FILE__, __LINE__, *l);

		index = is_event(item);
		if (index == 0)
		{
			milterr(Prog, __FILE__, __LINE__, FALSE,
				EINVAL, item,
				"Unrecognized event keyword");
		}

		switch(index)
		{
		    /* count of envelope recipients */
		    case EVENT_ENVRCPTS:
			if (value <= 0)
			{
				milterr(Prog, __FILE__, __LINE__, FALSE,
					EINVAL, item,
					"May not have a value zero or less");
			}
			Priv->envrcpts = value;
			break;

		    case EVENT_HDRRCPTS:
			if (value <= 0)
			{
				milterr(Prog, __FILE__, __LINE__, FALSE,
					EINVAL, item,
					"May not have a value zero or less");
			}
			Priv->nhdrrcpts = value;
			break;

		    case EVENT_HONEYRCPTS:
			if (value <= 0)
			{
				milterr(Prog, __FILE__, __LINE__, FALSE,
					EINVAL, item,
					"May not have a value zero or less");
			}
			Priv->honeyrcpts = value;
			break;

		    case EVENT_BADRCPTS:
			if (value <= 0)
			{
				milterr(Prog, __FILE__, __LINE__, FALSE,
					EINVAL, item,
					"May not have a value zero or less");
			}
			Priv->badrcpts = value;
			break;

		    case EVENT_TOOHDR:
			set_bit(BIT_TOO_MANY_HDR_RCPTS, Priv->bits);
			break;

		    case EVENT_TOOENV:
			set_bit(BIT_TOO_MANY_ENV_RCPTS, Priv->bits);
			break;

		    case EVENT_HONEY:
			set_bit(BIT_GOT_HONEYPOT, Priv->bits);
			break;

		    case EVENT_MSGID:
			set_bit(BIT_BAD_MSG_ID, Priv->bits);
			break;

		    case EVENT_FROMH:
			set_bit(BIT_BAD_FROM_HEAD, Priv->bits);
			break;

		    case EVENT_BADHO:
			set_bit(BIT_BAD_HOST, Priv->bits);
			break;

		    case EVENT_RBL:
			set_bit(BIT_RBL_BAD, Priv->bits);
			break;

		    case EVENT_MILT:
			set_bit(BIT_MILTER_ABORTED, Priv->bits);
			break;

		    case EVENT_ADVW:
			set_bit(BIT_ADVANCEWRITE, Priv->bits);
			break;

		    case EVENT_FORGE:
			set_bit(BIT_FORGED, Priv->bits);
			break;

		    case EVENT_FROMMX:
			set_bit(BIT_FROMMX, Priv->bits);
			break;

		    case EVENT_NOTINET:
			set_bit(BIT_NOTINET, Priv->bits);
			break;

		}
		(void) free(item);
	}
	Priv->iptxt = iptext;
	return TRUE;
}

