diff options
Diffstat (limited to 'src/klammail/cfgparser.c')
-rw-r--r-- | src/klammail/cfgparser.c | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/src/klammail/cfgparser.c b/src/klammail/cfgparser.c new file mode 100644 index 0000000..a48fe85 --- /dev/null +++ b/src/klammail/cfgparser.c @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2002 - 2004 Tomasz Kojm <[email protected]> + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "options.h" +#include "cfgparser.h" +#include "defaults.h" +#include "str.h" +#include "memory.h" + +static int isnumb(const char *str) +{ + int i; + + for(i = 0; i < strlen(str); i++) + if(!isdigit(str[i])) + return 0; + + return 1; +} + +struct cfgstruct *parsecfg(const char *cfgfile) +{ + char buff[LINE_LENGTH], *name, *arg; + FILE *fs; + int line = 0, i, found, ctype, calc; + struct cfgstruct *copt = NULL; + struct cfgoption *pt; + + struct cfgoption cfg_options[] = { + {"LogFile", OPT_STR}, + {"LogFileUnlock", OPT_NOARG}, + {"LogFileMaxSize", OPT_COMPSIZE}, + {"LogTime", OPT_NOARG}, + {"LogClean", OPT_NOARG}, + {"LogVerbose", OPT_NOARG}, /* clamd + freshclam */ + {"LogSyslog", OPT_NOARG}, + {"LogFacility", OPT_STR}, + {"PidFile", OPT_STR}, + {"TemporaryDirectory", OPT_STR}, + {"MaxFileSize", OPT_COMPSIZE}, + {"ScanMail", OPT_NOARG}, + {"ScanOLE2", OPT_NOARG}, + {"ScanArchive", OPT_NOARG}, + {"ScanRAR", OPT_NOARG}, + {"ArchiveMaxFileSize", OPT_COMPSIZE}, + {"ArchiveMaxRecursion", OPT_NUM}, + {"ArchiveMaxFiles", OPT_NUM}, + {"ArchiveMaxCompressionRatio", OPT_NUM}, + {"ArchiveLimitMemoryUsage", OPT_NOARG}, + {"ArchiveBlockEncrypted", OPT_NOARG}, + {"DataDirectory", OPT_STR}, /* obsolete */ + {"DatabaseDirectory", OPT_STR}, /* clamd + freshclam */ + {"TCPAddr", OPT_STR}, + {"TCPSocket", OPT_NUM}, + {"LocalSocket", OPT_STR}, + {"MaxConnectionQueueLength", OPT_NUM}, + {"StreamSaveToDisk", OPT_NOARG}, + {"StreamMaxLength", OPT_COMPSIZE}, + {"MaxThreads", OPT_NUM}, + {"ReadTimeout", OPT_NUM}, + {"MaxDirectoryRecursion", OPT_NUM}, + {"FollowDirectorySymlinks", OPT_NOARG}, + {"FollowFileSymlinks", OPT_NOARG}, + {"Foreground", OPT_NOARG}, + {"Debug", OPT_NOARG}, + {"LeaveTemporaryFiles", OPT_NOARG}, + {"FixStaleSocket", OPT_NOARG}, + {"User", OPT_STR}, + {"AllowSupplementaryGroups", OPT_NOARG}, + {"SelfCheck", OPT_NUM}, + {"VirusEvent", OPT_FULLSTR}, + {"ClamukoScanOnLine", OPT_NOARG}, /* old name */ + {"ClamukoScanOnAccess", OPT_NOARG}, + {"ClamukoScanOnOpen", OPT_NOARG}, + {"ClamukoScanOnClose", OPT_NOARG}, + {"ClamukoScanOnExec", OPT_NOARG}, + {"ClamukoIncludePath", OPT_STR}, + {"ClamukoExcludePath", OPT_STR}, + {"ClamukoMaxFileSize", OPT_COMPSIZE}, + {"ClamukoScanArchive", OPT_NOARG}, + {"DatabaseOwner", OPT_STR}, /* freshclam */ + {"Checks", OPT_NUM}, /* freshclam */ + {"UpdateLogFile", OPT_STR}, /* freshclam */ + {"DatabaseMirror", OPT_STR}, /* freshclam */ + {"MaxAttempts", OPT_NUM}, /* freshclam */ + {"HTTPProxyServer", OPT_STR}, /* freshclam */ + {"HTTPProxyPort", OPT_NUM}, /* freshclam */ + {"HTTPProxyUsername", OPT_STR}, /* freshclam */ + {"HTTPProxyPassword", OPT_STR}, /* freshclam */ + {"NotifyClamd", OPT_OPTARG}, /* freshclam */ + {"OnUpdateExecute", OPT_FULLSTR}, /* freshclam */ + {"OnErrorExecute", OPT_FULLSTR}, /* freshclam */ + {0, 0} + }; + + + if((fs = fopen(cfgfile, "r")) == NULL) { + return NULL; + } + + + while(fgets(buff, LINE_LENGTH, fs)) { + + line++; + + if(buff[0] == '#') + continue; + + if(!strncmp("Example", buff, 7)) { + fprintf(stderr, "ERROR: Please edit the example config file %s.\n", cfgfile); + return NULL; + } + + + if((name = cli_strtok(buff, 0, " \r\n"))) { + arg = cli_strtok(buff, 1, " \r\n"); + found = 0; + for(i = 0; ; i++) { + pt = &cfg_options[i]; + if(pt->name) { + if(!strcmp(name, pt->name)) { + found = 1; + switch(pt->argtype) { + case OPT_STR: + if(!arg) { + fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name); + return NULL; + } + copt = regcfg(copt, name, arg, 0); + break; + case OPT_FULLSTR: + if(!arg) { + fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name); + return NULL; + } + /* FIXME: this one is an ugly hack of the above case */ + free(arg); + arg = strstr(buff, " "); + arg = strdup(++arg); + copt = regcfg(copt, name, arg, 0); + break; + case OPT_NUM: + if(!arg || !isnumb(arg)) { + fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical argument.\n", line, name); + return NULL; + } + copt = regcfg(copt, name, NULL, atoi(arg)); + free(arg); + break; + case OPT_COMPSIZE: + if(!arg) { + fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires argument.\n", line, name); + return NULL; + } + ctype = tolower(arg[strlen(arg) - 1]); + if(ctype == 'm' || ctype == 'k') { + char *cpy = (char *) mcalloc(strlen(arg), sizeof(char)); + strncpy(cpy, arg, strlen(arg) - 1); + if(!isnumb(cpy)) { + fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); + return NULL; + } + if(ctype == 'm') + calc = atoi(cpy) * 1024 * 1024; + else + calc = atoi(cpy) * 1024; + free(cpy); + } else { + if(!isnumb(arg)) { + fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); + return NULL; + } + calc = atoi(arg); + } + copt = regcfg(copt, name, NULL, calc); + free(arg); + break; + case OPT_NOARG: + if(arg) { + fprintf(stderr, "ERROR: Parse error at line %d: Option %s doesn't support arguments (got '%s').\n", line, name, arg); + return NULL; + } + copt = regcfg(copt, name, NULL, 0); + break; + case OPT_OPTARG: + copt = regcfg(copt, name, arg, 0); + break; + default: + fprintf(stderr, "ERROR: Parse error at line %d: Option %s is of unknown type %d\n", line, name, pt->argtype); + free(name); + free(arg); + break; + } + } + } else + break; + } + + if(!found) { + fprintf(stderr, "ERROR: Parse error at line %d: Unknown option %s.\n", line, name); + return NULL; + } + } + } + + fclose(fs); + return copt; +} + +void freecfg(struct cfgstruct *copt) +{ + struct cfgstruct *handler; + struct cfgstruct *arg; + + while (copt) { + arg = copt->nextarg; + while (arg) { + if(arg->strarg) { + free(arg->optname); + free(arg->strarg); + handler = arg; + arg=arg->nextarg; + free(handler); + } + } + if(copt->optname) { + free(copt->optname); + } + if(copt->strarg) { + free(copt->strarg); + } + handler = copt; + copt = copt->next; + free(handler); + } + return; +} + +struct cfgstruct *regcfg(struct cfgstruct *copt, char *optname, char *strarg, int numarg) +{ + struct cfgstruct *newnode, *pt; + + newnode = (struct cfgstruct *) mmalloc(sizeof(struct cfgstruct)); + newnode->optname = optname; + newnode->nextarg = NULL; + newnode->next = NULL; + + if(strarg) + newnode->strarg = strarg; + else { + newnode->strarg = NULL; + newnode->numarg = numarg; + } + + if((pt = cfgopt(copt, optname))) { + while(pt->nextarg) + pt = pt->nextarg; + + pt->nextarg = newnode; + return copt; + } else { + newnode->next = copt; + return newnode; + } +} + +struct cfgstruct *cfgopt(const struct cfgstruct *copt, const char *optname) +{ + struct cfgstruct *handler; + + handler = (struct cfgstruct *) copt; + + while(1) { + if(handler) { + if(handler->optname) + if(!strcmp(handler->optname, optname)) + return handler; + } else break; + handler = handler->next; + } + + return NULL; +} + |