summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile102
-rw-r--r--src/config.c715
-rw-r--r--src/config.h80
-rw-r--r--src/dbase.c281
-rw-r--r--src/dbase.h86
-rw-r--r--src/dstring.c111
-rw-r--r--src/dstring.h86
-rw-r--r--src/global.h44
-rw-r--r--src/kbs.c147
-rw-r--r--src/kbsrc91
-rw-r--r--src/msg.h45
-rw-r--r--src/pop3.c530
-rw-r--r--src/pop3.h90
-rw-r--r--src/rexp.c63
-rw-r--r--src/rexp.h52
-rw-r--r--src/util.c79
-rw-r--r--src/util.h58
17 files changed, 2660 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..22cc523
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,102 @@
+# kbs - Simple, easily fooled, POP3 spam filter
+#
+# Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+#
+# 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
+#
+# -------------------------------------------------------------------------
+#
+# $Id: Makefile,v 1.1.1.1 2003-12-04 01:54:55 ianc Exp $
+#
+
+CFLAGS += -g
+
+TARGET = kbs
+
+SOURCE = kbs.c \
+ pop3.c \
+ config.c \
+ rexp.c \
+ dbase.c \
+ dstring.c \
+ util.c
+
+OBJECTS = kbs.o \
+ pop3.o \
+ config.o \
+ rexp.o \
+ dbase.o \
+ dstring.o \
+ util.o
+
+$(TARGET): $(OBJECTS)
+ $(CC) $(CLAGS) -o $(TARGET) $(OBJECTS)
+
+clean:
+ rm -f $(TARGET) $(OBJECTS) core
+
+depend:
+ make clean
+ makedepend -- $(CFLAGS) -- $(SOURCE)
+ if test -e Makefile ; then rm -f Makefile.bak ; fi
+
+# DO NOT DELETE THIS LINE -- make depend depends on it
+
+kbs.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+kbs.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+kbs.o: /usr/include/limits.h /usr/include/sys/limits.h
+kbs.o: /usr/include/machine/_limits.h /usr/include/sys/syslimits.h
+kbs.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+kbs.o: /usr/include/stdarg.h /usr/include/time.h /usr/include/sys/timespec.h
+kbs.o: /usr/include/errno.h global.h config.h pop3.h msg.h rexp.h util.h
+pop3.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+pop3.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+pop3.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h
+pop3.o: /usr/include/stdarg.h /usr/include/ctype.h /usr/include/runetype.h
+pop3.o: /usr/include/sys/types.h /usr/include/machine/endian.h
+pop3.o: /usr/include/sys/select.h /usr/include/sys/_sigset.h
+pop3.o: /usr/include/sys/_timeval.h /usr/include/sys/timespec.h
+pop3.o: /usr/include/sys/socket.h /usr/include/sys/_iovec.h
+pop3.o: /usr/include/machine/param.h /usr/include/netinet/in.h
+pop3.o: /usr/include/netinet6/in6.h /usr/include/netinet/tcp.h
+pop3.o: /usr/include/netdb.h global.h pop3.h msg.h dstring.h util.h
+config.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+config.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+config.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h
+config.o: /usr/include/errno.h /usr/include/ctype.h /usr/include/runetype.h
+config.o: global.h config.h dstring.h dbase.h msg.h rexp.h util.h
+rexp.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+rexp.o: /usr/include/sys/_types.h /usr/include/machine/_types.h global.h
+rexp.o: rexp.h
+dbase.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+dbase.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+dbase.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h
+dbase.o: /usr/include/ctype.h /usr/include/runetype.h global.h dbase.h msg.h
+dbase.o: dstring.h config.h rexp.h util.h
+dstring.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+dstring.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+dstring.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h
+dstring.o: /usr/include/stdarg.h /usr/include/ctype.h /usr/include/runetype.h
+dstring.o: /usr/include/sys/types.h /usr/include/machine/endian.h
+dstring.o: /usr/include/sys/select.h /usr/include/sys/_sigset.h
+dstring.o: /usr/include/sys/_timeval.h /usr/include/sys/timespec.h
+dstring.o: /usr/include/sys/socket.h /usr/include/sys/_iovec.h
+dstring.o: /usr/include/machine/param.h /usr/include/netinet/in.h
+dstring.o: /usr/include/netinet6/in6.h /usr/include/netinet/tcp.h
+dstring.o: /usr/include/netdb.h global.h dstring.h util.h
+util.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
+util.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+util.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h
+util.o: global.h util.h
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..af55d58
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,715 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Config
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "global.h"
+#include "config.h"
+#include "dstring.h"
+#include "dbase.h"
+#include "rexp.h"
+#include "util.h"
+
+
+/* ---------------------------------------- TYPES
+*/
+typedef enum {
+ TOK_Expression,
+ TOK_Set,
+ TOK_OpenBracket,
+ TOK_CloseBracket,
+ TOK_Domain,
+ TOK_TrustedUsers,
+ TOK_TrustedDomains,
+ TOK_Default,
+ TOK_BlockUser,
+ TOK_AllowSubject,
+ TOK_BlockSubject,
+ TOK_VarHostname,
+ TOK_VarPort,
+ TOK_VarUsername,
+ TOK_VarPassword,
+ TOK_VarLog,
+ TOK_VarTimeout,
+ TOK_VarCasesense,
+ TOK_VarDejunk,
+ TOK_VarTestmode,
+ TOK_VarBlockHTML,
+ TOK_VarDeletelog,
+ TOK_ConstOn,
+ TOK_ConstOff,
+ TOK_ConstBlock,
+ TOK_ConstAllow,
+ TOK_EOF
+ } Token;
+
+typedef struct Command
+ {
+ const char *cmd;
+ Token token;
+ } Command;
+
+
+/* ---------------------------------------- GLOBALS
+*/
+static DString error;
+static char *hostname="localhost";
+static char *username="nobody";
+static char *password="";
+static char *log="";
+static char *deletelog="";
+static int port=110;
+static int timeout=60;
+static int casesense=FALSE;
+static int dejunk=FALSE;
+static int testmode=FALSE;
+static int blockhtml=FALSE;
+
+
+/* ---------------------------------------- COMMAND TABLE
+*/
+static const Command cmd_table[]=
+ {
+ /* Commands and main tokens
+ */
+ {"set", TOK_Set},
+ {"trusted_users", TOK_TrustedUsers},
+ {"trusted_domains", TOK_TrustedDomains},
+ {"{", TOK_OpenBracket},
+ {"}", TOK_CloseBracket},
+ {"domain", TOK_Domain},
+ {"default", TOK_Default},
+ {"block_user", TOK_BlockUser},
+ {"allow_subject", TOK_AllowSubject},
+ {"block_subject", TOK_BlockSubject},
+
+ /* Variables
+ */
+ {"hostname", TOK_VarHostname},
+ {"port", TOK_VarPort},
+ {"username", TOK_VarUsername},
+ {"password", TOK_VarPassword},
+ {"log", TOK_VarLog},
+ {"timeout", TOK_VarTimeout},
+ {"casesense", TOK_VarCasesense},
+ {"dejunk", TOK_VarDejunk},
+ {"testmode", TOK_VarTestmode},
+ {"blockhtml", TOK_VarBlockHTML},
+
+ /* Constants
+ */
+ {"on", TOK_ConstOn},
+ {"off", TOK_ConstOff},
+ {"block", TOK_ConstBlock},
+ {"allow", TOK_ConstAllow},
+
+ /* End of table
+ */
+ {NULL, TOK_EOF}
+ };
+
+
+/* ---------------------------------------- REQUIRED PROTOS
+*/
+static Token GetToken(FILE *fp, DString ret);
+
+
+/* ---------------------------------------- COMMAND HANDLERS
+*/
+static int DoSet(FILE *fp)
+{
+# define TYPE_STR 0
+# define TYPE_INT 1
+# define TYPE_ONOFF 2
+
+ static const struct VarTable
+ {
+ Token token;
+ int type;
+ void *ptr;
+ } var_table[]=
+ {
+ {TOK_VarHostname, TYPE_STR, (void *)&hostname},
+ {TOK_VarPort, TYPE_INT, (void *)&port},
+ {TOK_VarUsername, TYPE_STR, (void *)&username},
+ {TOK_VarPassword, TYPE_STR, (void *)&password},
+ {TOK_VarLog, TYPE_STR, (void *)&log},
+ {TOK_VarTimeout, TYPE_INT, (void *)&timeout},
+ {TOK_VarCasesense, TYPE_ONOFF, (void *)&casesense},
+ {TOK_VarDejunk, TYPE_ONOFF, (void *)&dejunk},
+ {TOK_VarTestmode, TYPE_ONOFF, (void *)&testmode},
+ {TOK_VarBlockHTML, TYPE_ONOFF, (void *)&blockhtml},
+ {TOK_VarDeletelog, TYPE_STR, (void *)&deletelog},
+ {TOK_EOF,0,NULL}
+ };
+
+ const struct VarTable *vt=NULL;
+ DString ds;
+ Token tok;
+ int status=TRUE;
+ int f;
+
+ ds=DSInit();
+
+ tok=GetToken(fp,ds);
+
+ for(f=0;var_table[f].token!=TOK_EOF && !vt;f++)
+ if (var_table[f].token==tok)
+ vt=var_table+f;
+
+ if (vt)
+ {
+ char **cp;
+ int *ip;
+
+ switch(vt->type)
+ {
+ case TYPE_STR:
+ cp=vt->ptr;
+ tok=GetToken(fp,ds);
+ *cp=CopyStr(ds->text);
+ break;
+
+ case TYPE_INT:
+ ip=vt->ptr;
+ tok=GetToken(fp,ds);
+ *ip=atoi(ds->text);
+ break;
+
+ case TYPE_ONOFF:
+ ip=vt->ptr;
+ tok=GetToken(fp,ds);
+
+ switch(tok)
+ {
+ case TOK_ConstOn:
+ *ip=TRUE;
+ break;
+
+ case TOK_ConstOff:
+ *ip=FALSE;
+ break;
+
+ default:
+ status=FALSE;
+ DSAddCP(error,"Expected on/off. Got: ");
+ DSAddDS(error,ds);
+ }
+ break;
+ }
+ }
+ else
+ {
+ status=FALSE;
+ DSAddCP(error,"Unrecognised variable: ");
+ DSAddDS(error,ds);
+ }
+
+ DSFree(ds);
+
+# undef TYPE_STR
+# undef TYPE_INT
+# undef TYPE_ONOFF
+
+ return status;
+}
+
+
+static int DoDomain(FILE *fp)
+{
+ DString ds;
+ Token tok;
+ int status=TRUE;
+ Domain *domain;
+
+ ds=DSInit();
+
+ tok=GetToken(fp,ds);
+
+ if (tok!=TOK_Expression)
+ {
+ DSAddCP(error,"Domain must be followed by expression. Got: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ }
+
+ if (RExpSearch(ds->text,"dummy")==RE_BadExpression)
+ {
+ DSAddCP(error,"Bad regular expression: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ }
+
+ domain=DBNewDomain(ds->text);
+
+ tok=GetToken(fp,ds);
+
+ if (tok!=TOK_OpenBracket)
+ {
+ DSAddCP(error,"Missing opening bracket in domain");
+ DSFree(ds);
+ return FALSE;
+ }
+
+ while((tok=GetToken(fp,ds))!=TOK_CloseBracket)
+ {
+ if (tok==TOK_EOF)
+ {
+ DSAddCP(error,"Missing close bracket in domain");
+ DSFree(ds);
+ return FALSE;
+ }
+
+ switch(tok)
+ {
+ case TOK_Default:
+ switch(GetToken(fp,ds))
+ {
+ case TOK_ConstAllow:
+ DBDefault(domain,FALSE);
+ break;
+
+ case TOK_ConstBlock:
+ DBDefault(domain,TRUE);
+ break;
+
+ default:
+ DSAddCP(error,"Unexpected value in default command: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ break;
+ }
+
+ break;
+
+ case TOK_BlockUser:
+ GetToken(fp,ds);
+ DBBlockUser(domain,ds->text);
+ break;
+
+ case TOK_AllowSubject:
+ GetToken(fp,ds);
+
+ if (RExpSearch(ds->text,"dummy")==RE_BadExpression)
+ {
+ DSAddCP(error,"Bad regular expression: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ }
+
+ DBAllowSubject(domain,ds->text);
+ break;
+
+ case TOK_BlockSubject:
+ GetToken(fp,ds);
+
+ if (RExpSearch(ds->text,"dummy")==RE_BadExpression)
+ {
+ DSAddCP(error,"Bad regular expression: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ }
+
+ DBBlockSubject(domain,ds->text);
+ break;
+
+ default:
+ DSAddCP(error,"Unexpected string in domain command: ");
+ DSAddDS(error,ds);
+ DSFree(ds);
+ return FALSE;
+ break;
+ }
+ }
+
+ DSFree(ds);
+
+ return TRUE;
+}
+
+
+static int DoTrustedUsers(FILE *fp)
+{
+ DString ds;
+ Token tok;
+ int status=TRUE;
+
+ ds=DSInit();
+
+ tok=GetToken(fp,ds);
+
+ if (tok!=TOK_OpenBracket)
+ {
+ DSAddCP(error,"Missing opening bracket in trusted_users");
+ DSFree(ds);
+ return FALSE;
+ }
+
+ while((tok=GetToken(fp,ds))!=TOK_CloseBracket)
+ {
+ if (tok==TOK_EOF)
+ {
+ DSAddCP(error,"Missing close bracket in trusted_users");
+ DSFree(ds);
+ return FALSE;
+ }
+
+ DBTrustedUser(ds->text);
+ }
+
+ DSFree(ds);
+
+ return TRUE;
+}
+
+
+static int DoTrustedDomains(FILE *fp)
+{
+ DString ds;
+ Token tok;
+ int status=TRUE;
+
+ ds=DSInit();
+
+ tok=GetToken(fp,ds);
+
+ if (tok!=TOK_OpenBracket)
+ {
+ DSAddCP(error,"Missing opening bracket in trusted_domains");
+ return FALSE;
+ }
+
+ while((tok=GetToken(fp,ds))!=TOK_CloseBracket)
+ {
+ if (tok==TOK_EOF)
+ {
+ DSAddCP(error,"Missing close bracket in trusted_domains");
+ return FALSE;
+ }
+
+ DBTrustedDomain(ds->text);
+ }
+
+ return TRUE;
+}
+
+
+/* ---------------------------------------- PRVIVATE FUNCTIONS
+*/
+static int Getc(FILE *fp)
+{
+ int ch;
+
+ ch=fgetc(fp);
+
+ if (ch=='#')
+ {
+ ch=fgetc(fp);
+
+ while(ch!=EOF && ch!='\n')
+ ch=fgetc(fp);
+ }
+
+ return ch;
+}
+
+
+static int SkipWS(FILE *fp)
+{
+ int ch;
+
+ ch=Getc(fp);
+
+ while(isspace(ch))
+ ch=Getc(fp);
+
+ if (ch==EOF)
+ return FALSE;
+ else
+ {
+ ungetc(ch,fp);
+ return TRUE;
+ }
+}
+
+
+static Token FindToken(const char *p)
+{
+ int f;
+
+ for(f=0;cmd_table[f].cmd;f++)
+ if (strcmp(cmd_table[f].cmd,p)==0)
+ return cmd_table[f].token;
+
+ return TOK_Expression;
+}
+
+
+static int IsTerm(int ch)
+{
+ return isspace(ch) || ch=='#';
+}
+
+
+static Token GetToken(FILE *fp, DString ret)
+{
+ int ch;
+ int done=FALSE;
+ int quote=0;
+ Token tok;
+
+ ret=DSReset(ret);
+
+ if (feof(fp))
+ {
+ DSAddCP(ret,"EOF");
+ return TOK_EOF;
+ }
+
+ if (!SkipWS(fp))
+ {
+ DSAddCP(ret,"EOF");
+ return TOK_EOF;
+ }
+
+ while(!done)
+ {
+ ch=fgetc(fp);
+
+ if (quote)
+ {
+ if (ch==EOF)
+ {
+ done=TRUE;
+
+ DSAddCP(error,"Unexpected EOF in string");
+ tok=TOK_EOF;
+ }
+ else if (ch==quote)
+ {
+ done=TRUE;
+ tok=FindToken(ret->text);
+ }
+ else
+ {
+ DSAddChar(ret,ch);
+ }
+ }
+ else
+ {
+ if (ch==EOF)
+ {
+ done=TRUE;
+
+ if (ret->len)
+ tok=FindToken(ret->text);
+ else
+ tok=TOK_EOF;
+ }
+ else if (IsTerm(ch))
+ {
+ ungetc(ch,fp);
+ done=TRUE;
+ tok=FindToken(ret->text);
+ }
+ else if (ch=='\'' || ch=='"')
+ {
+ quote=ch;
+ }
+ else
+ {
+ DSAddChar(ret,ch);
+ }
+ }
+ }
+
+ return tok;
+}
+
+
+static int Parse(FILE *fp)
+{
+ DString txt;
+ Token tok;
+ char *p;
+
+ txt=DSInit();
+
+ while((tok=GetToken(fp,txt))!=TOK_EOF)
+ {
+ int ok=TRUE;
+
+ switch(tok)
+ {
+ case TOK_Set:
+ if (!DoSet(fp))
+ ok=FALSE;
+ break;
+
+ case TOK_Domain:
+ if (!DoDomain(fp))
+ ok=FALSE;
+ break;
+
+ case TOK_TrustedUsers:
+ if (!DoTrustedUsers(fp))
+ ok=FALSE;
+ break;
+
+ case TOK_TrustedDomains:
+ if (!DoTrustedDomains(fp))
+ ok=FALSE;
+ break;
+
+ case TOK_Expression:
+ DSAddCP(error,"Unknown command in config file: ");
+ DSAddDS(error,txt);
+ ok=FALSE;
+ break;
+
+ default:
+ DSAddCP(error,"Unexpected token in config file: ");
+ DSAddDS(error,txt);
+ ok=FALSE;
+ break;
+ }
+
+ if (!ok)
+ break;
+
+ txt=DSReset(txt);
+ }
+
+ DSFree(txt);
+
+ return error->len==0;
+}
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+int ConfigLoad(void)
+{
+ DString ds;
+ FILE *fp;
+ int ret;
+
+ error=DSInit();
+
+ if (!getenv("HOME"))
+ return FALSE;
+
+ ds=DSInit();
+
+ DSAddCP(ds,getenv("HOME"));
+ DSAddChar(ds,'/');
+ DSAddCP(ds,".kbsrc");
+
+ if ((fp=fopen(ds->text,"r")))
+ ret=Parse(fp);
+ else
+ ret=FALSE;
+
+ DSFree(ds);
+
+ return ret;
+}
+
+
+const char *ConfigError(void)
+{
+ if (strlen(error->text))
+ return error->text;
+ else
+ return strerror(errno);
+}
+
+
+const char *ConfigString(ConfigStringVar var)
+{
+ switch(var)
+ {
+ case CONFIG_HOSTNAME:
+ return hostname;
+
+ case CONFIG_USERNAME:
+ return username;
+
+ case CONFIG_PASSWORD:
+ return password;
+
+ case CONFIG_LOG:
+ return log;
+
+ case CONFIG_DELETE_LOG:
+ return deletelog;
+
+ default:
+ return "";
+ }
+}
+
+
+int ConfigInt(ConfigIntVar var)
+{
+ switch(var)
+ {
+ case CONFIG_PORT:
+ return port;
+
+ case CONFIG_TIMEOUT:
+ return timeout;
+
+ case CONFIG_CASESENSE:
+ return casesense;
+
+ case CONFIG_DEJUNK:
+ return dejunk;
+
+ case CONFIG_TESTMODE:
+ return testmode;
+
+ case CONFIG_BLOCKHTML:
+ return blockhtml;
+
+ default:
+ return 0;
+ }
+}
+
+
+/* END OF FILE */
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..a2ddc78
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,80 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Config file.
+
+*/
+
+#ifndef KBS_CONFIG_H
+#define KBS_CONFIG_H
+
+
+/* ---------------------------------------- VARIABLE NAMES
+*/
+
+/* char* variables
+*/
+typedef enum
+ {
+ CONFIG_HOSTNAME,
+ CONFIG_USERNAME,
+ CONFIG_PASSWORD,
+ CONFIG_LOG,
+ CONFIG_DELETE_LOG
+ } ConfigStringVar;
+
+
+/* int/boolean variables
+*/
+typedef enum
+ {
+ CONFIG_PORT,
+ CONFIG_TIMEOUT,
+ CONFIG_CASESENSE,
+ CONFIG_DEJUNK,
+ CONFIG_TESTMODE,
+ CONFIG_BLOCKHTML
+ } ConfigIntVar;
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Loads in config file. Returns FALSE for problems.
+*/
+int ConfigLoad(void);
+
+
+/* Returns a reason for config load failure
+*/
+const char *ConfigError(void);
+
+
+/* Query interfaces for variables
+*/
+const char *ConfigString(ConfigStringVar var);
+int ConfigInt(ConfigIntVar var);
+
+#endif
+
+/* END OF FILE */
diff --git a/src/dbase.c b/src/dbase.c
new file mode 100644
index 0000000..5eca1a9
--- /dev/null
+++ b/src/dbase.c
@@ -0,0 +1,281 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Rules database
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "global.h"
+#include "dbase.h"
+#include "dstring.h"
+#include "config.h"
+#include "rexp.h"
+#include "util.h"
+
+
+/* ---------------------------------------- TYPES
+*/
+struct Domain
+ {
+ char *name;
+ int def_block;
+ int no_user;
+ int no_block;
+ int no_allow;
+ char **user;
+ char **block;
+ char **allow;
+ Domain *next;
+ Domain *prev;
+ };
+
+
+/* ---------------------------------------- GLOBALS
+*/
+static Domain *head;
+static Domain *tail;
+
+static int no_trusted_users=0;
+static int no_trusted_domains=0;
+
+static char **trusted_user=NULL;
+static char **trusted_domain=NULL;
+
+
+/* ---------------------------------------- PRVIVATE FUNCTIONS
+*/
+static int IsTrustedUser(const char *username)
+{
+ int f;
+
+ for(f=0;f<no_trusted_users;f++)
+ {
+ if (strcasecmp(username,trusted_user[f])==0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static int IsTrustedDomain(const char *domain)
+{
+ int f;
+
+ for(f=0;f<no_trusted_domains;f++)
+ {
+ if (strcasecmp(domain,trusted_domain[f])==0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static const Domain *GetDomain(const char *domain)
+{
+ Domain *dom;
+
+ dom=head;
+
+ while(dom)
+ {
+ if (RExpSearch(dom->name,domain)==RE_Found)
+ return dom;
+
+ dom=dom->next;
+ }
+
+ return NULL;
+}
+
+
+static void DeJunk(DString ds, const char *p)
+{
+ int last_ws=FALSE;
+
+ while(*p)
+ {
+ if (isspace(*p))
+ {
+ if (!last_ws)
+ DSAddChar(ds,' ');
+
+ last_ws=TRUE;
+ }
+ else
+ last_ws=FALSE;
+
+ if (isalnum(*p))
+ {
+ DSAddChar(ds,*p);
+ }
+
+ p++;
+ }
+}
+
+
+/* ---------------------------------------- INTERFACES
+*/
+Domain *DBNewDomain(const char *regexp)
+{
+ Domain *dom;
+
+ dom=Malloc(sizeof *dom);
+
+ dom->name=CopyStr(regexp);
+ dom->def_block=FALSE;
+
+ dom->no_user=0;
+ dom->no_block=0;
+ dom->no_allow=0;
+
+ dom->user=NULL;
+ dom->block=NULL;
+ dom->allow=NULL;
+
+ if (tail)
+ tail->next=dom;
+ else
+ head=tail=dom;
+
+ dom->prev=tail;
+ dom->next=NULL;
+
+ return dom;
+}
+
+
+void DBDefault(Domain *domain, int block)
+{
+ domain->def_block=block;
+}
+
+
+void DBBlockUser(Domain *domain, const char *username)
+{
+ domain->no_user++;
+ domain->user=Realloc(domain->user,sizeof(char *)*domain->no_user);
+ domain->user[domain->no_user-1]=CopyStr(username);
+}
+
+
+void DBAllowSubject(Domain *domain, const char *regexp)
+{
+ domain->no_allow++;
+ domain->allow=Realloc(domain->allow,sizeof(char *)*domain->no_allow);
+ domain->allow[domain->no_allow-1]=CopyStr(regexp);
+}
+
+
+void DBBlockSubject(Domain *domain, const char *regexp)
+{
+ domain->no_block++;
+ domain->block=Realloc(domain->block,sizeof(char *)*domain->no_block);
+ domain->block[domain->no_block-1]=CopyStr(regexp);
+}
+
+
+void DBTrustedUser(const char *username)
+{
+ no_trusted_users++;
+ trusted_user=Realloc(trusted_user,sizeof(char *)*no_trusted_users);
+ trusted_user[no_trusted_users-1]=CopyStr(username);
+}
+
+
+void DBTrustedDomain(const char *domain)
+{
+ no_trusted_domains++;
+ trusted_domain=Realloc(trusted_domain,sizeof(char *)*no_trusted_domains);
+ trusted_domain[no_trusted_domains-1]=CopyStr(domain);
+}
+
+
+int DBBlockMessage(const POP3Message *msg)
+{
+ DString ds;
+ const Domain *dom;
+ int f;
+
+ if (IsTrustedDomain(msg->from_domain))
+ return FALSE;
+
+ if (IsTrustedUser(msg->from_uname))
+ return FALSE;
+
+ if (!(dom=GetDomain(msg->from_domain)))
+ return FALSE;
+
+ for(f=0;f<dom->no_user;f++)
+ {
+ if (ConfigInt(CONFIG_CASESENSE))
+ {
+ if (strcmp(dom->user[f],msg->from_uname)==0)
+ return TRUE;
+ }
+ else
+ {
+ if (strcasecmp(dom->user[f],msg->from_uname)==0)
+ return TRUE;
+ }
+ }
+
+ ds=DSInit();
+
+ if (ConfigInt(CONFIG_DEJUNK))
+ DeJunk(ds,msg->subject);
+ else
+ DSAddCP(ds,msg->subject);
+
+ for(f=0;f<dom->no_allow;f++)
+ {
+ if (RExpSearch(dom->allow[f],ds->text)==RE_Found)
+ {
+ DSFree(ds);
+ return FALSE;
+ }
+ }
+
+ for(f=0;f<dom->no_block;f++)
+ {
+ if (RExpSearch(dom->block[f],ds->text)==RE_Found)
+ {
+ DSFree(ds);
+ return TRUE;
+ }
+ }
+
+ DSFree(ds);
+ return dom->def_block;
+}
+
+
+/* END OF FILE */
diff --git a/src/dbase.h b/src/dbase.h
new file mode 100644
index 0000000..df64927
--- /dev/null
+++ b/src/dbase.h
@@ -0,0 +1,86 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Rules database
+
+*/
+
+#ifndef KBS_DBASE_H
+#define KBS_DBASE_H
+
+#include "msg.h"
+
+/* ---------------------------------------- TYPES
+*/
+struct Domain;
+
+typedef struct Domain Domain;
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Add a new domain and define the regular expression that defines it
+*/
+Domain *DBNewDomain(const char *regexp);
+
+
+/* Define the default mode for a domain
+*/
+void DBDefault(Domain *domain, int block);
+
+
+/* Adds a disallowed username for a domain
+*/
+void DBBlockUser(Domain *domain, const char *username);
+
+
+/* Add an allowable subject for a domain
+*/
+void DBAllowSubject(Domain *domain, const char *regexp);
+
+
+/* Adds a disallowed subject for a domain
+*/
+void DBBlockSubject(Domain *domain, const char *regexp);
+
+
+/* Adds a trusted username
+*/
+void DBTrustedUser(const char *username);
+
+
+/* Adds a trusted domain
+*/
+void DBTrustedDomain(const char *domain);
+
+
+/* Returns TRUE if message is to be blocked
+*/
+int DBBlockMessage(const POP3Message *msg);
+
+
+#endif
+
+/* END OF FILE */
diff --git a/src/dstring.c b/src/dstring.c
new file mode 100644
index 0000000..e614e83
--- /dev/null
+++ b/src/dstring.c
@@ -0,0 +1,111 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Dynamic strings
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+
+#include "global.h"
+#include "dstring.h"
+#include "util.h"
+
+
+/* ---------------------------------------- CONSTANTS
+*/
+#define BLOCKSIZE 512
+
+
+/* ---------------------------------------- INTERFACES
+*/
+DString DSInit(void)
+{
+ DString ds;
+
+ ds=Malloc(sizeof *ds);
+
+ ds->len=0;
+ ds->text=Malloc(BLOCKSIZE);
+ ds->text[0]=0;
+
+ return ds;
+}
+
+
+void DSFree(DString ds)
+{
+ free(ds->text);
+ free(ds);
+}
+
+
+DString DSReset(DString ds)
+{
+ DSFree(ds);
+ return DSInit();
+}
+
+
+DString DSAddChar(DString to, char c)
+{
+ if (((to->len+2)%BLOCKSIZE)==0)
+ {
+ to->text=Realloc(to->text,(((to->len+2)/BLOCKSIZE)+1)*BLOCKSIZE);
+ }
+
+ to->text[to->len++]=c;
+ to->text[to->len]=0;
+}
+
+
+DString DSAddCP(DString to, const char *from)
+{
+ to->len+=strlen(from);
+ to->text=Realloc(to->text,(((to->len+1)/BLOCKSIZE)+1)*BLOCKSIZE);
+
+ strcat(to->text,from);
+}
+
+
+DString DSAddDS(DString to, const DString from)
+{
+ to->len+=from->len;
+ to->text=Realloc(to->text,(((to->len+1)/BLOCKSIZE)+1)*BLOCKSIZE);
+
+ strcat(to->text,from->text);
+}
+
+
+/* END OF FILE */
diff --git a/src/dstring.h b/src/dstring.h
new file mode 100644
index 0000000..db6454f
--- /dev/null
+++ b/src/dstring.h
@@ -0,0 +1,86 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Dynamic strings
+
+*/
+
+#ifndef KBS_DSTRING_H
+#define KBS_DSTRING_H
+
+/* ---------------------------------------- TYPES
+*/
+typedef struct
+ {
+ size_t len;
+ char *text;
+ } *DString;
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Sets a DString up for use. Note when reusing the same DString, remember
+ to call DSReset() and get the return.
+
+ Returns the new DString.
+*/
+DString DSInit();
+
+
+/* Frees a DString.
+*/
+void DSFree(DString ds);
+
+
+/* Resets a string. Basically calls DSFree() then DSInit().
+
+ Returns the parameter.
+*/
+DString DSReset(DString ds);
+
+
+/* Adds a character onto a DString.
+
+ Returns the passed DString.
+*/
+DString DSAddChar(DString to, char c);
+
+
+/* Adds a nul-terminated char pointer onto a DString.
+
+ Returns the passed DString.
+*/
+DString DSAddCP(DString to, const char *p);
+
+
+/* Adds another DString.
+
+ Returns the passed to DString.
+*/
+DString DSAddDS(DString to, const DString from);
+
+
+#endif
+
+/* END OF FILE */
diff --git a/src/global.h b/src/global.h
new file mode 100644
index 0000000..6fcfe52
--- /dev/null
+++ b/src/global.h
@@ -0,0 +1,44 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Global include
+
+*/
+
+#ifndef KBS_GLOBAL_H
+#define KBS_GLOBAL_H
+
+/* ---------------------------------------- MACROS
+*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#endif
+
+/* END OF FILE */
diff --git a/src/kbs.c b/src/kbs.c
new file mode 100644
index 0000000..25afe5f
--- /dev/null
+++ b/src/kbs.c
@@ -0,0 +1,147 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+
+#include "global.h"
+#include "config.h"
+#include "pop3.h"
+#include "dbase.h"
+#include "util.h"
+
+/* ---------------------------------------- MACROS
+*/
+#define LOG (logfp ? logfp:stderr)
+
+
+/* ---------------------------------------- TYPES
+*/
+
+
+/* ---------------------------------------- GLOBALS
+*/
+static const char *name=NULL;
+static FILE *logfp=NULL;
+
+
+/* ---------------------------------------- PROTOS
+*/
+
+
+/* ---------------------------------------- MAIN
+*/
+int main(int argc, char *argv[])
+{
+ POP3Message *msg;
+
+ if (strchr(argv[0],'/'))
+ name=strchr(argv[0],'/')+1;
+ else
+ name=argv[0];
+
+ if (!ConfigLoad())
+ {
+ fprintf(stderr,"%s\n",ConfigError());
+ exit(EXIT_FAILURE);
+ }
+
+ switch(POP3Connect(ConfigString(CONFIG_HOSTNAME),
+ ConfigInt(CONFIG_PORT),
+ ConfigString(CONFIG_USERNAME),
+ ConfigString(CONFIG_PASSWORD),
+ ConfigInt(CONFIG_TIMEOUT)))
+ {
+ case POP3_OK:
+ break;
+
+ case POP3_COMMERROR:
+ fprintf(LOG,"Comms error (errno = %d)\n",errno);
+ exit(EXIT_FAILURE);
+ break;
+
+ case POP3_NOCONNECT:
+ fprintf(LOG,"No connection to host (errno = %d)\n",errno);
+ exit(EXIT_FAILURE);
+ break;
+
+ case POP3_BADUSER:
+ fprintf(LOG,"Bad username\n");
+ exit(EXIT_FAILURE);
+ break;
+
+ case POP3_BADPASSWD:
+ fprintf(LOG,"Bad password\n");
+ exit(EXIT_FAILURE);
+ break;
+
+ default:
+ break;
+ }
+
+ if ((msg=POP3GetList()))
+ {
+ int f;
+ int tot=0;
+ int block=0;
+
+ for(f=0;msg[f].to;f++)
+ {
+ tot++;
+ printf("Num %d\n",msg[f].id);
+ printf(" From : %s@%s\n",msg[f].from_uname,msg[f].from_domain);
+ printf(" Subject : %s\n",msg[f].subject);
+
+ if (DBBlockMessage(msg+f))
+ {
+ printf(" BLOCKED : YES\n\n");
+ block++;
+ }
+ else
+ printf(" BLOCKED : NO\n\n");
+ }
+
+ printf("%d messages, %d blocked\n",tot,block);
+
+ POP3FreeList(msg);
+ }
+ else
+ {
+ printf("No messages\n");
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+/* ---------------------------------------- UTIL
+*/
+
+/* END OF FILE */
diff --git a/src/kbsrc b/src/kbsrc
new file mode 100644
index 0000000..e59e512
--- /dev/null
+++ b/src/kbsrc
@@ -0,0 +1,91 @@
+# Simple example KBS config file
+#
+
+# Set variables
+#
+set hostname mail.myisp.co.uk
+set username foobar
+set password raboof
+set casesense off
+set dejunk on
+set testmode on
+
+
+# Trusted people (from my address book)
+#
+trusted_users
+{
+ family@aol.com
+ fred@foobar.org
+ mailinglist@wibblesticks.com
+}
+
+trusted_domains
+{
+ my-place-of-work.com
+ freebsd.org
+}
+
+
+# Domain based rules
+#
+# Remember that the domain is defined in the form of a regular expression!
+#
+
+# Anyone who doesn't know me, has to include the string ansi-c to
+# get through from a .net address.
+#
+domain "\.net$"
+{
+ default block
+ allow_subject ".*ansi-c.*"
+}
+
+# 'Blacklist' a specific domain
+#
+domain "^wretched-hive-of-scum-and-villainy\.com$"
+{
+ default block
+}
+
+
+# Or alternatively apply general rules to all untrusted messages
+#
+domain "."
+{
+ default allow
+
+ # Apologies in advance if you have the same user ID as me...
+ #
+ block_user emailname
+
+ # Obviously, things like "credit card" will not be blocked from the bank
+ # as that's in the trusted_domains.
+ #
+ # And some of these may be accidently found in normal words, so remember
+ # to check the delete logs once in a while.
+ #
+ # And to avoid insulting anyone, there are some obvious words missing
+ # from this example list... If you're old enough, add them yourself.
+ #
+ # And finally remember a few variants - spelling isn't what it once was
+ # amongst spammers...
+ #
+ block_subject ".* ?penis ?.*"
+ block_subject ".* ?teenz ?.*"
+ block_subject ".* ?viagra ?.*"
+ block_subject ".* ?free all you can download ?.*"
+ block_subject ".* ?mortgage ?.*"
+ block_subject ".* ?credit card ?.*"
+ block_subject ".* ?miracle pill ?.*"
+ block_subject ".* ?teenage girl ?.*"
+ block_subject ".* ?video tape ?.*"
+ block_subject ".* ?sexy? ?.*"
+ block_subject ".* ?naked ?.*"
+ block_subject ".* ?nigeria ?.*"
+
+ # Why would anyone sane want to use my username in a subject?
+ # I know who I am!
+ #
+ block_subject "emailname@my-isp.co.uk"
+}
diff --git a/src/msg.h b/src/msg.h
new file mode 100644
index 0000000..314e9a7
--- /dev/null
+++ b/src/msg.h
@@ -0,0 +1,45 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Defines a POP3 message
+
+*/
+
+#ifndef KBS_MSG_H
+#define KBS_MSG_H
+
+typedef struct
+ {
+ int id;
+ char *to;
+ char *from;
+ char *from_uname;
+ char *from_domain;
+ char *subject;
+ char *content_type;
+ } POP3Message;
+
+#endif
+
+/* END OF FILE */
diff --git a/src/pop3.c b/src/pop3.c
new file mode 100644
index 0000000..8fd2750
--- /dev/null
+++ b/src/pop3.c
@@ -0,0 +1,530 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ POP3 Interface
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+
+#include "global.h"
+#include "pop3.h"
+#include "dstring.h"
+#include "util.h"
+
+
+/* ---------------------------------------- CONSTANTS
+*/
+#define BLOCKSIZE 512
+
+#define HDR_UNKNOWN -1
+#define HDR_SUBJECT 0
+#define HDR_FROM 1
+#define HDR_TO 2
+#define HDR_CONTENT_TYPE 3
+
+/* ---------------------------------------- TYPES
+*/
+
+
+/* ---------------------------------------- GLOBALS
+*/
+static int sock;
+static int timeout;
+static int connected=FALSE;
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void Chomp(char *p)
+{
+ size_t l;
+
+ l=strlen(p);
+
+ if (l && p[l-1]=='\012')
+ {
+ p[--l]=0;
+ }
+
+ if (l && p[l-1]=='\015')
+ {
+ p[--l]=0;
+ }
+}
+
+
+static char *ChompQuotesWS(char *p)
+{
+ size_t l;
+
+ l=strlen(p);
+
+ while (l && (p[l-1]=='"' || isspace(p[l-1])))
+ {
+ p[--l]=0;
+ }
+
+ while (l && (p[0]=='"' || isspace(p[0])))
+ memmove(p,p+1,--l);
+
+ return p;
+}
+
+
+static int Connect(const char *hostname, int port)
+{
+ struct hostent *remote;
+ struct sockaddr_in addr;
+
+ if (!(remote=gethostbyname(hostname)))
+ {
+ return FALSE;
+ }
+
+ memcpy(&addr.sin_addr,remote->h_addr,remote->h_length);
+
+ if ((sock=socket(PF_INET,SOCK_STREAM,0))==-1)
+ return FALSE;
+
+ addr.sin_family=AF_INET;
+ addr.sin_port=htons(port);
+
+ if (connect(sock,(const void *)&addr,sizeof(addr))==-1)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static int SendSock(const char *p, size_t len)
+{
+ size_t sent=0;
+
+ while(sent<len)
+ {
+ ssize_t w;
+
+ w=write(sock,p+sent,len-sent);
+
+ if (w==-1)
+ return -1;
+
+ if (w==0)
+ return 0;
+
+ sent+=w;
+ }
+
+ return 1;
+}
+
+
+static int Send(const char *cmd, ...)
+{
+ va_list ap;
+ const char *p;
+ int status;
+
+ va_start(ap,cmd);
+
+ status=SendSock(cmd,strlen(cmd));
+
+ p=va_arg(ap,const char *);
+
+ while (p && status==1)
+ {
+ status=SendSock(p,strlen(p));
+ p=va_arg(ap,const char *);
+ }
+
+ va_end(ap);
+
+ if (status==1)
+ status=SendSock("\015\012",2);
+
+ return status;
+}
+
+
+static int GetChar(void)
+{
+ static char buff[BLOCKSIZE];
+ static ssize_t len=0;
+ static int ptr=0;
+ int ch;
+
+ if (len==0 || ptr==len)
+ {
+ struct timeval tv;
+ fd_set set;
+
+ tv.tv_sec=timeout;
+ tv.tv_usec=timeout;
+
+ FD_ZERO(&set);
+ FD_SET(sock,&set);
+
+ if (select(sock+1,&set,NULL,NULL,&tv)==-1)
+ return -1;
+
+ if (!FD_ISSET(sock,&set))
+ return -1;
+
+ if ((len=read(sock,buff,sizeof buff))<1)
+ return -1;
+
+ ptr=0;
+ }
+
+ return buff[ptr++];
+}
+
+
+static int GetLine(DString t)
+{
+ size_t size;
+ int done;
+ int ch;
+ int last;
+
+ done=FALSE;
+
+ while(!done && (ch=GetChar())!=-1)
+ {
+ DSAddChar(t,ch);
+
+ if (last=='\015' && ch=='\012')
+ done=TRUE;
+
+ last=ch;
+ }
+
+ if (ch==-1)
+ return FALSE;
+
+ Chomp(t->text);
+
+ return TRUE;
+}
+
+
+static int GetResponse(DString ret)
+{
+ DString t;
+ int flag;
+
+ t=DSInit();
+
+ if (GetLine(t))
+ flag=t->text[0]=='+';
+ else
+ flag=FALSE;
+
+ if (ret)
+ DSAddDS(ret,t);
+
+ DSFree(t);
+
+ return flag;
+}
+
+
+static int GetMultiLine(DString ret)
+{
+ int flag;
+
+ if (GetLine(ret))
+ flag=TRUE;
+ else
+ flag=FALSE;
+
+ return flag;
+}
+
+
+static void ParseHeader(POP3Message *msg, char *line)
+{
+ static const struct
+ {
+ const char *text;
+ int type;
+ } field[]=
+ {
+ {"Subject: ", HDR_SUBJECT},
+ {"From: ", HDR_FROM},
+ {"To: ", HDR_TO},
+ {"Content-type: ", HDR_CONTENT_TYPE},
+ {"Content-Type: ", HDR_CONTENT_TYPE},
+ {NULL, HDR_UNKNOWN}
+ };
+
+ int f;
+ int type=HDR_UNKNOWN;
+
+ for(f=0;type==HDR_UNKNOWN && field[f].text;f++)
+ if (strncmp(field[f].text,line,strlen(field[f].text))==0)
+ {
+ type=field[f].type;
+ line+=strlen(field[f].text);
+ }
+
+ switch(type)
+ {
+ case HDR_SUBJECT:
+ msg->subject=CopyStr(line);
+ break;
+
+ case HDR_FROM:
+ if (strchr(line,'<'))
+ {
+ char *t[3];
+
+ for(f=0;f<3 && t[f-1];f++)
+ t[f]=strtok(f==0 ? line:NULL,"<>@");
+
+ msg->from=CopyStr(t[0] ? ChompQuotesWS(t[0]) : "UNKNOWN");
+ msg->from_uname=CopyStr(t[1] ? t[1] : "UNKNOWN");
+ msg->from_domain=CopyStr(t[2] ? t[2] : "UNKNOWN");
+ }
+ else
+ {
+ char *t[2];
+
+ for(f=0;f<2 && t[f-1];f++)
+ t[f]=strtok(f==0 ? line:NULL,"@");
+
+ msg->from=CopyStr("UNKNOWN");
+ msg->from_uname=CopyStr(t[0] ? t[0] : "UNKNOWN");
+ msg->from_domain=CopyStr(t[1] ? t[1] : "UNKNOWN");
+ }
+ break;
+
+ case HDR_TO:
+ msg->to=CopyStr(line);
+ break;
+
+ case HDR_CONTENT_TYPE:
+ msg->content_type=CopyStr(line);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+POP3Status POP3Connect(const char *hostname, int port,
+ const char *username, const char *passwd,
+ int t)
+{
+ timeout=t;
+ connected=FALSE;
+
+ if (port==0)
+ {
+ struct servent *ent;
+
+ if ((ent=getservbyname("pop3","tcp")))
+ port=ntohs(ent->s_port);
+ else
+ port=110;
+ }
+
+ if (!Connect(hostname,port))
+ return POP3_NOCONNECT;
+
+ if (!GetResponse(NULL))
+ return POP3_COMMERROR;
+
+ if (Send("USER ",username,(const char *)NULL)!=1)
+ return POP3_COMMERROR;
+
+ if (!GetResponse(NULL))
+ return POP3_BADUSER;
+
+ if (Send("PASS ",passwd,(const char *)NULL)!=1)
+ return POP3_COMMERROR;
+
+ if(!GetResponse(NULL))
+ return POP3_BADPASSWD;
+
+ connected=TRUE;
+
+ return POP3_OK;
+}
+
+
+POP3Message *POP3GetList(void)
+{
+ POP3Message *msg=NULL;
+ DString t;
+ char *p;
+ int no;
+ int f;
+
+ if (!connected)
+ return NULL;
+
+ t=DSInit();
+
+ Send("STAT",(const char *)NULL);
+
+ if (!GetResponse(t))
+ goto end;
+
+ p=strtok(t->text," ");
+
+ if (p)
+ p=strtok(NULL," ");
+
+ if (!p)
+ goto end;
+
+ no=atoi(p);
+
+ msg=Malloc(sizeof *msg * (no+1));
+
+ for(f=0;f<no;f++)
+ {
+ char cmd[64];
+ int done=FALSE;
+
+ msg[f].id=f+1;
+ msg[f].to=NULL;
+ msg[f].from=NULL;
+ msg[f].from_uname=NULL;
+ msg[f].from_domain=NULL;
+ msg[f].subject=NULL;
+ msg[f].content_type=NULL;
+
+ sprintf(cmd,"TOP %d 0",f+1);
+
+ Send(cmd,(const char *)NULL);
+
+ if (!GetResponse(NULL))
+ {
+ free(msg);
+ msg=NULL;
+ goto end;
+ }
+
+ while(!done)
+ {
+ t=DSReset(t);
+
+ if (!GetMultiLine(t))
+ {
+ free(msg);
+ msg=NULL;
+ goto end;
+ }
+
+ if (strcmp(t->text,".")==0)
+ done=TRUE;
+ else
+ {
+ ParseHeader(msg+f,t->text);
+ }
+ }
+
+ if (!msg[f].to)
+ msg[f].to=CopyStr("UNKNOWN");
+
+ if (!msg[f].from)
+ msg[f].from=CopyStr("UNKNOWN");
+
+ if (!msg[f].from_uname)
+ msg[f].from_uname=CopyStr("UNKNOWN");
+
+ if (!msg[f].from_domain)
+ msg[f].from_domain=CopyStr("UNKNOWN");
+
+ if (!msg[f].subject)
+ msg[f].subject=CopyStr("UNKNOWN");
+
+ if (!msg[f].content_type)
+ msg[f].content_type=CopyStr("UNKNOWN");
+ }
+
+ msg[no].id=0;
+ msg[no].to=NULL;
+ msg[no].from=NULL;
+ msg[no].from_uname=NULL;
+ msg[no].from_domain=NULL;
+ msg[no].subject=NULL;
+
+end:
+ DSFree(t);
+ return msg;
+}
+
+
+POP3Status POP3Delete(int msg)
+{
+ return POP3_OK;
+}
+
+
+void POP3Logoff(void)
+{
+ Send("QUIT",(const char *)NULL);
+ GetResponse(NULL);
+}
+
+
+void POP3FreeList(POP3Message *list)
+{
+ if (list)
+ {
+ int f;
+
+ for(f=0;list[f].to;f++)
+ {
+ free(list[f].to);
+ free(list[f].from);
+ free(list[f].from_uname);
+ free(list[f].from_domain);
+ free(list[f].subject);
+ }
+
+ free(list);
+ }
+}
+
+
+/* END OF FILE */
diff --git a/src/pop3.h b/src/pop3.h
new file mode 100644
index 0000000..c684634
--- /dev/null
+++ b/src/pop3.h
@@ -0,0 +1,90 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ POP3 Interface
+
+*/
+
+#ifndef KBS_POP3_H
+#define KBS_POP3_H
+
+#include "msg.h"
+
+/* ---------------------------------------- TYPES AND CONSTANTS
+*/
+typedef enum
+ {
+ POP3_OK,
+ POP3_COMMERROR,
+ POP3_NOCONNECT,
+ POP3_BADUSER,
+ POP3_BADPASSWD
+ } POP3Status;
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Connect to a POP3 server. Pass a port number of zero to use the
+ default. Returns POP_OK if connected OK, otherwise one of the POP_x errors.
+*/
+POP3Status POP3Connect(const char *hostname, int port,
+ const char *username, const char *passwd,
+ int timeout);
+
+
+/* Collect information from the POP3 server. Returns a list of POP3Messages,
+ terminated with a NULL to entry, or NULL for not connected or error.
+ Note that fields that weren't present in a message will be set to
+ "UNKOWN".
+
+ Note that if the TOP command is unimplemented on the server, then all the
+ fields in the message will be set to UNKNOWN.
+
+ Obviously, this isn't much use.
+*/
+POP3Message *POP3GetList(void);
+
+
+/* Deletes the specified message. Returns POP_OK if deleted OK, otherwise
+ one of the POP_x errors.
+
+ Remember that POP3 messages are number 1 .. N (so use the id field in
+ POP3Message).
+*/
+POP3Status POP3Delete(int msg);
+
+
+/* Logoff
+*/
+void POP3Logoff(void);
+
+
+/* Couresy function to free a message list.
+*/
+void POP3FreeList(POP3Message *list);
+
+
+#endif
+
+/* END OF FILE */
diff --git a/src/rexp.c b/src/rexp.c
new file mode 100644
index 0000000..0311c44
--- /dev/null
+++ b/src/rexp.c
@@ -0,0 +1,63 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Common utilities
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <regex.h>
+
+#include "global.h"
+#include "rexp.h"
+#include "config.h"
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+RExpStatus RExpSearch(const char *regexpr, const char *string)
+{
+ regex_t re;
+ int flags;
+ int res;
+
+ flags=REG_EXTENDED|REG_NOSUB;
+
+ if (!ConfigInt(CONFIG_CASESENSE))
+ flags|=REG_ICASE;
+
+ if (regcomp(&re,regexpr,flags))
+ return RE_BadExpression;
+
+ res=regexec(&re,string,0,NULL,0);
+
+ regfree(&re);
+
+ /* printf("RExpSearch(%s,%s)=%d\n",regexpr,string,res); */
+
+ return res ? RE_NotFound : RE_Found;
+}
+
+
+/* END OF FILE */
diff --git a/src/rexp.h b/src/rexp.h
new file mode 100644
index 0000000..04d1bb6
--- /dev/null
+++ b/src/rexp.h
@@ -0,0 +1,52 @@
+/*
+
+ kbs - Simple, easily fooled, REXP spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Regular expressions
+
+*/
+
+#ifndef KBS_REXP_H
+#define KBS_REXP_H
+
+#include <stdlib.h>
+
+/* ---------------------------------------- INTERFACES
+*/
+
+typedef enum
+ {
+ RE_Found,
+ RE_NotFound,
+ RE_BadExpression,
+ } RExpStatus;
+
+
+/* Search string for regexpr
+*/
+RExpStatus RExpSearch(const char *regexpr, const char *string);
+
+
+#endif
+
+/* END OF FILE */
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..b65ac01
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,79 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Common utilities
+
+*/
+static const char id[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "global.h"
+#include "util.h"
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+char *CopyStr(const char *p)
+{
+ char *new;
+
+ new=Malloc(strlen(p)+1);
+ strcpy(new,p);
+ return new;
+}
+
+
+void *F_Malloc(const char *file, int line, size_t len)
+{
+ void *new;
+
+ if (!(new=malloc(len)))
+ {
+ fprintf(stderr,"Unable to allocate %lu bytes for %s:%d\n",
+ (unsigned long)len,file,line);
+ exit(EXIT_FAILURE);
+ }
+
+ return new;
+}
+
+
+void *F_Realloc(const char *file, int line, void *p, size_t len)
+{
+ void *new;
+
+ if (!(new=realloc(p,len)))
+ {
+ fprintf(stderr,"Unable to reallocate %lu bytes for %s:%d\n",
+ (unsigned long)len,file,line);
+ exit(EXIT_FAILURE);
+ }
+
+ return new;
+}
+
+
+/* END OF FILE */
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..f37eb12
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,58 @@
+/*
+
+ kbs - Simple, easily fooled, POP3 spam filter
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+ Common utilities
+
+*/
+
+#ifndef KBS_UTIL_H
+#define KBS_UTIL_H
+
+#include <stdlib.h>
+
+/* ---------------------------------------- INTERFACES
+*/
+
+#define Malloc(l) F_Malloc(__FILE__,__LINE__,(l))
+#define Realloc(p,l) F_Realloc(__FILE__,__LINE__,(p),(l))
+
+
+/* Copy a string
+*/
+char *CopyStr(const char *p);
+
+
+/* Malloc wrapper. Just use free() to free.
+*/
+void *F_Malloc(const char *file, int line, size_t len);
+
+
+/* Realloc wrapper. Just use free() to free.
+*/
+void *F_Realloc(const char *file, int line, void *p, size_t len);
+
+
+#endif
+
+/* END OF FILE */