704 lines
18 KiB
C
704 lines
18 KiB
C
/*
|
|
* $LynxId: HTRules.c,v 1.47 2017/07/02 19:45:22 tom Exp $
|
|
*
|
|
* Configuration manager for Hypertext Daemon HTRules.c
|
|
* ==========================================
|
|
*
|
|
*
|
|
* History:
|
|
* 3 Jun 91 Written TBL
|
|
* 10 Aug 91 Authorisation added after Daniel Martin (pass, fail)
|
|
* Rule order in file changed
|
|
* Comments allowed with # on 1st char of rule line
|
|
* 17 Jun 92 Bug fix: pass and fail failed if didn't contain '*' TBL
|
|
* 1 Sep 93 Bug fix: no memory check - Nathan Torkington
|
|
* BYTE_ADDRESSING removed - Arthur Secret
|
|
* 11 Sep 93 MD Changed %i into %d in debug printf.
|
|
* VMS does not recognize %i.
|
|
* Bug Fix: in case of PASS, only one parameter to printf.
|
|
* 19 Sep 93 AL Added Access Authorization stuff.
|
|
* 1 Nov 93 AL Added htbin.
|
|
* 25 May 99 KW Added redirect for lynx.
|
|
*
|
|
*/
|
|
|
|
#include <HTUtils.h>
|
|
|
|
/* (c) CERN WorldWideWeb project 1990,91. See Copyright.html for details */
|
|
#include <HTRules.h>
|
|
|
|
#include <HTFile.h>
|
|
#include <LYLeaks.h>
|
|
#include <HTAAProt.h>
|
|
|
|
#define LINE_LENGTH 256
|
|
|
|
typedef struct _rule {
|
|
struct _rule *next;
|
|
HTRuleOp op;
|
|
char *pattern;
|
|
char *equiv;
|
|
char *condition_op; /* as strings - may be inefficient, */
|
|
char *condition; /* but this is not for a server - kw */
|
|
} rule;
|
|
|
|
#ifndef NO_RULES
|
|
|
|
#include <HTTP.h> /* for redirecting_url, indirectly HTPermitRedir - kw */
|
|
#include <LYGlobalDefs.h> /* for LYUserSpecifiedURL - kw */
|
|
#include <LYStrings.h> /* for LYscanFloat */
|
|
#include <LYUtils.h> /* for LYFixCursesOn - kw */
|
|
#include <HTAlert.h>
|
|
|
|
/* Global variables
|
|
* ----------------
|
|
*/
|
|
char *HTBinDir = NULL; /* Physical /htbin directory path. */
|
|
|
|
/* In future this should not be global. */
|
|
char *HTSearchScript = NULL; /* Search script name. */
|
|
|
|
/* Module-wide variables
|
|
* ---------------------
|
|
*/
|
|
|
|
static rule *rules = 0; /* Pointer to first on list */
|
|
|
|
#ifndef PUT_ON_HEAD
|
|
static rule *rule_tail = 0; /* Pointer to last on list */
|
|
#endif
|
|
|
|
/* Add rule to the list HTAddRule()
|
|
* --------------------
|
|
*
|
|
* On entry,
|
|
* pattern points to 0-terminated string containing a single "*"
|
|
* equiv points to the equivalent string with * for the
|
|
* place where the text matched by * goes.
|
|
* On exit,
|
|
* returns 0 if success, -1 if error.
|
|
*/
|
|
|
|
int HTAddRule(HTRuleOp op, const char *pattern,
|
|
const char *equiv,
|
|
const char *cond_op,
|
|
const char *cond)
|
|
{ /* BYTE_ADDRESSING removed and memory check - AS - 1 Sep 93 */
|
|
rule *temp;
|
|
char *pPattern = NULL;
|
|
|
|
temp = typecalloc(rule);
|
|
if (temp == NULL)
|
|
outofmem(__FILE__, "HTAddRule");
|
|
|
|
if (equiv) { /* Two operands */
|
|
char *pEquiv = NULL;
|
|
|
|
StrAllocCopy(pEquiv, equiv);
|
|
temp->equiv = pEquiv;
|
|
} else {
|
|
temp->equiv = 0;
|
|
}
|
|
if (cond_op) {
|
|
StrAllocCopy(temp->condition_op, cond_op);
|
|
StrAllocCopy(temp->condition, cond);
|
|
}
|
|
StrAllocCopy(pPattern, pattern);
|
|
temp->pattern = pPattern;
|
|
temp->op = op;
|
|
|
|
if (equiv) {
|
|
CTRACE((tfp, "Rule: For `%s' op %d `%s'", pattern, (int) op, equiv));
|
|
} else {
|
|
CTRACE((tfp, "Rule: For `%s' op %d", pattern, (int) op));
|
|
}
|
|
if (cond_op) {
|
|
CTRACE((tfp, "\t%s %s\n", cond_op, NONNULL(cond)));
|
|
} else {
|
|
CTRACE((tfp, "\n"));
|
|
}
|
|
|
|
if (!rules) {
|
|
#ifdef LY_FIND_LEAKS
|
|
atexit(HTClearRules);
|
|
#endif
|
|
}
|
|
#ifdef PUT_ON_HEAD
|
|
temp->next = rules;
|
|
rules = temp;
|
|
#else
|
|
temp->next = 0;
|
|
if (rule_tail)
|
|
rule_tail->next = temp;
|
|
else
|
|
rules = temp;
|
|
rule_tail = temp;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Clear all rules HTClearRules()
|
|
* ---------------
|
|
*
|
|
* On exit,
|
|
* There are no rules
|
|
*
|
|
* See also
|
|
* HTAddRule()
|
|
*/
|
|
void HTClearRules(void)
|
|
{
|
|
while (rules) {
|
|
rule *temp = rules;
|
|
|
|
rules = temp->next;
|
|
FREE(temp->pattern);
|
|
FREE(temp->equiv);
|
|
FREE(temp->condition_op);
|
|
FREE(temp->condition);
|
|
FREE(temp);
|
|
}
|
|
#ifndef PUT_ON_HEAD
|
|
rule_tail = 0;
|
|
#endif
|
|
}
|
|
|
|
static BOOL rule_cond_ok(rule * r)
|
|
{
|
|
BOOL result;
|
|
|
|
if (!r->condition_op)
|
|
return YES;
|
|
if (strcmp(r->condition_op, "if") && strcmp(r->condition_op, "unless")) {
|
|
CTRACE((tfp, "....... rule ignored, unrecognized `%s'!\n",
|
|
r->condition_op));
|
|
return NO;
|
|
}
|
|
if (!strcmp(r->condition, "redirected"))
|
|
result = (BOOL) (redirection_attempts > 0);
|
|
else if (!strcmp(r->condition, "userspec"))
|
|
result = LYUserSpecifiedURL;
|
|
else {
|
|
CTRACE((tfp, "....... rule ignored, unrecognized `%s %s'!\n",
|
|
r->condition_op, NONNULL(r->condition)));
|
|
return NO;
|
|
}
|
|
if (!strcmp(r->condition_op, "if"))
|
|
return result;
|
|
else
|
|
return (BOOL) (!result);
|
|
|
|
}
|
|
|
|
/* Translate by rules HTTranslate()
|
|
* ------------------
|
|
*
|
|
* The most recently defined rules are applied first.
|
|
*
|
|
* On entry,
|
|
* required points to a string whose equivalent value is needed
|
|
* On exit,
|
|
* returns the address of the equivalent string allocated from
|
|
* the heap which the CALLER MUST FREE. If no translation
|
|
* occurred, then it is a copy of the original.
|
|
* NEW FEATURES:
|
|
* When a "protect" or "defprot" rule is matched,
|
|
* a call to HTAA_setCurrentProtection() or
|
|
* HTAA_setDefaultProtection() is made to notify
|
|
* the Access Authorization module that the file is
|
|
* protected, and so it knows how to handle it.
|
|
* -- AL
|
|
*/
|
|
char *HTTranslate(const char *required)
|
|
{
|
|
rule *r;
|
|
char *current = NULL;
|
|
char *msgtmp = NULL;
|
|
const char *pMsg;
|
|
int proxy_none_flag = 0;
|
|
int permitredir_flag = 0;
|
|
|
|
StrAllocCopy(current, required);
|
|
|
|
HTAA_clearProtections(); /* Reset from previous call -- AL */
|
|
|
|
for (r = rules; r; r = r->next) {
|
|
char *p = r->pattern;
|
|
int m = 0; /* Number of characters matched against wildcard */
|
|
const char *q = current;
|
|
|
|
for (; *p && *q; p++, q++) { /* Find first mismatch */
|
|
if (*p != *q)
|
|
break;
|
|
}
|
|
|
|
if (*p == '*') { /* Match up to wildcard */
|
|
m = (int) strlen(q) - (int) strlen(p + 1); /* Amount to match to wildcard */
|
|
if (m < 0)
|
|
continue; /* tail is too short to match */
|
|
if (0 != strcmp(q + m, p + 1))
|
|
continue; /* Tail mismatch */
|
|
} else
|
|
/* Not wildcard */ if (*p != *q)
|
|
continue; /* plain mismatch: go to next rule */
|
|
|
|
if (!rule_cond_ok(r)) /* check condition, next rule if false - kw */
|
|
continue;
|
|
|
|
switch (r->op) { /* Perform operation */
|
|
|
|
case HT_DefProt:
|
|
case HT_Protect:
|
|
#ifdef ACCESS_AUTH
|
|
{
|
|
char *local_copy = NULL;
|
|
char *p2;
|
|
char *eff_ids = NULL;
|
|
char *prot_file = NULL;
|
|
|
|
CTRACE((tfp, "HTRule: `%s' matched %s %s: `%s'\n",
|
|
current,
|
|
(r->op == HT_Protect ? "Protect" : "DefProt"),
|
|
"rule, setup",
|
|
(r->equiv ? r->equiv :
|
|
(r->op == HT_Protect ? "DEFAULT" : "NULL!!"))));
|
|
|
|
if (r->equiv) {
|
|
StrAllocCopy(local_copy, r->equiv);
|
|
p2 = local_copy;
|
|
prot_file = HTNextField(&p2);
|
|
eff_ids = HTNextField(&p2);
|
|
}
|
|
|
|
if (r->op == HT_Protect)
|
|
HTAA_setCurrentProtection(current, prot_file, eff_ids);
|
|
else
|
|
HTAA_setDefaultProtection(current, prot_file, eff_ids);
|
|
|
|
FREE(local_copy);
|
|
|
|
/* continue translating rules */
|
|
}
|
|
#endif /* ACCESS_AUTH */
|
|
break;
|
|
|
|
case HT_UserMsg: /* Produce message immediately */
|
|
LYFixCursesOn("show rule message:");
|
|
HTUserMsg2((r->equiv ? r->equiv : "Rule: %s"), current);
|
|
break;
|
|
case HT_InfoMsg: /* Produce messages immediately */
|
|
case HT_Progress:
|
|
case HT_Alert:
|
|
LYFixCursesOn("show rule message:"); /* and fall through */
|
|
/* FALLTHRU */
|
|
case HT_AlwaysAlert:
|
|
pMsg = r->equiv ? r->equiv :
|
|
(r->op == HT_AlwaysAlert) ? "%s" : "Rule: %s";
|
|
if (StrChr(pMsg, '%')) {
|
|
HTSprintf0(&msgtmp, pMsg, current);
|
|
pMsg = msgtmp;
|
|
}
|
|
switch (r->op) { /* Actually produce message */
|
|
case HT_InfoMsg:
|
|
HTInfoMsg(pMsg);
|
|
break;
|
|
case HT_Progress:
|
|
HTProgress(pMsg);
|
|
break;
|
|
case HT_Alert:
|
|
HTAlert(pMsg);
|
|
break;
|
|
case HT_AlwaysAlert:
|
|
HTAlwaysAlert("Rule alert:", pMsg);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
FREE(msgtmp);
|
|
break;
|
|
|
|
case HT_PermitRedir: /* Set special flag */
|
|
permitredir_flag = 1;
|
|
CTRACE((tfp, "HTRule: Mark for redirection permitted\n"));
|
|
break;
|
|
|
|
case HT_Pass: /* Authorised */
|
|
if (!r->equiv) {
|
|
if (proxy_none_flag) {
|
|
char *temp = NULL;
|
|
|
|
StrAllocCopy(temp, "NoProxy=");
|
|
StrAllocCat(temp, current);
|
|
FREE(current);
|
|
current = temp;
|
|
}
|
|
CTRACE((tfp, "HTRule: Pass `%s'\n", current));
|
|
return current;
|
|
}
|
|
/* FALLTHRU */
|
|
|
|
case HT_Map:
|
|
case HT_Redirect:
|
|
case HT_RedirectPerm:
|
|
if (*p == *q) { /* End of both strings, no wildcard */
|
|
CTRACE((tfp, "For `%s' using `%s'\n", current, r->equiv));
|
|
StrAllocCopy(current, r->equiv); /* use entire translation */
|
|
} else {
|
|
char *ins = StrChr(r->equiv, '*'); /* Insertion point */
|
|
|
|
if (ins) { /* Consistent rule!!! */
|
|
char *temp = NULL;
|
|
|
|
HTSprintf0(&temp, "%.*s%.*s%s",
|
|
(int) (ins - r->equiv),
|
|
r->equiv,
|
|
m,
|
|
q,
|
|
ins + 1);
|
|
CTRACE((tfp, "For `%s' using `%s'\n",
|
|
current, temp));
|
|
FREE(current);
|
|
current = temp; /* Use this */
|
|
|
|
} else { /* No insertion point */
|
|
char *temp = NULL;
|
|
|
|
StrAllocCopy(temp, r->equiv);
|
|
CTRACE((tfp, "For `%s' using `%s'\n",
|
|
current, temp));
|
|
FREE(current);
|
|
current = temp; /* Use this */
|
|
} /* If no insertion point exists */
|
|
}
|
|
if (r->op == HT_Pass) {
|
|
if (proxy_none_flag) {
|
|
char *temp = NULL;
|
|
|
|
StrAllocCopy(temp, "NoProxy=");
|
|
StrAllocCat(temp, current);
|
|
FREE(current);
|
|
current = temp;
|
|
}
|
|
CTRACE((tfp, "HTRule: ...and pass `%s'\n",
|
|
current));
|
|
return current;
|
|
} else if (r->op == HT_Redirect) {
|
|
CTRACE((tfp, "HTRule: ...and redirect to `%s'\n",
|
|
current));
|
|
redirecting_url = current;
|
|
HTPermitRedir = (BOOL) (permitredir_flag == 1);
|
|
return (char *) 0;
|
|
} else if (r->op == HT_RedirectPerm) {
|
|
CTRACE((tfp, "HTRule: ...and redirect like 301 to `%s'\n",
|
|
current));
|
|
redirecting_url = current;
|
|
permanent_redirection = TRUE;
|
|
HTPermitRedir = (BOOL) (permitredir_flag == 1);
|
|
return (char *) 0;
|
|
}
|
|
break;
|
|
|
|
case HT_UseProxy:
|
|
if (r->equiv && 0 == strcasecomp(r->equiv, "none")) {
|
|
CTRACE((tfp, "For `%s' will not use proxy\n", current));
|
|
proxy_none_flag = 1;
|
|
} else if (proxy_none_flag) {
|
|
CTRACE((tfp, "For `%s' proxy server ignored: %s\n",
|
|
current,
|
|
NONNULL(r->equiv)));
|
|
} else {
|
|
char *temp = NULL;
|
|
|
|
StrAllocCopy(temp, "Proxied=");
|
|
StrAllocCat(temp, r->equiv);
|
|
StrAllocCat(temp, current);
|
|
CTRACE((tfp, "HTRule: proxy server found: %s\n",
|
|
NONNULL(r->equiv)));
|
|
FREE(current);
|
|
return temp;
|
|
}
|
|
break;
|
|
|
|
case HT_Invalid:
|
|
case HT_Fail: /* Unauthorised */
|
|
CTRACE((tfp, "HTRule: *** FAIL `%s'\n", current));
|
|
FREE(current);
|
|
return (char *) 0;
|
|
} /* if tail matches ... switch operation */
|
|
|
|
} /* loop over rules */
|
|
|
|
if (proxy_none_flag) {
|
|
char *temp = NULL;
|
|
|
|
StrAllocCopy(temp, "NoProxy=");
|
|
StrAllocCat(temp, current);
|
|
FREE(current);
|
|
return temp;
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
/* Load one line of configuration
|
|
* ------------------------------
|
|
*
|
|
* Call this, for example, to load a X resource with config info.
|
|
*
|
|
* returns 0 OK, < 0 syntax error.
|
|
*/
|
|
int HTSetConfiguration(char *config)
|
|
{
|
|
HTRuleOp op;
|
|
char *line = NULL;
|
|
char *pointer = NULL;
|
|
char *word1;
|
|
const char *word2;
|
|
const char *word3;
|
|
const char *cond_op = NULL;
|
|
const char *cond = NULL;
|
|
float quality, secs, secs_per_byte;
|
|
long maxbytes;
|
|
int status;
|
|
|
|
StrAllocCopy(line, config);
|
|
if (line != NULL) {
|
|
char *p = line;
|
|
|
|
/* Chop off comments */
|
|
while ((p = StrChr(p, '#'))) {
|
|
if (p == line || isspace(UCH(*(p - 1)))) {
|
|
*p = 0;
|
|
break;
|
|
} else {
|
|
p++;
|
|
}
|
|
}
|
|
}
|
|
pointer = line;
|
|
word1 = HTNextField(&pointer);
|
|
if (!word1) {
|
|
FREE(line);
|
|
return 0;
|
|
}; /* Comment only or blank */
|
|
|
|
word2 = HTNextField(&pointer);
|
|
|
|
if (0 == strcasecomp(word1, "defprot") ||
|
|
0 == strcasecomp(word1, "protect"))
|
|
word3 = pointer; /* The rest of the line to be parsed by AA module */
|
|
else
|
|
word3 = HTNextField(&pointer); /* Just the next word */
|
|
|
|
if (!word2) {
|
|
fprintf(stderr, "HTRule: %s %s\n", RULE_NEEDS_DATA, line);
|
|
FREE(line);
|
|
return -2; /*syntax error */
|
|
}
|
|
|
|
if (0 == strcasecomp(word1, "suffix")) {
|
|
char *encoding = HTNextField(&pointer);
|
|
|
|
status = 0;
|
|
if (pointer)
|
|
status = LYscanFloat(pointer, &quality);
|
|
|
|
HTSetSuffix(word2, word3,
|
|
encoding ? encoding : "binary",
|
|
status >= 1 ? quality : (float) 1.0);
|
|
|
|
} else if (0 == strcasecomp(word1, "presentation")) {
|
|
status = 0;
|
|
if (pointer) {
|
|
const char *temp = pointer;
|
|
|
|
if (LYscanFloat2(&temp, &quality)) {
|
|
status = 1;
|
|
if (LYscanFloat2(&temp, &secs)) {
|
|
status = 2;
|
|
if (LYscanFloat2(&temp, &secs_per_byte)) {
|
|
status = 3;
|
|
if (sscanf(temp, "%ld", &maxbytes)) {
|
|
status = 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HTSetPresentation(word2, word3, NULL,
|
|
status >= 1 ? quality : 1.0,
|
|
status >= 2 ? secs : 0.0,
|
|
status >= 3 ? secs_per_byte : 0.0,
|
|
status >= 4 ? maxbytes : 0,
|
|
mediaCFG);
|
|
|
|
} else if (0 == strncasecomp(word1, "htbin", 5) ||
|
|
0 == strncasecomp(word1, "bindir", 6)) {
|
|
StrAllocCopy(HTBinDir, word2); /* Physical /htbin location */
|
|
|
|
} else if (0 == strncasecomp(word1, "search", 6)) {
|
|
StrAllocCopy(HTSearchScript, word2); /* Search script name */
|
|
|
|
} else {
|
|
op = 0 == strcasecomp(word1, "map") ? HT_Map
|
|
: 0 == strcasecomp(word1, "pass") ? HT_Pass
|
|
: 0 == strcasecomp(word1, "fail") ? HT_Fail
|
|
: 0 == strcasecomp(word1, "redirect") ? HT_Redirect
|
|
: 0 == strncasecomp(word1, "redirectperm", 12) ? HT_RedirectPerm
|
|
: 0 == strcasecomp(word1, "redirecttemp") ? HT_Redirect
|
|
: 0 == strcasecomp(word1, "permitredirection") ? HT_PermitRedir
|
|
: 0 == strcasecomp(word1, "useproxy") ? HT_UseProxy
|
|
: 0 == strcasecomp(word1, "alert") ? HT_Alert
|
|
: 0 == strcasecomp(word1, "alwaysalert") ? HT_AlwaysAlert
|
|
: 0 == strcasecomp(word1, "progress") ? HT_Progress
|
|
: 0 == strcasecomp(word1, "usermsg") ? HT_UserMsg
|
|
: 0 == strcasecomp(word1, "infomsg") ? HT_InfoMsg
|
|
: 0 == strcasecomp(word1, "defprot") ? HT_DefProt
|
|
: 0 == strcasecomp(word1, "protect") ? HT_Protect
|
|
: HT_Invalid;
|
|
if (op == HT_Invalid) {
|
|
fprintf(stderr, "HTRule: %s '%s'\n", RULE_INCORRECT, config);
|
|
} else {
|
|
switch (op) {
|
|
case HT_Fail: /* never a or other 2nd parameter */
|
|
case HT_PermitRedir:
|
|
cond_op = word3;
|
|
if (cond_op && *cond_op) {
|
|
word3 = NULL;
|
|
cond = HTNextField(&pointer);
|
|
}
|
|
break;
|
|
|
|
case HT_Pass: /* possibly a URL2 */
|
|
if (word3 && (!strcasecomp(word3, "if") ||
|
|
!strcasecomp(word3, "unless"))) {
|
|
cond_op = word3;
|
|
word3 = NULL;
|
|
cond = HTNextField(&pointer);
|
|
break;
|
|
}
|
|
/* else fall through */
|
|
case HT_Map: /* always a URL2 (or other 2nd parameter) */
|
|
case HT_Redirect:
|
|
case HT_RedirectPerm:
|
|
case HT_UseProxy:
|
|
cond_op = HTNextField(&pointer);
|
|
/* check for extra status word in "Redirect" */
|
|
if (op == HT_Redirect && 0 == strcasecomp(word1, "redirect") &&
|
|
cond_op &&
|
|
strcasecomp(cond_op, "if") &&
|
|
strcasecomp(cond_op, "unless")) {
|
|
if (0 == strcmp(word2, "301") ||
|
|
0 == strcasecomp(word2, "permanent")) {
|
|
op = HT_RedirectPerm;
|
|
} else if (!(0 == strcmp(word2, "302") ||
|
|
0 == strcmp(word2, "303") ||
|
|
0 == strcasecomp(word2, "temp") ||
|
|
0 == strcasecomp(word2, "seeother"))) {
|
|
CTRACE((tfp, "Rule: Ignoring `%s' in Redirect\n", word2));
|
|
}
|
|
word2 = word3;
|
|
word3 = cond_op; /* cond_op isn't condition op after all */
|
|
cond_op = HTNextField(&pointer);
|
|
}
|
|
if (cond_op && *cond_op)
|
|
cond = HTNextField(&pointer);
|
|
break;
|
|
|
|
case HT_Progress:
|
|
case HT_InfoMsg:
|
|
case HT_UserMsg:
|
|
case HT_Alert:
|
|
case HT_AlwaysAlert:
|
|
cond_op = HTNextField(&pointer);
|
|
if (cond_op && *cond_op)
|
|
cond = HTNextField(&pointer);
|
|
if (word3) { /* Fix string with too may %s - kw */
|
|
const char *cp = word3;
|
|
char *cp1, *cp2;
|
|
|
|
while ((cp1 = StrChr(cp, '%'))) {
|
|
if (cp1[1] == '\0') {
|
|
*cp1 = '\0';
|
|
break;
|
|
} else if (cp1[1] == '%') {
|
|
cp = cp1 + 2;
|
|
continue;
|
|
} else
|
|
while ((cp2 = StrChr(cp1 + 2, '%'))) {
|
|
if (cp2[1] == '\0') {
|
|
*cp2 = '\0';
|
|
break;
|
|
} else if (cp2[1] == '%') {
|
|
cp1 = cp2;
|
|
} else {
|
|
*cp2 = '?'; /* replace bad % */
|
|
cp1 = cp2;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
if (cond_op && cond && *cond && !strcasecomp(cond_op, "unless")) {
|
|
cond_op = "unless";
|
|
} else if (cond_op && cond && *cond &&
|
|
!strcasecomp(cond_op, "if")) {
|
|
cond_op = "if";
|
|
} else if (cond_op || cond) {
|
|
fprintf(stderr, "HTRule: %s '%s'\n", RULE_INCORRECT, config);
|
|
FREE(line); /* syntax error, condition is a mess - kw */
|
|
return -2; /* NB unrecognized cond passes here - kw */
|
|
}
|
|
if (cond && !strncasecomp(cond, "redirected", (int) strlen(cond))) {
|
|
cond = "redirected"; /* recognized, canonical case - kw */
|
|
} else if (cond && strlen(cond) >= 8 &&
|
|
!strncasecomp(cond, "userspecified", (int) strlen(cond))) {
|
|
cond = "userspec"; /* also allow abbreviation - kw */
|
|
}
|
|
HTAddRule(op, word2, word3, cond_op, cond);
|
|
}
|
|
}
|
|
FREE(line);
|
|
return 0;
|
|
}
|
|
|
|
/* Load the rules from a file HTLoadRules()
|
|
* --------------------------
|
|
*
|
|
* On entry,
|
|
* Rules can be in any state
|
|
* On exit,
|
|
* Any existing rules will have been kept.
|
|
* Any new rules will have been loaded.
|
|
* Returns 0 if no error, 0 if error!
|
|
*
|
|
* Bugs:
|
|
* The strings may not contain spaces.
|
|
*/
|
|
|
|
int HTLoadRules(const char *filename)
|
|
{
|
|
FILE *fp = fopen(filename, TXT_R);
|
|
char line[LINE_LENGTH + 1];
|
|
|
|
if (!fp) {
|
|
CTRACE((tfp, "HTRules: Can't open rules file %s\n", filename));
|
|
return -1; /* File open error */
|
|
}
|
|
for (;;) {
|
|
if (!fgets(line, LINE_LENGTH + 1, fp))
|
|
break; /* EOF or error */
|
|
(void) HTSetConfiguration(line);
|
|
}
|
|
fclose(fp);
|
|
return 0; /* No error or syntax errors ignored */
|
|
}
|
|
|
|
#endif /* NO_RULES */
|