diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 102 | ||||
-rw-r--r-- | src/config.c | 715 | ||||
-rw-r--r-- | src/config.h | 80 | ||||
-rw-r--r-- | src/dbase.c | 281 | ||||
-rw-r--r-- | src/dbase.h | 86 | ||||
-rw-r--r-- | src/dstring.c | 111 | ||||
-rw-r--r-- | src/dstring.h | 86 | ||||
-rw-r--r-- | src/global.h | 44 | ||||
-rw-r--r-- | src/kbs.c | 147 | ||||
-rw-r--r-- | src/kbsrc | 91 | ||||
-rw-r--r-- | src/msg.h | 45 | ||||
-rw-r--r-- | src/pop3.c | 530 | ||||
-rw-r--r-- | src/pop3.h | 90 | ||||
-rw-r--r-- | src/rexp.c | 63 | ||||
-rw-r--r-- | src/rexp.h | 52 | ||||
-rw-r--r-- | src/util.c | 79 | ||||
-rw-r--r-- | src/util.h | 58 |
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 */ |