/*
 renattach 1.2.4 - Filter that renames/deletes dangerous email attachments
 Copyright (C) 2003-2006  Jem E. Berkes <jberkes@pc-tools.net>

 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 2 of the License, 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, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#include "config.h"
#include "renattach.h"
#include "strings-en.h"
#include "utility.h"
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef HAVE_STRCASECMP
#define strcasecmp stricmp
#endif

#ifndef HAVE_STRNCASECMP
#define strncasecmp strnicmp
#endif



/*
	Iterates through the list and returns the number of entries within.
	If verbose is specified, each entry is displayed.
*/
int tokenize_list(const char* thelist, int verbose)
{
	char *tmpbuf, *token;
	int count=0;

	tmpbuf = malloc(strlen(thelist) + 1);
	strcpy(tmpbuf, thelist);
	token = strtok(tmpbuf, LIST_TOKENS);
	while (token)
	{
		if (verbose)
		{
			if (count)
				fprintf(stderr, "|%s", token);
			else
				fprintf(stderr, "%s", token);
		}
		count++;
		token = strtok(NULL, LIST_TOKENS);
	}
	free(tmpbuf);
	return count;
}


/*
	Parse the configuration file and fill in the options structure
	Any errors found are written to stderr. Returns CODE_OK or CODE_FAILURE
*/
int parse_conf(struct config_opts* options)
{
	int linecount = 0;
	char confline[MAXFIELD];
	char directive[MAXFIELD], parameter[MAXFIELD];
	FILE* config = NULL;

	if (options->config_file == NULL)
	{
		fprintf(stderr, TXT_INFO_CONFIGFILE TXT_INFO_UNDEF "\n");
		return CODE_FAILURE;
	}

	config = fopen(options->config_file, "r");
	if (!config)
	{
		perror(options->config_file);
		return CODE_FAILURE;
	}

	while (fgets(confline, sizeof(confline), config))
	{
		int syntax_error = 0;
		linecount++;

		trim_leading(confline);
		trim_trailing(confline);

		if ((*confline == '#') || (*confline == '\r') || (*confline == '\n'))
			continue;
		if (sscanf(confline, "%[^\t =]%*[\t =]%[^\r\n]", directive, parameter) == 2)
		{
			int state = OPTION_UNSET;
			if ( (strncasecmp(parameter, TAG_OPTENABLED, strlen(TAG_OPTENABLED))==0)
				|| (*parameter=='1'))	/* 'yes' or 1 */
				state = OPTION_ENABLED;
			else if ( (strncasecmp(parameter, TAG_OPTDISABLED, strlen(TAG_OPTDISABLED))==0)
				|| (*parameter=='0'))	/* 'no' or 0 */
				state = OPTION_DISABLED;

			if ((strcasecmp(directive, TAG_DELETE_EXE)==0) && state)
				options->delete_exe = state;
			else if ((strcasecmp(directive, TAG_KILL_EXE)==0) && state)
				options->kill_exe = state;
			else if ((strcasecmp(directive, TAG_SEARCH_ZIP)==0) && state)
				options->search_zip = state;
			else if ((strcasecmp(directive, TAG_PASS_CONTENTID)==0) && state)
				options->pass_contentid = state;
			else if ((strcasecmp(directive, TAG_FULL_RENAME)==0) && state)
				options->full_rename = state;
			else if ((strcasecmp(directive, TAG_USE_SYSLOG)==0) && state)
				options->use_syslog = state;
			else if (strcasecmp(directive, TAG_GENERIC_NAME) == 0)
				strcpy(options->generic_name, parameter);
			else if (strcasecmp(directive, TAG_NEW_EXTENSION) == 0)
				strcpy(options->new_extension, parameter);
			else if (strcasecmp(directive, TAG_NEW_MIME_TYPE) == 0)
				strcpy(options->new_mime_type, parameter);
			else if (strcasecmp(directive, TAG_SUBJ_BANNED) == 0)
				strcpy(options->subj_banned, parameter);
			else if (strcasecmp(directive, TAG_SUBJ_EXEC) == 0)
				strcpy(options->subj_exec, parameter);
			else if (strcasecmp(directive, TAG_SUBJ_DELETED) == 0)
				strcpy(options->subj_deleted, parameter);
			else if (strcasecmp(directive, TAG_SUBJ_RENAMED) == 0)
				strcpy(options->subj_renamed, parameter);
			else if (strcasecmp(directive, TAG_ADD_SUBJECT) == 0)
				strcpy(options->add_subject, parameter);
			else if (strcasecmp(directive, TAG_HTMLWARN_POS) == 0)
				strcpy(options->htmlwarn_pos, parameter);
			else if (strcasecmp(directive, TAG_WARNING_TEXT) == 0)
				expand_list(&options->warning_text, parameter, "\n");
			else if (strcasecmp(directive, TAG_WARNING_HTML) == 0)
				expand_list(&options->warning_html, parameter, "\n");
			else if (strcasecmp(directive, TAG_ADD_HEADER) == 0)
				expand_list(&options->add_header, parameter, "\n");
			else if (strcasecmp(directive, TAG_BANNED_FILES) == 0)
				expand_list(&options->banned_files, parameter, "\n");
			else if (strcasecmp(directive, TAG_BADLIST) == 0)
				expand_list(&options->badlist, parameter, "\n");
			else if (strcasecmp(directive, TAG_GOODLIST) == 0)
				expand_list(&options->goodlist, parameter, "\n");
			else
				syntax_error = 1;
		}
		else
			syntax_error = 1;

		if (syntax_error)
		{
			fprintf(stderr, TXT_ERR_CONFSYNTAX "%d: %s\n", linecount, confline);
			fclose(config);
			return CODE_FAILURE;
		}
	}

	fclose(config);
	return CODE_OK;
}


/*
	Check all configuration directives
	If any are unset, use defaults
*/
void directive_defaults(struct config_opts* options)
{
	if (options->delete_exe == OPTION_UNSET)
		options->delete_exe = DEF_DELETE_EXE;
	if (options->kill_exe == OPTION_UNSET)
		options->kill_exe = DEF_KILL_EXE;
	if (options->search_zip == OPTION_UNSET)
		options->search_zip = DEF_SEARCH_ZIP;
	if (options->pass_contentid == OPTION_UNSET)
		options->pass_contentid = DEF_PASS_CONTENTID;
	if (options->full_rename == OPTION_UNSET)
		options->full_rename = DEF_FULL_RENAME;
	if (options->use_syslog == OPTION_UNSET)
		options->use_syslog = DEF_USE_SYSLOG;
	if (options->generic_name[0] == '\0')
		strcpy(options->generic_name, DEF_GENERIC_NAME);
	if (options->new_extension[0] == '\0')
		strcpy(options->new_extension, DEF_NEW_EXTENSION);
	if (options->new_mime_type[0] == '\0')
		strcpy(options->new_mime_type, DEF_NEW_MIME_TYPE);
	if (options->subj_banned[0] == '\0')
		strcpy(options->subj_banned, DEF_SUBJ_BANNED);
	if (options->subj_exec[0] == '\0')
		strcpy(options->subj_exec, DEF_SUBJ_EXEC);
	if (options->subj_deleted[0] == '\0')
		strcpy(options->subj_deleted, DEF_SUBJ_DELETED);
	if (options->subj_renamed[0] == '\0')
		strcpy(options->subj_renamed, DEF_SUBJ_RENAMED);
	if (options->add_subject[0] == '\0')
		strcpy(options->add_subject, DEF_ADD_SUBJECT);
	if (options->htmlwarn_pos[0] == '\0')
		strcpy(options->htmlwarn_pos, DEF_HTMLWARN_POS);
	if ( (options->warning_text == NULL) || (options->warning_text[0] == '\0'))
		expand_list(&options->warning_text, DEF_WARNING_TEXT, "\n");
	if ( (options->warning_html == NULL) || (options->warning_html[0] == '\0'))
		expand_list(&options->warning_html, DEF_WARNING_HTML, "\n");
	if ( (options->add_header == NULL) || (options->add_header[0] == '\0'))
		expand_list(&options->add_header, DEF_ADD_HEADER, "\n");
	if ( (options->banned_files == NULL) || (tokenize_list(options->banned_files, 0)==0) )
		expand_list(&options->banned_files, DEF_BANNED_FILES, "\n");
	if ( (options->goodlist == NULL) || (tokenize_list(options->goodlist, 0)==0) )
		expand_list(&options->goodlist, DEF_GOODLIST, "\n");
	if ( (options->badlist == NULL) || (tokenize_list(options->badlist, 0)==0) )
		expand_list(&options->badlist, DEF_BADLIST, "\n");
}


/*
	Show current configuration; used in verbose mode
*/
void show_configuration(struct config_opts* options)
{
	/* Where is our configuration file? */
	fprintf(stderr, TXT_INFO_CONFIGFILE "\n  ");
	if (options->config_file)
		fprintf(stderr, "%s\n", options->config_file);
	else
		fprintf(stderr, TXT_INFO_UNDEF "\n");

	fprintf(stderr, TXT_INFO_OUTPUT "\n  ");
	if (options->pipe_cmd)
	{
		int arg = 0;
		fprintf(stderr, "{");
		while (options->pipe_cmd[arg])
		{
			if (arg) fprintf(stderr, "|");
			fprintf(stderr, "%s", options->pipe_cmd[arg++]);
		}
		fprintf(stderr, "}\n");
	}
	else
		fprintf(stderr, TXT_INFO_STDOUT "\n");

	/* What filtering mode are we using? */
	fprintf(stderr, TXT_INFO_MODE "\n  %s\n", mode2str(options->mode));

	/* What filtering action are we using? */
	fprintf(stderr, TXT_INFO_ACTION "\n  %s\n", act2str(options->action));

	fprintf(stderr, TXT_INFO_CONFOPTS "\n");
	/* Show status of all settings from renattach.conf */
	fprintf(stderr, "  "TAG_DELETE_EXE ": %s\n", opt2str(options->delete_exe));
	fprintf(stderr, "  "TAG_KILL_EXE ": %s\n", opt2str(options->kill_exe));
	fprintf(stderr, "  "TAG_SEARCH_ZIP ": %s\n", opt2str(options->search_zip));
	fprintf(stderr, "  "TAG_PASS_CONTENTID ": %s\n", opt2str(options->pass_contentid));
	fprintf(stderr, "  "TAG_FULL_RENAME ": %s\n", opt2str(options->full_rename));
	fprintf(stderr, "  "TAG_USE_SYSLOG ": %s\n", opt2str(options->use_syslog));
	fprintf(stderr, "  "TAG_GENERIC_NAME ": \"%s\"\n", options->generic_name);
	fprintf(stderr, "  "TAG_NEW_EXTENSION ": \"%s\"\n", options->new_extension);
	fprintf(stderr, "  "TAG_NEW_MIME_TYPE ": \"%s\"\n", options->new_mime_type);
	fprintf(stderr, "  "TAG_SUBJ_BANNED ": \"%s\"\n", options->subj_banned);
	fprintf(stderr, "  "TAG_SUBJ_EXEC ": \"%s\"\n", options->subj_exec);
	fprintf(stderr, "  "TAG_SUBJ_DELETED ": \"%s\"\n", options->subj_deleted);
	fprintf(stderr, "  "TAG_SUBJ_RENAMED ": \"%s\"\n", options->subj_renamed);
	fprintf(stderr, "  "TAG_ADD_SUBJECT ": \"%s\"\n", options->add_subject);
	fprintf(stderr, "  "TAG_HTMLWARN_POS ": \"%s\"\n", options->htmlwarn_pos);
	fprintf(stderr, "  "TAG_WARNING_TEXT ": %d bytes,\n%s\n",
		(int)strlen(options->warning_text), options->warning_text);
	fprintf(stderr, "  "TAG_WARNING_HTML ": %d bytes,\n%s\n",
		(int)strlen(options->warning_html), options->warning_html);
	fprintf(stderr, "  "TAG_ADD_HEADER ": %d bytes,\n%s\n",
		(int)strlen(options->add_header), options->add_header);
	fprintf(stderr, "  "TAG_BANNED_FILES ": {");
	tokenize_list(options->banned_files, 1);
	fprintf(stderr, "}\n  "TAG_BADLIST ": {");
	tokenize_list(options->badlist, 1);
	fprintf(stderr, "}\n  " TAG_GOODLIST ": {");
	tokenize_list(options->goodlist, 1);
	fprintf(stderr, "}\n");
}


/*
	Return description of directive state
*/
const char* opt2str(int state)
{
	if (state == OPTION_DISABLED)
		return TAG_OPTDISABLED;
	else if (state == OPTION_ENABLED)
		return TAG_OPTENABLED;
	else
		return TXT_INFO_UNDEF;
}


/*
	Return description of filter mode
*/
const char* mode2str(int mode)
{
	if (mode == MODE_ALL)
		return TXT_INFO_MODEALL;
	else if (mode == MODE_BAD)
		return TXT_INFO_MODEBAD;
	else if (mode == MODE_GOOD)
		return TXT_INFO_MODEGOOD;
	else
		return TXT_INFO_UNDEF;
}


/*
	Return description of action type
*/
const char* act2str(int action)
{
	switch (action)
	{
		case ACTION_RENAME:
			return TAG_ACTRENAME;

		case ACTION_DELETE:
			return TAG_ACTDELETE;

		case ACTION_KILL:
			return TAG_ACTKILL;

		case ACTION_SKIP:
			return TAG_ACTSKIP;

		default:
			return TXT_INFO_UNDEF;
	}
}


syntax highlighted by Code2HTML, v. 0.9.1