/*
 * Program: Synonym
 * File: filtering.c
 * Author: Ionut Nistor
 * Date: 9 Sep 2003
 *
 * $Id: filtering.c,v 1.4 2004/01/19 09:24:31 diciu Exp $
 *
 * Licensed under the Modulo Consulting Software License
 * (see file license.txt)
 * 
 */


#include <stdlib.h>
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
#include "synonym.h"
#include "filtering.h"
#include "config.h"


const char filtering_c_objid[]="$Id: filtering.c,v 1.4 2004/01/19 09:24:31 diciu Exp $";

sresult Synonym_Process_Rules(synonym_rule *rules, synonym_header *headers, char *envelope_from, to_list *envelope_to, matched_action **matched_actions)
{
	synonym_rule *temp_rule;
	synonym_condition *temp_condition;
	synonym_header *temp_header;
	to_list *temp_to;
	matched_action *new_matched_action, *temp_action;

	BOOL condition_mismatch; /* Flag used to drop us out of the rule is a condition failed to match */
	
//	if(headers == NULL) /* Just in case - even though it should already have been checked in the calling module */
//	{
//		syslog(LOG_ERR, "No headers found for rules processing");
//		return SYNONYM_RULES_PROCESSING_ERROR;
//	}
	syslog(LOG_DEBUG, "Begin checking rules");
	for(temp_rule=rules; temp_rule != NULL; temp_rule = temp_rule->next) /* Parse all the rules */
	{
		syslog(LOG_DEBUG, "Processing rule...");
		condition_mismatch = FALSE;
		if(temp_rule->conditions==NULL) /* Just in case, though we checked in the config parsing */
		{
			syslog(LOG_ERR, "No conditions in rule while processing the rules");
			return SYNONYM_RULES_PROCESSING_ERROR;
		}
		for(temp_condition=temp_rule->conditions;temp_condition!=NULL;temp_condition=temp_condition->next) /* All the conditions in the current rule */
		{
			/* Let's look for the condition type */
			if(temp_condition->header_field[0] != '\0') /* We have a header condition */
			{
				syslog(LOG_DEBUG, "Checking condition in rule (look for %s header field)", temp_condition->header_field);
				for(temp_header=headers; temp_header != NULL; temp_header = temp_header->next)
					if(!strcasecmp(temp_condition->header_field, temp_header->header_name)) /* We found the header to match */
					{
						syslog(LOG_DEBUG, "Checking %s against header name %s value %s", temp_condition->header_regexp, temp_header->header_name, temp_header->header_value);
						if(regexec(&temp_condition->header_compiled_regexp, temp_header->header_value, 0, NULL, 0) == REG_NOMATCH) /* Condition does not match so the rule drops since all conditions are implemented with 'and' between them */
						{
								syslog(LOG_DEBUG, "Header condition failed to match");
								condition_mismatch = TRUE;
								break;
						}
						else /* It matched */
							break;
					}
				if(temp_header == NULL) /* We did not find any header with that name */
					condition_mismatch = TRUE;
	
				if(condition_mismatch) /* One condition already failed to match */
					break;
			}
			if(temp_condition->env_to_condition[0] != '\0') /* We have an 'envelope to' condition */
			{
				syslog(LOG_DEBUG, "Matching an envelope from");
				for(temp_to=envelope_to; temp_to!=NULL; temp_to=temp_to->next)
				{
					if(regexec(&temp_condition->env_to_compiled_regexp, temp_to->email, 0, NULL, 0) == REG_NOMATCH) /* Condition does not match so the rule drops since all conditions are implemented with 'and' between them */
					{
							syslog(LOG_DEBUG, "'Envelope To' condition failed to match");
							condition_mismatch = TRUE;
					}	
				}
			}
			if(temp_condition->env_from_condition[0] != '\0') /* We have an 'envelope from' condition */
			{
				syslog(LOG_DEBUG, "Matching an envelope from");
				if(regexec(&temp_condition->env_from_compiled_regexp, envelope_from, 0, NULL, 0) == REG_NOMATCH) /* Condition does not match so the rule drops since all conditions are implemented with 'and' between them */
				{
						syslog(LOG_DEBUG, "'Envelope From' condition failed to match");
						condition_mismatch = TRUE;
				}	
			}
		}
		if(!condition_mismatch) /* All the condition of the rule matched */
		{
			syslog(LOG_DEBUG, "All conditions matched for the action type %d", temp_rule->action.action_type);
			new_matched_action = (matched_action*)malloc(sizeof(matched_action));
			if(new_matched_action == NULL) /* Alloc failure */
			{
				syslog(LOG_CRIT, "CRITICAL ERROR: Failed to allocate memory in rule processing");
				return SYNONYM_ALLOC_FAILED;
			}
			new_matched_action->action.action_type = temp_rule->action.action_type;
			if(temp_rule->action.action_custom_field != NULL)
				strcpy(new_matched_action->action.action_custom_field, temp_rule->action.action_custom_field);
#ifdef DISCLAIMER_SUPPORT
			if(temp_rule->action.action_text_disclaimer != NULL)
				strcpy(new_matched_action->action.action_text_disclaimer, temp_rule->action.action_text_disclaimer);
			if(temp_rule->action.action_html_disclaimer != NULL)
				strcpy(new_matched_action->action.action_html_disclaimer, temp_rule->action.action_html_disclaimer);
#endif
			new_matched_action->next = NULL;
			if(*matched_actions == NULL) /* None matched until now */
				*matched_actions = new_matched_action;
			else /* Add at the end of the list */
			{
				temp_action = *matched_actions;
				while(temp_action->next != NULL)
					temp_action = temp_action->next;
				temp_action->next=new_matched_action;
			}
		}

	}
	return SYNONYM_OK;
}


syntax highlighted by Code2HTML, v. 0.9.1