summaryrefslogtreecommitdiff
path: root/src/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c715
1 files changed, 715 insertions, 0 deletions
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 */