Annotation of libwww/Library/src/HTRules.c, revision 2.15
2.1 timbl 1: /* Configuration manager for Hypertext Daemon HTRules.c
2: ** ==========================================
3: **
4: **
5: ** History:
6: ** 3 Jun 91 Written TBL
7: ** 10 Aug 91 Authorisation added after Daniel Martin (pass, fail)
8: ** Rule order in file changed
9: ** Comments allowed with # on 1st char of rule line
10: ** 17 Jun 92 Bug fix: pass and fail failed if didn't contain '*' TBL
2.9 secret 11: ** 1 Sep 93 Bug fix: no memory check - Nathan Torkington
12: ** BYTE_ADDRESSING removed - Arthur Secret
2.12 luotonen 13: ** 11 Sep 93 MD Changed %i into %d in debug printf.
2.10 duns 14: ** VMS does not recognize %i.
15: ** Bug Fix: in case of PASS, only one parameter to printf.
2.12 luotonen 16: ** 19 Sep 93 AL Added Access Authorization stuff.
17: ** 1 Nov 93 AL Added htbin.
2.15 ! luotonen 18: ** 30 Nov 93 AL Added HTTranslateReq().
2.11 luotonen 19: **
2.1 timbl 20: */
21:
22: /* (c) CERN WorldWideWeb project 1990,91. See Copyright.html for details */
23: #include "HTRules.h"
24:
25: #include <stdio.h>
26: #include "tcp.h"
27: #include "HTFile.h"
2.11 luotonen 28: #include "HTAAServ.h" /* Access Authorization */
2.1 timbl 29:
30: #define LINE_LENGTH 256
31:
32:
33: typedef struct _rule {
34: struct _rule * next;
35: HTRuleOp op;
36: char * pattern;
37: char * equiv;
38: } rule;
39:
2.15 ! luotonen 40: /* Global variables (these will be obsolite once I put exec rule in)
2.12 luotonen 41: ** ----------------
42: */
43: PUBLIC char *HTBinDir = NULL; /* Physical /htbin directory path. */
44: /* In future this should not be global. */
2.13 luotonen 45: PUBLIC char *HTSearchScript = NULL; /* Search script name. */
2.12 luotonen 46:
2.13 luotonen 47:
2.1 timbl 48: /* Module-wide variables
49: ** ---------------------
50: */
51:
52: PRIVATE rule * rules = 0; /* Pointer to first on list */
53: #ifndef PUT_ON_HEAD
54: PRIVATE rule * rule_tail = 0; /* Pointer to last on list */
55: #endif
56:
2.11 luotonen 57:
2.1 timbl 58: /* Add rule to the list HTAddRule()
59: ** --------------------
60: **
61: ** On entry,
62: ** pattern points to 0-terminated string containing a single "*"
63: ** equiv points to the equivalent string with * for the
64: ** place where the text matched by * goes.
65: ** On exit,
66: ** returns 0 if success, -1 if error.
67: */
2.9 secret 68:
2.15 ! luotonen 69: PUBLIC int HTAddRule ARGS3(HTRuleOp, op,
! 70: CONST char *, pattern,
! 71: CONST char *, equiv)
2.9 secret 72: { /* BYTE_ADDRESSING removed and memory check - AS - 1 Sep 93 */
73: rule * temp;
74: char * pPattern;
75:
76: temp = (rule *)malloc(sizeof(*temp));
77: if (temp==NULL)
78: outofmem(__FILE__, "HTAddRule");
79: pPattern = (char *)malloc(strlen(pattern)+1);
80: if (pPattern==NULL)
81: outofmem(__FILE__, "HTAddRule");
2.1 timbl 82: if (equiv) { /* Two operands */
83: char * pEquiv = (char *)malloc(strlen(equiv)+1);
2.9 secret 84: if (pEquiv==NULL)
85: outofmem(__FILE__, "HTAddRule");
2.1 timbl 86: temp->equiv = pEquiv;
87: strcpy(pEquiv, equiv);
88: } else {
89: temp->equiv = 0;
90: }
91: temp->pattern = pPattern;
92: temp->op = op;
93:
94: strcpy(pPattern, pattern);
2.10 duns 95: if (TRACE) {
96: if (equiv)
97: printf("Rule: For `%s' op %d `%s'\n", pattern, op, equiv);
98: else
99: printf("Rule: For `%s' op %d\n", pattern, op);
100: }
2.1 timbl 101:
102: #ifdef PUT_ON_HEAD
103: temp->next = rules;
104: rules = temp;
105: #else
106: temp->next = 0;
107: if (rule_tail) rule_tail->next = temp;
108: else rules = temp;
109: rule_tail = temp;
110: #endif
111:
112:
113: return 0;
114: }
115:
116:
117: /* Clear all rules HTClearRules()
118: ** ---------------
119: **
120: ** On exit,
121: ** There are no rules
122: ** returns 0 if success, -1 if error.
123: **
124: ** See also
125: ** HTAddRule()
126: */
2.15 ! luotonen 127: PUBLIC int HTClearRules NOARGS
2.1 timbl 128: {
129: while (rules) {
130: rule * temp = rules;
131: rules = temp->next;
132: free(temp->pattern);
133: free(temp->equiv);
134: free(temp);
135: }
136: #ifndef PUT_ON_HEAD
137: rule_tail = 0;
138: #endif
139:
140: return 0;
141: }
142:
143:
144: /* Translate by rules HTTranslate()
145: ** ------------------
146: **
2.15 ! luotonen 147: ** ATTENTION:
! 148: ** THIS FUNCTION HAS BEEN OBSOLITED BY HTTranslateReq()
! 149: ** ON SERVER SIDE -- ON BROWSER SIDE THIS IS STILL USED!
! 150: ** Don't add new server features to this, this already has
! 151: ** more than it can handle cleanly.
! 152: **
! 153: ** The most recently defined rules are applied last.
2.1 timbl 154: **
155: ** On entry,
156: ** required points to a string whose equivalent value is neeed
157: ** On exit,
158: ** returns the address of the equivalent string allocated from
159: ** the heap which the CALLER MUST FREE. If no translation
160: ** occured, then it is a copy of te original.
2.11 luotonen 161: ** NEW FEATURES:
162: ** When a "protect" or "defprot" rule is mathed,
163: ** a call to HTAA_setCurrentProtection() or
164: ** HTAA_setDefaultProtection() is made to notify
165: ** the Access Authorization module that the file is
166: ** protected, and so it knows how to handle it.
167: ** -- AL
2.1 timbl 168: */
2.15 ! luotonen 169: PUBLIC char * HTTranslate ARGS1(CONST char *, required)
2.1 timbl 170: {
171: rule * r;
2.11 luotonen 172: char *current = NULL;
173: StrAllocCopy(current, required);
174:
2.15 ! luotonen 175: #ifdef OLD_CODE
2.11 luotonen 176: HTAA_clearProtections(); /* Reset from previous call -- AL */
2.15 ! luotonen 177: #endif
2.11 luotonen 178:
2.1 timbl 179: for(r = rules; r; r = r->next) {
180: char * p = r->pattern;
2.11 luotonen 181: int m=0; /* Number of characters matched against wildcard */
2.1 timbl 182: CONST char * q = current;
183: for(;*p && *q; p++, q++) { /* Find first mismatch */
184: if (*p!=*q) break;
185: }
186:
187: if (*p == '*') { /* Match up to wildcard */
188: m = strlen(q) - strlen(p+1); /* Amount to match to wildcard */
189: if(m<0) continue; /* tail is too short to match */
190: if (0!=strcmp(q+m, p+1)) continue; /* Tail mismatch */
191: } else /* Not wildcard */
192: if (*p != *q) continue; /* plain mismatch: go to next rule */
193:
194: switch (r->op) { /* Perform operation */
2.11 luotonen 195:
196: #ifdef ACCESS_AUTH
197: case HT_DefProt:
198: case HT_Protect:
199: {
200: char *local_copy = NULL;
201: char *p;
202: char *eff_ids = NULL;
203: char *prot_file = NULL;
204:
205: if (TRACE) fprintf(stderr,
206: "HTRule: `%s' matched %s %s: `%s'\n",
207: current,
208: (r->op==HT_Protect ? "Protect" : "DefProt"),
209: "rule, setup",
210: (r->equiv ? r->equiv :
211: (r->op==HT_Protect ?"DEFAULT" :"NULL!!")));
212:
213: if (r->equiv) {
214: StrAllocCopy(local_copy, r->equiv);
215: p = local_copy;
216: prot_file = HTNextField(&p);
217: eff_ids = HTNextField(&p);
218: }
219:
2.15 ! luotonen 220: #ifdef THESE_NO_LONGER_WORK
2.11 luotonen 221: if (r->op == HT_Protect)
222: HTAA_setCurrentProtection(current, prot_file, eff_ids);
223: else
224: HTAA_setDefaultProtection(current, prot_file, eff_ids);
2.15 ! luotonen 225: #endif
2.11 luotonen 226: FREE(local_copy);
227:
228: /* continue translating rules */
229: }
230: break;
231: #endif ACCESS_AUTH
232:
2.1 timbl 233: case HT_Pass: /* Authorised */
234: if (!r->equiv) {
235: if (TRACE) printf("HTRule: Pass `%s'\n", current);
236: return current;
237: }
2.11 luotonen 238: /* Else fall through ...to map and pass */
2.1 timbl 239:
240: case HT_Map:
241: if (*p == *q) { /* End of both strings, no wildcard */
242: if (TRACE) printf(
243: "For `%s' using `%s'\n", current, r->equiv);
244: StrAllocCopy(current, r->equiv); /* use entire translation */
245: } else {
246: char * ins = strchr(r->equiv, '*'); /* Insertion point */
247: if (ins) { /* Consistent rule!!! */
248: char * temp = (char *)malloc(
249: strlen(r->equiv)-1 + m + 1);
2.9 secret 250: if (temp==NULL)
251: outofmem(__FILE__, "HTTranslate"); /* NT & AS */
2.1 timbl 252: strncpy(temp, r->equiv, ins-r->equiv);
253: /* Note: temp may be unterminated now! */
254: strncpy(temp+(ins-r->equiv), q, m); /* Matched bit */
255: strcpy (temp+(ins-r->equiv)+m, ins+1); /* Last bit */
256: if (TRACE) printf("For `%s' using `%s'\n",
257: current, temp);
258: free(current);
259: current = temp; /* Use this */
260:
261: } else { /* No insertion point */
262: char * temp = (char *)malloc(strlen(r->equiv)+1);
2.9 secret 263: if (temp==NULL)
264: outofmem(__FILE__, "HTTranslate"); /* NT & AS */
2.1 timbl 265: strcpy(temp, r->equiv);
266: if (TRACE) printf("For `%s' using `%s'\n",
267: current, temp);
268: free(current);
269: current = temp; /* Use this */
270: } /* If no insertion point exists */
271: }
272: if (r->op == HT_Pass) {
273: if (TRACE) printf("HTRule: ...and pass `%s'\n", current);
274: return current;
275: }
276: break;
277:
2.15 ! luotonen 278: case HT_Exec:
2.11 luotonen 279: case HT_Invalid:
280: case HT_Fail: /* Unauthorised */
2.15 ! luotonen 281: default:
2.1 timbl 282: if (TRACE) printf("HTRule: *** FAIL `%s'\n", current);
283: return (char *)0;
284:
2.11 luotonen 285: } /* if tail matches ... switch operation */
2.1 timbl 286:
287: } /* loop over rules */
288:
289:
290: return current;
291: }
292:
2.15 ! luotonen 293:
! 294:
! 295: /* Translate by rules HTTranslate()
! 296: ** ------------------
! 297: **
! 298: ** On entry,
! 299: ** req request structure.
! 300: ** req->simplified simplified pathname (no ..'s etc in it),
! 301: ** which will be translated.
! 302: ** If this starts with /htbin/ it is taken
! 303: ** to be a script call request.
! 304: **
! 305: ** On exit,
! 306: ** returns YES on success, NO on failure (Forbidden).
! 307: ** req->translated contains the translated filename;
! 308: ** NULL if a script call.
! 309: ** req->script contains the executable script name;
! 310: ** NULL if not a script call.
! 311: */
! 312: PUBLIC BOOL HTTranslateReq ARGS1(HTRequest *, req)
! 313: {
! 314: rule * r;
! 315: char *current = NULL;
! 316:
! 317: if (!req || !req->simplified)
! 318: return NO;
! 319:
! 320: current = strdup(req->simplified);
! 321:
! 322: #ifdef OLD_CODE
! 323: if (0 == strncmp(current, "/htbin/", 7)) {
! 324: if (!HTBinDir) {
! 325: req->reason = HTAA_HTBIN;
! 326: return NO;
! 327: }
! 328: else {
! 329: char *end = strchr(current + 7, '/');
! 330: if (end)
! 331: *end = (char)0;
! 332: req->script=(char*)malloc(strlen(HTBinDir)+strlen(current)+1);
! 333: strcpy(req->script, HTBinDir);
! 334: strcat(req->script, current + 6);
! 335: if (end) {
! 336: *end = '/'; /* Reconstruct */
! 337: req->script_pathinfo = strdup(end); /* @@@@ This should */
! 338: /* be translated !! */
! 339: }
! 340: free(current);
! 341: return YES;
! 342: }
! 343: }
! 344: #endif /*OLD_CODE*/
! 345:
! 346: for(r = rules; r; r = r->next) {
! 347: char * p = r->pattern;
! 348: int m=0; /* Number of characters matched against wildcard */
! 349: CONST char * q = current;
! 350: for(;*p && *q; p++, q++) { /* Find first mismatch */
! 351: if (*p!=*q) break;
! 352: }
! 353:
! 354: if (*p == '*') { /* Match up to wildcard */
! 355: m = strlen(q) - strlen(p+1); /* Amount to match to wildcard */
! 356: if(m<0) continue; /* tail is too short to match */
! 357: if (0!=strcmp(q+m, p+1)) continue; /* Tail mismatch */
! 358: } else /* Not wildcard */
! 359: if (*p != *q) continue; /* plain mismatch: go to next rule */
! 360:
! 361: switch (r->op) { /* Perform operation */
! 362:
! 363: #ifdef ACCESS_AUTH
! 364: case HT_DefProt:
! 365: case HT_Protect:
! 366: {
! 367: char *local_copy = NULL;
! 368: char *p;
! 369: char *eff_ids = NULL;
! 370: char *prot_file = NULL;
! 371:
! 372: if (TRACE) fprintf(stderr,
! 373: "HTRule: `%s' matched %s %s: `%s'\n",
! 374: current,
! 375: (r->op==HT_Protect ? "Protect" : "DefProt"),
! 376: "rule, setup",
! 377: (r->equiv ? r->equiv :
! 378: (r->op==HT_Protect ?"DEFAULT" :"NULL!!")));
! 379:
! 380: if (r->equiv) {
! 381: StrAllocCopy(local_copy, r->equiv);
! 382: p = local_copy;
! 383: prot_file = HTNextField(&p);
! 384: eff_ids = HTNextField(&p);
! 385: }
! 386:
! 387: if (r->op == HT_Protect)
! 388: HTAA_setCurrentProtection(req, prot_file, eff_ids);
! 389: else
! 390: HTAA_setDefaultProtection(req, prot_file, eff_ids);
! 391:
! 392: FREE(local_copy);
! 393:
! 394: /* continue translating rules */
! 395: }
! 396: break;
! 397: #endif ACCESS_AUTH
! 398:
! 399: case HT_Exec:
! 400: if (!r->equiv) {
! 401: if (TRACE) fprintf(stderr,
! 402: "HTRule: Exec `%s', no extra pathinfo\n",
! 403: current);
! 404: req->script = current;
! 405: req->script_pathinfo = NULL;
! 406: return YES;
! 407: }
! 408: else if (*p == *q || !strchr(r->equiv, '*')) { /* No wildcards */
! 409: if (TRACE) fprintf(stderr,
! 410: "HTRule: Exec `%s', no extra pathinfo\n",
! 411: r->equiv);
! 412: StrAllocCopy(req->script, r->equiv);
! 413: req->script_pathinfo = NULL;
! 414: return YES;
! 415: }
! 416: else {
! 417: char *ins = strchr(r->equiv, '*');
! 418: char *pathinfo;
! 419: if (!(req->script = (char*)malloc(strlen(r->equiv) + m)))
! 420: outofmem(__FILE__, "HTTranslate");
! 421: strncpy(req->script, r->equiv, ins-r->equiv);
! 422: strncpy(req->script+(ins-r->equiv), q, m);
! 423: strcpy(req->script+(ins-r->equiv)+m, ins+1);
! 424: for (pathinfo = req->script+(ins-r->equiv)+1;
! 425: *pathinfo && *pathinfo != '/';
! 426: pathinfo++)
! 427: ;
! 428: if (*pathinfo) {
! 429: StrAllocCopy(req->script_pathinfo, pathinfo);
! 430: *pathinfo = 0;
! 431: }
! 432: return YES;
! 433: }
! 434: break;
! 435:
! 436: case HT_Pass: /* Authorised */
! 437: if (!r->equiv) {
! 438: if (TRACE) fprintf(stderr, "HTRule: Pass `%s'\n", current);
! 439: req->translated = current;
! 440: return YES;
! 441: }
! 442: /* Else fall through ...to map and pass */
! 443:
! 444: case HT_Map:
! 445: if (*p == *q) { /* End of both strings, no wildcard */
! 446: if (TRACE) printf(
! 447: "For `%s' using `%s'\n", current, r->equiv);
! 448: StrAllocCopy(current, r->equiv); /* use entire translation */
! 449: } else {
! 450: char * ins = strchr(r->equiv, '*'); /* Insertion point */
! 451: if (ins) { /* Consistent rule!!! */
! 452: char * temp = (char *)malloc(
! 453: strlen(r->equiv)-1 + m + 1);
! 454: if (temp==NULL)
! 455: outofmem(__FILE__, "HTTranslate"); /* NT & AS */
! 456: strncpy(temp, r->equiv, ins-r->equiv);
! 457: /* Note: temp may be unterminated now! */
! 458: strncpy(temp+(ins-r->equiv), q, m); /* Matched bit */
! 459: strcpy (temp+(ins-r->equiv)+m, ins+1); /* Last bit */
! 460: if (TRACE) printf("For `%s' using `%s'\n",
! 461: current, temp);
! 462: free(current);
! 463: current = temp; /* Use this */
! 464:
! 465: } else { /* No insertion point */
! 466: char * temp = (char *)malloc(strlen(r->equiv)+1);
! 467: if (temp==NULL)
! 468: outofmem(__FILE__, "HTTranslate"); /* NT & AS */
! 469: strcpy(temp, r->equiv);
! 470: if (TRACE) printf("For `%s' using `%s'\n",
! 471: current, temp);
! 472: free(current);
! 473: current = temp; /* Use this */
! 474: } /* If no insertion point exists */
! 475: }
! 476: if (r->op == HT_Pass) {
! 477: if (TRACE) fprintf(stderr, "HTRule: Pass `%s'\n", current);
! 478: req->translated = current;
! 479: return YES;
! 480: }
! 481: break;
! 482:
! 483: case HT_Invalid:
! 484: case HT_Fail: /* Unauthorised */
! 485: if (TRACE) printf("HTRule: *** FAIL `%s'\n", current);
! 486: return NO;
! 487: break;
! 488: } /* if tail matches ... switch operation */
! 489:
! 490: } /* loop over rules */
! 491:
! 492: /* Actually here failing might be more appropriate?? */
! 493: req->translated = current;
! 494: return YES;
! 495: }
! 496:
! 497:
! 498:
2.7 timbl 499: /* Load one line of configuration
500: ** ------------------------------
501: **
502: ** Call this, for example, to load a X resource with config info.
503: **
504: ** returns 0 OK, < 0 syntax error.
505: */
2.15 ! luotonen 506: PUBLIC int HTSetConfiguration ARGS1(CONST char *, config)
2.7 timbl 507: {
508: HTRuleOp op;
509: char * line = NULL;
510: char * pointer = line;
511: char *word1, *word2, *word3;
512: float quality, secs, secs_per_byte;
513: int status;
514:
515: StrAllocCopy(line, config);
516: {
517: char * p = strchr(line, '#'); /* Chop off comments */
518: if (p) *p = 0;
519: }
520: pointer = line;
521: word1 = HTNextField(&pointer);
522: if (!word1) {
523: free(line);
524: return 0;
525: } ; /* Comment only or blank */
2.11 luotonen 526:
2.7 timbl 527: word2 = HTNextField(&pointer);
2.11 luotonen 528:
529: if (0==strcasecomp(word1, "defprot") ||
530: 0==strcasecomp(word1, "protect"))
531: word3 = pointer; /* The rest of the line to be parsed by AA module */
532: else
533: word3 = HTNextField(&pointer); /* Just the next word */
534:
2.7 timbl 535: if (!word2) {
536: fprintf(stderr, "HTRule: Insufficient operands: %s\n", line);
537: free(line);
538: return -2; /*syntax error */
539: }
540:
541: if (0==strcasecomp(word1, "suffix")) {
2.8 timbl 542: char * encoding = HTNextField(&pointer);
543: if (pointer) status = sscanf(pointer, "%f", &quality);
544: else status = 0;
545: HTSetSuffix(word2, word3,
546: encoding ? encoding : "binary",
547: status >= 1? quality : 1.0);
2.7 timbl 548:
549: } else if (0==strcasecomp(word1, "presentation")) {
2.8 timbl 550: if (pointer) status = sscanf(pointer, "%f%f%f",
551: &quality, &secs, &secs_per_byte);
552: else status = 0;
2.14 timbl 553: if (!HTConversions) HTConversions = HTList_new();
554: HTSetPresentation(HTConversions, word2, word3,
2.7 timbl 555: status >= 1? quality : 1.0,
2.11 luotonen 556: status >= 2 ? secs : 0.0,
2.7 timbl 557: status >= 3 ? secs_per_byte : 0.0 );
2.12 luotonen 558:
2.13 luotonen 559: } else if (0==strncasecomp(word1, "htbin", 5) ||
560: 0==strncasecomp(word1, "bindir", 6)) {
2.15 ! luotonen 561: char *bindir = (char*)malloc(strlen(word2) + 3);
! 562: if (!bindir) outofmem(__FILE__, "HTSetConfiguration");
! 563: strcpy(bindir, word2);
! 564: strcat(bindir, "/*");
! 565: HTAddRule(HT_Exec, "/htbin/*", bindir);
! 566:
! 567: /*
! 568: ** Physical /htbin location -- this is almost obsolite
! 569: ** (only search may need it).
! 570: */
! 571: StrAllocCopy(HTBinDir, word2);
2.13 luotonen 572:
573: } else if (0==strncasecomp(word1, "search", 6)) {
2.15 ! luotonen 574: if (strchr(word2, '/'))
! 575: StrAllocCopy(HTSearchScript, word2); /* Full search script path */
! 576: else if (HTBinDir) {
! 577: if (!(HTSearchScript =
! 578: (char*)malloc(strlen(HTBinDir) + strlen(word2) + 2)))
! 579: outofmem(__FILE__, "HTSetConfiguration");
! 580: strcpy(HTSearchScript, HTBinDir);
! 581: strcat(HTSearchScript, "/");
! 582: strcat(HTSearchScript, word2);
! 583: }
! 584: else if (TRACE) fprintf(stderr,
! 585: "HTRule: Search rule without HTBin rule before ignored\n");
! 586: if (TRACE) {
! 587: if (HTSearchScript)
! 588: fprintf(stderr, "HTRule: Search script set to `%s'\n",
! 589: HTSearchScript);
! 590: else fprintf(stderr, "HTRule: Search script not set\n");
! 591: }
2.12 luotonen 592:
2.7 timbl 593: } else {
594: op = 0==strcasecomp(word1, "map") ? HT_Map
595: : 0==strcasecomp(word1, "pass") ? HT_Pass
596: : 0==strcasecomp(word1, "fail") ? HT_Fail
2.11 luotonen 597: : 0==strcasecomp(word1, "defprot") ? HT_DefProt
598: : 0==strcasecomp(word1, "protect") ? HT_Protect
2.7 timbl 599: : HT_Invalid;
600: if (op==HT_Invalid) {
601: fprintf(stderr, "HTRule: Bad rule `%s'\n", config);
602: } else {
603: HTAddRule(op, word2, word3);
604: }
605: }
606: free(line);
607: return 0;
608: }
609:
2.1 timbl 610:
2.11 luotonen 611: /* Load the rules from a file HTLoadRules()
2.1 timbl 612: ** --------------------------
613: **
614: ** On entry,
615: ** Rules can be in any state
616: ** On exit,
617: ** Any existing rules will have been kept.
2.7 timbl 618: ** Any new rules will have been loaded.
619: ** Returns 0 if no error, 0 if error!
2.1 timbl 620: **
621: ** Bugs:
622: ** The strings may not contain spaces.
623: */
624:
625: int HTLoadRules ARGS1(CONST char *, filename)
626: {
627: FILE * fp = fopen(filename, "r");
628: char line[LINE_LENGTH+1];
629:
630: if (!fp) {
631: if (TRACE) printf("HTRules: Can't open rules file %s\n", filename);
632: return -1; /* File open error */
633: }
634: for(;;) {
635: if (!fgets(line, LINE_LENGTH+1, fp)) break; /* EOF or error */
2.7 timbl 636: (void) HTSetConfiguration(line);
2.1 timbl 637: }
638: fclose(fp);
2.7 timbl 639: return 0; /* No error or syntax errors ignored */
2.1 timbl 640: }
2.11 luotonen 641:
642:
Webmaster