summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2003-12-08 02:20:14 +0000
committerIan C <ianc@noddybox.co.uk>2003-12-08 02:20:14 +0000
commit1c161a8cbe16aa59cc8bf4d60d5fa64fdcbc6aa5 (patch)
tree355d3a053199f03f5e13d8fa25b05723bf1da720
parent787bb7625c9abc6b09efbc6bbe004a19d4b96166 (diff)
Added subject_macro; Tweaked check order; Fixed some warnings
-rw-r--r--doc/INSTRUCTION78
-rw-r--r--src/Makefile13
-rw-r--r--src/config.c113
-rw-r--r--src/dbase.c36
-rw-r--r--src/dstring.c9
-rw-r--r--src/pop3.c5
6 files changed, 207 insertions, 47 deletions
diff --git a/doc/INSTRUCTION b/doc/INSTRUCTION
index ef0cdc6..e55fdef 100644
--- a/doc/INSTRUCTION
+++ b/doc/INSTRUCTION
@@ -23,19 +23,21 @@ order:
[trusted settings]
+[subject macros]
+
[domain settings]
-Note it is *highly* recommended to set .kbsrc to be only readable by the
-user - this is as passwords are stored in there.
+It is *highly* recommended to set .kbsrc to be only readable by the user - this
+is as passwords are stored in there.
Blank lines and text proceeded with a hash (#) are ignored.
Each token is delimited with white space - if the value you want to use
includes spaces, simple quote them (with either single or double quotes).
-Note that escapes aren't used (to make regular expression writing easier), so
-if you want to include a quote in a string, simply use the other sort of quote.
-If you want both, sorry, you're stuck!
+Escapes aren't used (to make regular expression writing easier), so if you want
+to include a quote in a string, simply use the other sort of quote. If you
+want both, sorry, you're stuck!
To see an example kbsrc file, see kbsrc in the src directory.
@@ -89,12 +91,13 @@ And understand the following variables:
Defaults to off.
blockhtml <on|off> Whether messages that are pure HTML (content part just
- reported as "text/html" are blocked.
+ reported as "text/html" are blocked. Also blocks
+ messages with an empty, or missing, content type.
Defaults to off.
testmode <on|off> Whether things will be really deleted, or just
- the actions logged. Note that the log is still
- filled out as if the deletion occured.
+ the actions logged. The log is still filled out as if
+ the deletion occured.
Defaults to off, though it is recommended to use this
for early runs to ensure your rules are not too harsh
(or too easy for that matter).
@@ -119,12 +122,47 @@ other tests.
}
+Subject Macros
+==============
+
+This command is simply to ease the writing of regular expressions where you
+want to match expressions where numbers or alternative characters are
+often used to try and fool filters:
+
+ subject_macro <source string> <replacement string>
+
+e.g.
+
+ subject_macro "i" "[i1!l]" # Common spam spellings for 'i'
+ subject_macro "e" "[e3]"
+ subject_macro "s" "[s5]"
+ ...
+ ...
+ disallow_subject " ?free movies ?"
+
+Subject macros are only expanded one time - if the result of an expansion
+includes another macro, that will not be expanded. Also remember
+that macros are case sensitive - this allows easy constructions like this
+which would break if the 'i' in the '[]' was expanded:
+
+ set casesense off
+ ...
+ ...
+ subject "i" "[i1!l]"
+ ...
+ ...
+ disallow_subject "i...[I12]"
+
+Even though it's not obvious from the examples above, the source string can
+be any number of characters.
+
+
Domain settings
===============
-These define the rules applied to a certain domain. Note the order these
-appear in is important, as the first match when checking domain names will
-be used.
+These define the rules applied to a certain domain. The order domains
+appear in is important, as the first match found when checking domain names
+will be used.
domain <regular expression>
{
@@ -147,9 +185,21 @@ always let through.
The block_subject means that subjects that match that regular expression are
always blocked and deleted.
-Note that multiple allow_subject and block_subject commands can be in one
-domain.
+Multiple allow and block commands can be in one domain.
+
+The commands inside a domain can appear in any order, but the checks are always
+done in this order:
+
+1. If a trusted domain, allow message.
+2. If a trusted user, allow message.
+3. If an HTML message and these are blocked, delete message.
+4. If the domain is not matched in a domain command, allow message.
+5. If the subject is allowed for the domain, allow message.
+6. If the username is blocked for the domain, delete message.
+7. If the subject is disallowed for the domain, delete message.
+8. Delete the message if the default is to block.
+
-------------------------------------------------------------------------------
-$Id: INSTRUCTION,v 1.3 2003-12-07 01:46:44 ianc Exp $
+$Id: INSTRUCTION,v 1.4 2003-12-08 02:20:14 ianc Exp $
diff --git a/src/Makefile b/src/Makefile
index 481148b..808d8ef 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -18,10 +18,11 @@
#
# -------------------------------------------------------------------------
#
-# $Id: Makefile,v 1.3 2003-12-05 19:38:37 ianc Exp $
+# $Id: Makefile,v 1.4 2003-12-08 02:20:14 ianc Exp $
#
-CFLAGS += -g
+# CFLAGS assumes that gcc is being used - simply comment out if required
+CFLAGS = -g -Wall -Werror
TARGET = kbs
@@ -60,8 +61,8 @@ 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 dbase.h dstring.h
-kbs.o: util.h
+kbs.o: /usr/include/errno.h global.h config.h pop3.h msg.h dbase.h rexp.h
+kbs.o: dstring.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
@@ -80,12 +81,12 @@ 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
-rexp.o: /usr/include/regex.h global.h rexp.h config.h
+rexp.o: /usr/include/regex.h global.h rexp.h config.h util.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
+dbase.o: rexp.h dstring.h config.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
diff --git a/src/config.c b/src/config.c
index 616fabf..268198d 100644
--- a/src/config.c
+++ b/src/config.c
@@ -53,6 +53,7 @@ typedef enum {
TOK_BlockUser,
TOK_AllowSubject,
TOK_BlockSubject,
+ TOK_SubjectMacro,
TOK_VarHostname,
TOK_VarPort,
TOK_VarUsername,
@@ -77,10 +78,17 @@ typedef struct Command
Token token;
} Command;
+typedef struct
+ {
+ char *macro;
+ char *expansion;
+ } Macro;
+
/* ---------------------------------------- GLOBALS
*/
static DString error;
+
static char *hostname=NULL;
static char *username=NULL;
static char *password=NULL;
@@ -93,6 +101,9 @@ static int testmode=FALSE;
static int blockhtml=FALSE;
static int verbose=TRUE;
+static int no_macro=0;
+static Macro *macro=NULL;
+
/* ---------------------------------------- COMMAND TABLE
*/
@@ -110,6 +121,7 @@ static const Command cmd_table[]=
{"block_user", TOK_BlockUser},
{"allow_subject", TOK_AllowSubject},
{"block_subject", TOK_BlockSubject},
+ {"subject_macro", TOK_SubjectMacro},
/* Variables
*/
@@ -143,6 +155,48 @@ static const Command cmd_table[]=
static Token GetToken(FILE *fp, DString *ret);
+/* ---------------------------------------- COMMAND HANDLER UTILS
+*/
+static DString ExpandRE(DString re)
+{
+ DString new;
+ Macro *m;
+ char *p;
+ int f;
+
+ new=DSInit();
+
+ p=re->text;
+
+ while(*p)
+ {
+ m=NULL;
+
+ for(f=0;f<no_macro && !m;f++)
+ {
+ if (strncmp(p,macro[f].macro,strlen(macro[f].macro))==0)
+ {
+ m=macro+f;
+ }
+ }
+
+ if (!m)
+ {
+ DSAddChar(new,*p);
+ p++;
+ }
+ else
+ {
+ DSAddCP(new,m->expansion);
+ p+=strlen(m->macro);
+ }
+ }
+
+ DSFree(re);
+ return new;
+}
+
+
/* ---------------------------------------- COMMAND HANDLERS
*/
static int DoSet(FILE *fp)
@@ -252,7 +306,6 @@ static int DoDomain(FILE *fp)
{
DString ds;
Token tok;
- int status=TRUE;
Domain *domain;
RE_Expression re;
@@ -327,6 +380,8 @@ static int DoDomain(FILE *fp)
case TOK_AllowSubject:
GetToken(fp,&ds);
+ ds=ExpandRE(ds);
+
if (!(re=RECompile(ds->text)))
{
DSAddCP(error,"Bad regular expression: ");
@@ -341,6 +396,8 @@ static int DoDomain(FILE *fp)
case TOK_BlockSubject:
GetToken(fp,&ds);
+ ds=ExpandRE(ds);
+
if (!(re=RECompile(ds->text)))
{
DSAddCP(error,"Bad regular expression: ");
@@ -371,7 +428,6 @@ static int DoTrustedUsers(FILE *fp)
{
DString ds;
Token tok;
- int status=TRUE;
ds=DSInit();
@@ -406,7 +462,6 @@ static int DoTrustedDomains(FILE *fp)
{
DString ds;
Token tok;
- int status=TRUE;
ds=DSInit();
@@ -433,6 +488,42 @@ static int DoTrustedDomains(FILE *fp)
}
+static int DoSubjectMacro(FILE *fp)
+{
+ DString arg[2];
+ int f;
+
+ for(f=0;f<2;f++)
+ {
+ arg[f]=DSInit();
+
+ if (GetToken(fp,&arg[f])==TOK_EOF)
+ {
+ DSAddCP(error,"Unexpected EOF in subject_macro");
+ return FALSE;
+ }
+ }
+
+ if (arg[0]->len==0 || arg[1]->len==0)
+ {
+ DSAddCP(error,"Can't use zero length strings in subject_macro");
+ return FALSE;
+ }
+
+ no_macro++;
+
+ macro=Realloc(macro,sizeof *macro * no_macro);
+
+ macro[no_macro-1].macro=CopyStr(arg[0]->text);
+ macro[no_macro-1].expansion=CopyStr(arg[1]->text);
+
+ for(f=0;f<2;f++)
+ DSFree(arg[f]);
+
+ return TRUE;
+}
+
+
/* ---------------------------------------- PRVIVATE FUNCTIONS
*/
static int Getc(FILE *fp)
@@ -570,7 +661,6 @@ static int Parse(FILE *fp)
{
DString txt;
Token tok;
- char *p;
txt=DSInit();
@@ -600,6 +690,11 @@ static int Parse(FILE *fp)
ok=FALSE;
break;
+ case TOK_SubjectMacro:
+ if (!DoSubjectMacro(fp))
+ ok=FALSE;
+ break;
+
case TOK_Expression:
DSAddCP(error,"Unknown command in config file: ");
DSAddDS(error,txt);
@@ -725,6 +820,16 @@ int ConfigInt(ConfigIntVar var)
void ConfigClose(void)
{
+ int f;
+
+ for(f=0;f<no_macro;f++)
+ {
+ free(macro[f].macro);
+ free(macro[f].expansion);
+ }
+
+ free(macro);
+
DSFree(error);
free(hostname);
free(username);
diff --git a/src/dbase.c b/src/dbase.c
index aed142d..43fe0b5 100644
--- a/src/dbase.c
+++ b/src/dbase.c
@@ -236,7 +236,8 @@ int DBBlockMessage(const POP3Message *msg)
return FALSE;
if (ConfigInt(CONFIG_BLOCKHTML) &&
- strncmp(msg->content_type,html,strlen(html))==0)
+ (strncmp(msg->content_type,html,strlen(html))==0 ||
+ strcmp(msg->content_type,"UNKNOWN")==0))
{
reason="HTML message";
return TRUE;
@@ -245,22 +246,6 @@ int DBBlockMessage(const POP3Message *msg)
if (!(dom=GetDomain(msg->from_domain)))
return FALSE;
- for(f=0;f<dom->no_user;f++)
- {
- int res;
-
- if (ConfigInt(CONFIG_CASESENSE))
- res=strcmp(dom->user[f],msg->from_uname);
- else
- res=strcasecmp(dom->user[f],msg->from_uname);
-
- if (res==0)
- {
- reason="disallowed name";
- return TRUE;
- }
- }
-
ds=DSInit();
if (ConfigInt(CONFIG_DEJUNK))
@@ -277,6 +262,23 @@ int DBBlockMessage(const POP3Message *msg)
}
}
+ for(f=0;f<dom->no_user;f++)
+ {
+ int res;
+
+ if (ConfigInt(CONFIG_CASESENSE))
+ res=strcmp(dom->user[f],msg->from_uname);
+ else
+ res=strcasecmp(dom->user[f],msg->from_uname);
+
+ if (res==0)
+ {
+ DSFree(ds);
+ reason="disallowed name";
+ return TRUE;
+ }
+ }
+
for(f=0;f<dom->no_block;f++)
{
if (RESearch(dom->block[f],ds->text))
diff --git a/src/dstring.c b/src/dstring.c
index e614e83..7e13067 100644
--- a/src/dstring.c
+++ b/src/dstring.c
@@ -87,6 +87,8 @@ DString DSAddChar(DString to, char c)
to->text[to->len++]=c;
to->text[to->len]=0;
+
+ return to;
}
@@ -96,15 +98,16 @@ DString DSAddCP(DString to, const char *from)
to->text=Realloc(to->text,(((to->len+1)/BLOCKSIZE)+1)*BLOCKSIZE);
strcat(to->text,from);
+
+ return to;
}
DString DSAddDS(DString to, const DString from)
{
- to->len+=from->len;
- to->text=Realloc(to->text,(((to->len+1)/BLOCKSIZE)+1)*BLOCKSIZE);
+ DSAddCP(to,from->text);
- strcat(to->text,from->text);
+ return to;
}
diff --git a/src/pop3.c b/src/pop3.c
index 660283e..d9fab19 100644
--- a/src/pop3.c
+++ b/src/pop3.c
@@ -31,6 +31,7 @@ static const char id[]="$Id$";
#include <stdarg.h>
#include <ctype.h>
+#include <unistd.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
@@ -183,7 +184,6 @@ static int GetChar(void)
static char buff[BLOCKSIZE];
static ssize_t len=0;
static int ptr=0;
- int ch;
if (len==0 || ptr==len)
{
@@ -214,10 +214,9 @@ static int GetChar(void)
static int GetLine(DString t)
{
- size_t size;
int done;
- int ch;
int last;
+ int ch;
done=FALSE;