📄 2002-12-24_rulefile.cpp
字号:
/*
+-----------------------------------------------------------------------------+
| |
| rulefile.cpp |
| Last change: yyyy-mm-dd |
| |
| Author: Jan Krumsiek |
| eMail: proxy@krumsiek.com |
| Web: http://www.krumsiek.com/proxy |
| |
| Copyright 2003 - Jan Krumsiek |
| This source code can freely be modified and redistributed. No liability |
| whatsoever is taken by the author for any use of this software. |
| |
| Description: |
| This module loads a rulefile (i.e. a file that contains rules which are |
| used to indicate if a message is blocked or may be passed) and creates a |
| RULEFILE struct which can then be used by the rule processor. |
| |
+-----------------------------------------------------------------------------+
*/
#include "proxymain.h"
#include "cfgfiles.h"
#include "rulefile.h"
#include "iostream.h"
#include <map>
// prototypes
RULE_COMMAND StrToCommand(CHARPTR command);
UINT AddRule(CHARPTR* parameters, RULESETPTR ruleset);
UINT AddList(CHARPTR* parameters, LISTMAPPTR listmap);
void SetFunctPointer(RULE* rule, RULE_TYPE type, bool insensitive);
int strstrcaps (const char* x, const char* y);
int stristrcaps (const char* x, const char* y);
RULE_TYPE StrToRuletype(CHARPTR command);
char* stristr(const char *szSrc,const char *szFind );
CHARPTR curfile; // Filename of current file
UINT curline; // Current line
LISTMAPPTR vlistmap; // Listmap must be globally accessible
RULEFILE* LoadRules(CHARPTR file) // exported
// loads a set of rules from a file and returns a pointer to the set
{
COMMAND cur;
RULE_COMMAND cur_cmd;
// create map of lists
vlistmap = new LISTMAP;
// create new ruleset
RULESETPTR vruleset = new RULESET;
// ruleset and map of lists are combined in the RULEFILE struct
RULEFILE* vreturn = new RULEFILE;
UINT retval;
// first of all open the file
OpenConfigFile(file);
// now iterate through all lines
cur = GetNextFullCommand();
curfile = file;
while (cur.command != 0)
{
// find out which command this is (convert the string to an integer)
cur_cmd = StrToCommand(cur.command);
// save current line
curline = cur.line;
// whic command is it?
switch (cur_cmd)
{
case C_RULE:
// it is a rule, call AddRule()
retval = AddRule(cur.paras,vruleset);
if (retval != 0)
{
// if return value of AddRule != -> something went wrong
// return 0 to indicate error
return 0;
}
break;
case C_LIST:
// A list to be loaded, call AddList()
AddList(cur.paras,vlistmap);
break;
default:
// invalid command
cout << "Error in " << curfile << "(" << curline << ")"
<< ": Unknown command '" << cur.command << "'" << endl;
// return zero to indicate error
return 0;
}
// release memory allocated for this command
ReleaseCommand(&cur);
// get next command
cur = GetNextFullCommand();
}
// release file (= deallocate memory)
ReleaseConfigFile();
// set return value
vreturn->rules = vruleset;
vreturn->list = vlistmap;
return vreturn;
}
void ReleaseRuleFile(RULEFILE* rulefile)
// dellocates all memory that has been allocated for a RULEFILE struct
{
UINT i,n;
LIST* curlist;
RULE* currule;
// first of all delete lists
// declare iterator
std::map<std::string, LIST*>::const_iterator iter;
// iterate throug map
for (iter = rulefile->list->begin(); iter != rulefile->list->end(); iter++)
{
// get current list
curlist = iter->second;
// iterate through list and delete each item
for (i=0;i<curlist->count;i++)
delete curlist->items[i];
// now delete array pointer of list
delete curlist->items;
// delete list pointer itsself
delete curlist;
}
// delete list-map
delete rulefile->list;
// delete rule structs
n = rulefile->rules->size();
for( i=0; i<n ; i++ )
{
// get rule from vector
currule = (*(rulefile->rules))[i];
// only 'fieldname' is a pointer that has to be deleted
delete currule->fieldname;
// now delete rule struct itself
delete currule;
}
// delete vector
delete rulefile->rules;
// finished... delete RULEFILE struct
delete rulefile;
// done
}
UINT AddRule(CHARPTR* parameters, RULESETPTR ruleset)
// adds a single rule to the ruleset 'ruleset'
// return 0 for success
{
RULE* newrule = new RULE;
RULE_TYPE ruletype;
bool issensitive;
// now check each parameter of this line, if something is wrong
// return 1 (= non-zero) and output error msg
// 1. parameter: field (header or body)
// must be 'header' or 'body'
if (stricmp(parameters[0],"header") == 0)
newrule->field = F_HEADER;
else if (stricmp(parameters[0],"body") == 0)
newrule->field = F_BODY;
else
{
// wrong parameter, output error
cout << "Error in " << curfile << "(" << curline << ")"
<< ": 1. parameter must be 'header' or 'body'"<< endl;
return 1;
}
// 2. parameter: name of header field
// if field = F_HEADER and 2. para empty -> error
if ((strlen(parameters[1]) == 0) && (newrule->field == F_HEADER))
{
cout << "Error in " << curfile << "(" << curline << ")"
<< ": 2. parameter may not be empty if field = 'header'"<< endl;
return 1;
}
else
{
// copy string
newrule->fieldname = (CHARPTR)CopyAndPtr(parameters[1],strlen(parameters[1]));
// lowercase (for string comparison)
strlwr(newrule->fieldname);
}
// 3. parameter: rule type (contains, equals ... etc.)
// convert from string to integer
ruletype = StrToRuletype(parameters[2]);
if (ruletype == R_UNKNOWN)
{
// unknown type -> error
cout << "Error in " << curfile << "(" << curline << ")"
<< ": 3. parameter must be 'equals', 'notequals', 'contains', 'notcontains', 'pattern' or 'notpattern'"<< endl;
return 1;
}
// 4. parameter: case sensitivity
// C for sensitive, I for insensitive
if (stricmp(parameters[3],"C") == 0)
issensitive = true;
else if (stricmp(parameters[3],"I") == 0)
issensitive = false;
else
{
// error
cout << "Error in " << curfile << "(" << curline << ")"
<< ": 4. parameter must be 'C' (case-sensitive) or 'I' (case-insensitive)"<< endl;
return 1;
}
// Now combine parameter 3 and 4 to get the pointer to the
// comparison function and the negation value
// (read comment in SetFunctPointer() for detailled description of "negation" value)
SetFunctPointer(newrule,ruletype,issensitive);
// 5. parameter: value
// if first byte is a @ -> pointer to list
if (*parameters[4] == '@')
{
// is list
// check if list already defined before
LIST* check;
check = (*vlistmap)[&(parameters[4])[1]];
// if check == 0 then list doesn't exist
if (check != 0)
{
// list exits. set a pointer to it
newrule->islist = true;
newrule->value = check;
LIST* ts = (LIST*) newrule->value;
ts = ts;
}
else
{
// list is not defined yet -> error
cout << "Error in " << curfile << "(" << curline << ")"
<< ": 5. parameter - list '" << &(parameters[4])[1] << "' does not exist or is not loaded yet" << endl;
return 1;
}
}
// no list, must be a value in quotes ""
else if (*parameters[4] == '"')
{
// Find closing quote
// Point to last byte
CHARPTR search = parameters[4] + strlen(parameters[4]) - 1;
// Go backwards to find closing quite
while (*search != '\"')
search--;
search--;
// Copy
newrule->islist = false;
newrule->value = (CHARPTR)CopyAndPtr(&(parameters[4])[1],search-parameters[4]);
}
else
{
cout << "Error in " << curfile << "(" << curline << ")"
<< ": 5. parameter must be a list pointer (@listname) or a value in quotes (\"val\")" << endl;
return 1;
}
// 6. parameter: action. sets what will be done if this rule matches
// must be 'pass' or 'isspam'
if (stricmp(parameters[5],"isspam") == 0)
newrule->action = A_ISSPAM;
else if (stricmp(parameters[5],"pass") == 0)
newrule->action = A_PASS;
else
{
cout << "Error in " << curfile << "(" << curline << ")"
<< ": 6. parameter must be 'isspam' or 'pass'" << endl;
return 1;
}
// if the code ran up to this point, the command is ok
// add to vector and return 0 (success)
ruleset->push_back(newrule);
return 0;
}
void SetFunctPointer(RULE* rule, RULE_TYPE type, bool issensitive)
// Sets the pointer of the comparison function according to the rule type
// and to the case sensitivity.
// About negation: Some comparison functions return zero if both strings match
// (e.g. strcmp), others return a non-zero values (e.g. strstr). The program
// expects a non-zero value for matching strings, so some results have to be negated
// Additionally, if we have negative rule type ("notequals", "notcontains") then
// we also have to negate the value (again)
{
// now we need to go through all possible combinations of rule types and
// case sensitivity values
switch (type)
{
case R_EQUALS:
// check if value is equal
if (issensitive == true)
rule->compare = strcmp; // case-sensitive equality check
else
rule->compare = stricmp; // case-insensitive equality check
rule->negate=false; // no negative funct
rule->negate=!rule->negate; // because strcmp returns 0 for matching strings
break;
case R_NOTEQUALS:
// same as R_EQUALS but negated
if (issensitive == true)
rule->compare = strcmp;
else
rule->compare = stricmp;
rule->negate=true; // negative funct !
rule->negate=!rule->negate; // because strcmp returns 0 for matching strings
break;
case R_CONTAINS:
// use function that return a non-zero value if a string
// is contained in another string
if (issensitive == true)
rule->compare = strstrcaps;
else
rule->compare = stristrcaps;
rule->negate = false; // No negative funct
break;
case R_NOTCONTAINS:
// same as R_CONTAINS but negated
if (issensitive == true)
rule->compare = strstrcaps;
else
rule->compare = stristrcaps;
rule->negate = true; // Negative funct!
break;
// [DBG] TODO: insert function for pattern matching
}
}
int strstrcaps (const char* x, const char* y)
// This function encapsulates strstr as strstr itself does not
// fit to our string comparision function signature CHECKFUNC
// (because it returns char* and we need int)
{
return (strstr(x,y) == 0) ? 0 : 1;
}
int stristrcaps (const char* x, const char* y)
// This function encapsulates stristr as stristr itself does not
// fit to our string comparision function signature CHECKFUNC
// (because it returns char* and we need int)
{
return (stristr(x,y) == 0) ? 0 : 1;
}
UINT AddList(CHARPTR* parameters, LISTMAPPTR listmap)
// opens a list file and uses each line as one lsit item
// the list is added to 'listmap'
{
CHARPTR filecont=0, fileend=0;
UINT filelen;
CHARPTR search=0,search2=0;
UINT linecount=0, cur=0;
LIST* newlist = new LIST;
// read file contents
GetFileCont(parameters[1],&filecont,&filelen);
// if filecont == 0 then failed opening file
if (filecont == 0)
{
cout << "Error in " << curfile << "(" << curline << ")"
<< ": failed opening file '" << parameters[1] << "'" << endl;
return 1;
}
fileend = filecont + filelen - 2;
// now count number of lines
search = filecont;
while ((search != 0) && (search < fileend))
{
linecount++;
search++;
search = strchr(search,10);
}
// reserve array of ptrs large enough for all lines
newlist->count = linecount;
newlist->items = new CHARPTR[linecount];
// walk through all lines and save them to array
search = filecont;
cur = 0;
while (search < fileend)
{
// find end of line
search2 = strchr(search,10);
if (search2 == 0)
{
// last line
newlist->items[cur] = (CHARPTR)CopyAndPtr(search,fileend-search);
break;
}
search2--;
// copy string
newlist->items[cur] = (CHARPTR)CopyAndPtr(search,search2-search+1);
cur++;
// go to beginning of next line
search = search2 + 2;
}
// save this list in listmap
(*listmap)[parameters[0]] = newlist;
return 0;
}
RULE_TYPE StrToRuletype(CHARPTR command)
// determines which rule type from enum RULE_TYPE belongs to
// the string command in 'command'
{
if (stricmp(command,"contains") == 0)
return R_CONTAINS;
if (stricmp(command,"notcontains") == 0)
return R_NOTCONTAINS;
if (stricmp(command,"equals") == 0)
return R_EQUALS;
if (stricmp(command,"notequals") == 0)
return R_NOTEQUALS;
if (stricmp(command,"pattern") == 0)
return R_PATTERN;
if (stricmp(command,"notpattern") == 0)
return R_NOTPATTERN;
// if code up to this point 'command' does not contain a valid command
return R_UNKNOWN;
}
RULE_COMMAND StrToCommand(CHARPTR command)
// determines which rule number from enum RULE_COMMAND belongs to
// the command in 'command'
{
if (stricmp(command,"rule") == 0)
return C_RULE;
if (stricmp(command,"loadlist") == 0)
return C_LIST;
return C_UNKNOWN;
}
CHARPTR stristr(const char *szsrc,const char *szfind )
// this function performs a case insensitive string search
{
int i, k, nfind, nsrc;
// if one of the strings is a zero-pointer or begins with a zero-byte -> no match
if( !szsrc || !szsrc[0] || !szfind || !szfind[0] )
return(0);
// determine lengths of strings
nsrc= strlen(szsrc);
nfind= strlen(szfind);
// now iterate through both strings and check byte for byte for
// matching strings. all characters are converted to lowercase before comparison
for( i=k=0 ; k<nfind && i<nsrc ; i++, k++ ) {
if( toupper(szsrc[i]) != toupper(szfind[k]) ) {
i -= k;
k = -1;
}
}
// k contains the max number of matching chars here
// if this value is equal to the length of the search string -> match!
if( k==nfind )
return(char*)(szsrc + i-nfind);
// if the code runs up to this point nothing the search string is not contained
return(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -