/*
 * Copyright (C) 2005 Baris Simsek, <simsek@enderunix.org>
 *                        http://www.enderunix.org/simsek/
 *
 * $Id: scanengine.c,v 1.1.1.1 2006/07/21 08:59:27 simsek Exp $
 *
 */

#include "qsheff-config.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>
#include <ctype.h>
#include <regex.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>

#include "smtp.h"
#include "loadconfig.h"
#include "scanengine.h"
#include "toolkit.h"
#include "log.h"

extern int errno;

static char *get_ruleword(char *ruleword, char *line)
{
	int i = 0;

	line++;
	while((*line != ')') && (*line != '\0')) ruleword[i++] = *line++;
	ruleword[i] = '\0';

	return ruleword;
}

static char *strip_ruleline(char *ruleline)
{
	char ch;

	while(*ruleline != '\0') {
		ch = *ruleline;
		ruleline++;
		if((ch == ')') && (*ruleline == '(')) break;
	}

	if(strlen(ruleline) < 1) return NULL;

	return ruleline;
}

/* Regular expression support. */
static int match_pattern(regex_t *regexp, char *line)
{
	int start = 0;						/* The offset from the beginning of the line */
	size_t no_sub = regexp->re_nsub + 1;			/* How many matches are there in a line? */
	regmatch_t *result;

	if ((result = (regmatch_t *) malloc(sizeof(regmatch_t) * no_sub)) == 0)
	{
		errlog(__FILE__, __LINE__, errno);
		return -1;
	}
  
	while (regexec(regexp, line+start, no_sub, result, 0) == 0)
	{
		free(result);
		return 1;					/* Found a match. */
	}

	free(result);

	return 0;
}

int do_regex(char *line, char *pattern)
{
	int ret = 0;
	regex_t *regexp; /* Regular expression pointer for the filter. */

	/* Allocate space for the regular expressions. */
	if ((regexp = (regex_t *) malloc(sizeof(regex_t))) == NULL) {
		errlog(__FILE__, __LINE__, errno);
		return -1;
	}
	memset(regexp, 0, sizeof(regex_t));

	if ((ret = regcomp(regexp, pattern, 0)) != 0) /* Compile the regular expression. */
	{
		regfree(regexp);
		free(regexp);
		return -1;
	}

	ret = match_pattern(regexp, line);

	regfree(regexp);
	free(regexp);

	return ret;
}


/* The heart of the code */
int body_filter(char *filename, char rt)
{
	int i, lc;
	FILE *fd;
	int ret, flag;
	char *ruleline;
	rulelist *tmp;
	char *ruleword;
	char msgbody[MAXBODYLINE][1024];

	if((fd = fopen(filename, "r")) == NULL) {
		errlog(__FILE__, __LINE__, errno);
		return -1;
	}

	lc = 0;
	while ((!feof(fd)) && (lc < MAXBODYLINE))
	{
                memset(msgbody[lc], 0, 1024);
		if ((fgets(msgbody[lc], 1024, fd) == NULL) && (!feof(fd)))
		{
			errlog(__FILE__, __LINE__, errno);
			fclose(fd);
                        return -1;
                }
		else
		{
			msgbody[lc][strlen(msgbody[lc])-1] = '\0';
		}
		lc++;
        }

	if ((ruleword = (char *) malloc(256)) == NULL) {
		errlog(__FILE__, __LINE__, errno);
		fclose(fd);
		return -1;
	}

	tmp = rule_sp;
	while(tmp != NULL) {
		if((tmp->attr == rt) || (tmp->attr == 'a'))
		{
			ruleline = tmp->ruleline;
			memset(rule_word, 0x0, sizeof(rule_word));
			strncpy(rule_word, ruleline, sizeof(rule_word)-1);
			memset(ruleword, 0x0, 256);

			while ((ruleword = get_ruleword(ruleword, ruleline)) != NULL) {
				flag = 0;
				for(i=0; i<lc; i++) {
					memset(spam_word, 0, sizeof(spam_word));
					strncpy(spam_word, msgbody[i], sizeof(spam_word)-1);

					ret = do_regex(msgbody[i], ruleword);
					if (ret == 1) {
						flag = 1;
						break;
					}
					else if (ret == -1) {
						free(ruleword);
						fclose(fd);
						return -1;
					}
				}
				if(flag == 0) break;

				if ((ruleline = strip_ruleline(ruleline)) == NULL) {
					/* End of rule line. AND chain is TRUE. */
					break;
				}
			}
			if (flag == 1) {
				/* AND chain is TRUE. All patterns in the chain are matched. */
				free(ruleword);
				fclose(fd);
				return 1;
			}
		}
		tmp = tmp->next;
	}

	free(ruleword);
        fclose(fd);

	return 0;
}

int attach_filter()
{
	int i, j;
	DIR *dirp;
	struct dirent *direntp;
	struct stat statbuf;
	char filename[256];
	char str[256];

	memset(filename, 0, sizeof(filename));

	if((dirp = opendir(".")) == NULL) {
		errlog(__FILE__, __LINE__, errno);
		return -1;
	}

	while((direntp = readdir(dirp)) != NULL) {
		if(strlen(direntp->d_name) > sizeof(filename)-1) return 1;
		strncpy(filename, direntp->d_name, sizeof(filename)-1);

		if((strncmp(filename, "textfile", 8) !=0) && (strncmp(filename, "_headers_", 9) !=0) && (strcmp(filename, ".") !=0) && (strcmp(filename, "..") != 0)) {
			if(lstat(filename, &statbuf) == -1) {
				errlog(__FILE__, __LINE__, errno);
				return -1;
			}
			if(!S_ISDIR(statbuf.st_mode)) {
				i = 0;
				while((i < 256) && (strlen(attach_list[i]) > 0)) {
					memset(str, 0, sizeof(str));
					if(strlen(attach_list[i]) <= strlen(direntp->d_name)) {
						/* Compare tails */
						for(j=0;j<strlen(attach_list[i]);j++)
							str[j] = filename[strlen(filename)-strlen(attach_list[i]+j)];
						str[j] = '\0';
						if(strcasestr(str, attach_list[i])) {
							strncpy(spam_word, filename, sizeof(spam_word)-1);
							strncpy(rule_word, str, sizeof(rule_word)-1);
							return 1;
						}
					}
					i++;
				}
			}
		}
		memset(filename, 0, sizeof(filename));
	}

	closedir(dirp);

	return 0;
}

int load_attachlist()
{
	int i = 0;
	FILE *fd;
	char pattern[128];

	if((fd = fopen(ATTACHFILE, "r")) == NULL) {
		errlog(__FILE__, __LINE__, errno);
		return -1;
	}

	while((i < 128) && (!feof(fd))) {
		memset(pattern, 0, sizeof(pattern));
		if((fscanf(fd, "%127s", pattern) < 0 ) && (!feof(fd))) {
			errlog(__FILE__, __LINE__, errno);
			fclose(fd);
			return -1;
		}

		if(strlen(pattern) > 1) {
			strncpy(attach_list[i], pattern, sizeof(attach_list[i])-1);
			i++;
		}
	}

	fclose(fd);

	return 0;
}


rulelist *load_rulelist()
{
	int i;
	FILE *fd;
	rulelist *ll, *sp;
	char ruleline[256];

	memset(ruleline, 0, sizeof(ruleline));

	if((fd = fopen(RULEFILE, "r")) == NULL) {
		errlog(__FILE__, __LINE__, errno);
		return NULL;
	}

	if((ll = (rulelist *) malloc(sizeof(rulelist))) == NULL) {
		errlog(__FILE__, __LINE__, errno);
		fclose(fd);
		return NULL;
	}

	sp = ll;
	while((fgets(ruleline, sizeof(ruleline)-1, fd) != 0) && (!feof(fd))) {
		if(((ruleline[0] == 'b') || (ruleline[0] == 'h') || (ruleline[0] == 'a')) && (ruleline[1] == ':') && (strlen(ruleline) > 4)) {
			ll->attr = ruleline[0];

			for(i=0;i<strlen(ruleline)-2;i++) ll->ruleline[i] = ruleline[i+2];
			ll->ruleline[i-1] = '\0';
			
			ll->next = (rulelist *) malloc(sizeof(rulelist));
			ll = ll->next;
		}
		memset(ruleline, 0, sizeof(ruleline));
	}
	
	ll = NULL;

	fclose(fd);

	return sp;
}




syntax highlighted by Code2HTML, v. 0.9.1