/***************************************************************************
 *                                                                         *
 *   Zabit: Content and attachment filter for qmail.                       *
 *   Version 0.7.1                                                         *
 *   http://www.enderunix.org/zabit                                        *
 *                                                                         *
 *   Copyright (C) 2004 by N.Ersen SISECI                                  *
 *   siseci@enderunix.org                                                  *
 *                                                                         *
 *   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 <stdio.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <ctype.h>

#include "zabit.h"
#include "scan.h"
#include "log.h"
#include "attach.h"

extern int searchbinary;
extern int scanonly;
extern int donotlog;

int bnstrstr(char *src, char *dest, long ssize, int threshold)
{
	long i;
	long j;
	char c1;
	char c2;
	long count = 0;
	long bssize;

	bssize = ssize;
	if (bssize < strlen(dest))
		return 0;
	for (i = 0; i < bssize - strlen(dest) + 1; i++) {
		for (j = 0; j < strlen(dest); j++) {
			c1 = *(src + i + j);
			c2 = *(dest + j);
			if (caseinsensitive) {
				c1 = toupper(c1);
				c2 = toupper(c2);
			}
			if (c1 != c2) {
				i = i + j;
				break;
			} else {
				if (j == (strlen(dest) - 1)) {
					i = i + j;
					count++;
				}
#ifndef DEBUG
				/* this makes a bit faster  */
				if (count >= threshold)
					return threshold;
#endif
			}
		}
	}
#ifdef DEBUG
	if (count >= threshold)
		return count;
#endif
	return 0;
}

int scanmailfile(char *fname, char *workingdir)
{
	char filename[MAXFILENAMELEN * 2];

	if ((strlen(fname) > MAXFILENAMELEN)
	    || (strlen(workingdir) > MAXFILENAMELEN)) {
		printf("Long File name: %s/%s\n", workingdir, fname);
		return ERRORTMP;
	}
	snprintf(filename, 511, "%s/%s", workingdir, fname);
	return scanfile(filename);
}

int scanmaildir(char *dirname, int recursive)
{

	DIR *dirp;
	struct dirent *entp;
	char newdir[512];
	int fromfile;
	int fromdir;
	struct stat statbuf;

#ifdef DEBUG
	printf("Next Scan Dir: %s\n", dirname);
#endif

	dirp = opendir(dirname);
	if (dirp != NULL) {
		while ((entp = readdir(dirp)) != NULL) {
			if ((strcmp(entp->d_name, "."))
			    && (strcmp(entp->d_name, ".."))) {
				snprintf(newdir, 511, "%s/%s", dirname,
					 entp->d_name);
				if (stat(newdir, &statbuf)) {
					printf("%s: %s\n", strerror(errno),
					       newdir);
					return ERRORTMP;
				}
				if (S_ISREG(statbuf.st_mode)) {
#ifdef DEBUG
					printf("Content Scan: File: %s\n", entp->d_name);
#endif
					fromfile =
					    scanmailfile(entp->d_name, dirname);
					if (fromfile)
						return SPAMMAIL;
				}

				if (S_ISDIR(statbuf.st_mode) && recursive) {
#ifdef DEBUG
					printf("Content Scan: Dir: %s\n", entp->d_name);
#endif
					fromdir =
					    scanmaildir(newdir, recursive);
					if (fromdir)
						return SPAMMAIL;
				}
			}
		}		/* while */
		closedir(dirp);
	} else {
		printf("Can not open DIR: %s\n", dirname);
		return ERRORTMP;
	}
	return 0;

}

int scanfile(char *filename)
{
	char bigbuf[BIGBUFSIZE];
	int gecen;
	int mailfile;
	int i;
	long ssize;
	long bssize;
	struct tm *ptr;
	time_t tm;
	char timestr[32];

	memset(bigbuf, 0, BIGBUFSIZE);
	if (checkdisablefilename(filename) == 0) return 0;
	if ((mailfile = open(filename, O_RDONLY)) != -1) {
		i = read(mailfile, bigbuf, BIGBUFSIZE);
		ssize = i;
		if (ssize > 0) {
			if (searchbinary)
				bssize = ssize;
			else
				bssize = strlen(bigbuf);

			for (i = 0; i < entrycount; i++) {
				gecen =
				    bnstrstr(bigbuf, wordlist[i].word, bssize,
					     wordlist[i].count);
				if (gecen >= wordlist[i].count) {
					tm = time(NULL);
					ptr = localtime(&tm);
					snprintf(timestr, 31, "%s", asctime(ptr));
					timestr[strlen(timestr) - 1] = 0;

#ifndef DEBUG
					snprintf(log_buffer, LOGBUFFERSIZE + 32,
						 "%s Word '%s' Found. File: %s . Mail Rejected\n",
						 timestr, wordlist[i].word,
						 filename);
#else
					snprintf(log_buffer, LOGBUFFERSIZE + 32,
						 "%s Word '%s' Found. File: %s : Count: %d Mail Rejected.\n",
						 timestr, wordlist[i].word,
						 filename, gecen);
#endif
					printf("%s", log_buffer);
					if (donotlog == 0)
						write_log(log_buffer);
					if (scanonly == 0)
						return SPAMMAIL;
					else
						return 0;
				}

			}
		}
		close(mailfile);
	} else {
		printf("Can't Open: %s\n", filename);
		return ERRORTMP;
	}
	return 0;

}



int scandirfilenames(char *dirname, int recursive)
{

        DIR *dirp;
        struct dirent *entp;
        char newdir[512];
        int fromfile;
        int fromdir;
        struct stat statbuf;

#ifdef DEBUG
        printf("Next Scan Dir: %s\n", dirname);
#endif

        dirp = opendir(dirname);
        if (dirp != NULL) {
                while ((entp = readdir(dirp)) != NULL) {
                        if ((strcmp(entp->d_name, "."))
                            && (strcmp(entp->d_name, ".."))) {
                                snprintf(newdir, 511, "%s/%s", dirname,
                                         entp->d_name);
                                if (stat(newdir, &statbuf)) {
                                        printf("%s: %s\n", strerror(errno), newdir);
                                        return ERRORTMP;
                                }
                                if (S_ISREG(statbuf.st_mode)) {
#ifdef DEBUG
                                        printf("File Name Scan: File: %s\n", entp->d_name);
#endif
                                        fromfile = checkfilename(entp->d_name);
                                        if (fromfile)
                                                return SPAMMAIL;
                                }

                               if (S_ISDIR(statbuf.st_mode) && recursive) {
#ifdef DEBUG
                                        printf("File Name Scan: Dir: %s\n", entp->d_name);
#endif
                                        fromdir = scandirfilenames(newdir, recursive);
                                        if (fromdir)
                                                return SPAMMAIL;
                                }
                        }
                }               /* while */
                closedir(dirp);
        } else {
                printf("Can not open DIR: %s\n", dirname);
                return ERRORTMP;
        }
        return 0;

}




syntax highlighted by Code2HTML, v. 0.9.1