Mercurial > dnsbl
annotate src/context.cpp @ 86:c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
author | carl |
---|---|
date | Tue, 19 Jul 2005 22:47:15 -0700 |
parents | fa47e1e401f1 |
children | 7245c45cef7a |
rev | line source |
---|---|
72 | 1 /* |
2 | |
3 Copyright (c) 2004 Carl Byington - 510 Software Group, released under | |
4 the GPL version 2 or any later version at your choice available at | |
5 http://www.fsf.org/licenses/gpl.txt | |
6 | |
7 */ | |
8 | |
9 #include "includes.h" | |
71 | 10 |
73 | 11 static char* context_version="$Id$"; |
71 | 12 |
13 char *token_black; | |
14 char *token_content; | |
15 char *token_context; | |
16 char *token_dccfrom; | |
17 char *token_dccto; | |
18 char *token_default; | |
19 char *token_dnsbl; | |
20 char *token_dnsbll; | |
21 char *token_envfrom; | |
22 char *token_envto; | |
23 char *token_filter; | |
24 char *token_host_limit; | |
25 char *token_html_limit; | |
26 char *token_html_tags; | |
27 char *token_ignore; | |
28 char *token_include; | |
29 char *token_inherit; | |
30 char *token_lbrace; | |
75 | 31 char *token_mailhost; |
71 | 32 char *token_many; |
33 char *token_off; | |
75 | 34 char *token_ok2; |
71 | 35 char *token_ok; |
36 char *token_on; | |
37 char *token_rbrace; | |
38 char *token_semi; | |
39 char *token_soft; | |
75 | 40 char *token_substitute; |
71 | 41 char *token_tld; |
42 char *token_unknown; | |
43 char *token_white; | |
44 | |
45 string_set all_strings; // owns all the strings, only modified by the config loader thread | |
75 | 46 const int maxlen = 1000; |
71 | 47 |
48 DNSBL::DNSBL(char *n, char *s, char *m) { | |
49 name = n; | |
50 suffix = s; | |
51 message = m; | |
52 } | |
53 | |
54 | |
86
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
55 bool DNSBL::operator==(const DNSBL &rhs) { |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
56 return (strcmp(name, rhs.name) == 0) && |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
57 (strcmp(suffix, rhs.suffix) == 0) && |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
58 (strcmp(message, rhs.message) == 0); |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
59 } |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
60 |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
61 |
71 | 62 CONFIG::CONFIG() { |
63 reference_count = 0; | |
64 generation = 0; | |
65 load_time = 0; | |
66 default_context = NULL; | |
67 } | |
68 | |
69 | |
70 CONFIG::~CONFIG() { | |
71 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { | |
72 CONTEXT *c = *i; | |
73 delete c; | |
74 } | |
75 } | |
76 | |
77 | |
78 void CONFIG::add_context(CONTEXTP con) { | |
79 contexts.push_back(con); | |
80 if (!default_context && !con->get_parent()) { | |
81 // first global context | |
82 default_context = con; | |
83 } | |
84 } | |
85 | |
86 | |
75 | 87 void CONFIG::add_to(char *to, CONTEXTP con) { |
88 context_map::iterator i = env_to.find(to); | |
71 | 89 if (i != env_to.end()) { |
76 | 90 CONTEXTP c = (*i).second; |
91 int s = strlen(to); | |
92 bool at = s && (to[s-1] == '@'); | |
93 if (at && con->is_parent(c->get_parent())) { | |
94 if (debug_syslog) { | |
95 char oldname[maxlen]; | |
96 char newname[maxlen]; | |
97 char *oldn = c->get_full_name(oldname, maxlen); | |
98 char *newn = con->get_full_name(newname, maxlen); | |
99 char buf[maxlen*3]; | |
100 snprintf(buf, maxlen*3, "both %s and %s claim envelope to %s, the first one wins", oldn, newn, to); | |
101 my_syslog(buf); | |
102 } | |
103 return; // don't take over user@ entries from your ancestors children | |
104 } | |
75 | 105 if ((c != con) && (c != con->get_parent())) { |
86
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
106 if (debug_syslog) { |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
107 char oldname[maxlen]; |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
108 char newname[maxlen]; |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
109 char *oldn = c->get_full_name(oldname, maxlen); |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
110 char *newn = con->get_full_name(newname, maxlen); |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
111 char buf[maxlen*3]; |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
112 snprintf(buf, maxlen*3, "both %s and %s claim envelope to %s, the second one wins", oldn, newn, to); |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
113 my_syslog(buf); |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
114 } |
75 | 115 } |
71 | 116 } |
75 | 117 env_to[to] = con; |
118 } | |
119 | |
120 | |
121 CONTEXTP CONFIG::find_context(char *to) { | |
122 context_map::iterator i = env_to.find(to); | |
123 if (i != env_to.end()) return (*i).second; // found user@domain.tld key | |
71 | 124 char *x = strchr(to, '@'); |
125 if (x) { | |
126 x++; | |
127 i = env_to.find(x); | |
75 | 128 if (i != env_to.end()) return (*i).second; // found domain.tld key |
129 char y = *x; | |
130 *x = '\0'; | |
131 i = env_to.find(to); | |
132 *x = y; | |
133 if (i != env_to.end()) return (*i).second; // found user@ key | |
71 | 134 } |
75 | 135 return default_context; |
71 | 136 } |
137 | |
138 | |
139 void CONFIG::dump() { | |
140 if (default_context) default_context->dump(); | |
141 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { | |
142 CONTEXTP c = *i; | |
143 CONTEXTP p = c->get_parent(); | |
144 if (!p && (c != default_context)) c->dump(); | |
145 } | |
75 | 146 char buf[maxlen]; |
147 for (context_map::iterator i=env_to.begin(); i!=env_to.end(); i++) { | |
148 char *to = (*i).first; | |
149 CONTEXTP con = (*i).second; | |
150 printf("// envelope to %s \t-> context %s \n", to, con->get_full_name(buf,maxlen)); | |
151 } | |
71 | 152 } |
153 | |
154 | |
155 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) { | |
156 parent = parent_; | |
157 name = name_; | |
158 env_from_default = (parent) ? token_inherit : token_unknown; | |
159 content_filtering = (parent) ? parent->content_filtering : false; | |
160 content_suffix = NULL; | |
161 content_message = NULL; | |
75 | 162 host_limit = (parent) ? parent->host_limit : 0; |
71 | 163 host_limit_message = NULL; |
75 | 164 host_random = (parent) ? parent->host_random : false; |
165 tag_limit = (parent) ? parent->tag_limit : 0; | |
71 | 166 tag_limit_message = NULL; |
167 } | |
168 | |
169 | |
170 CONTEXT::~CONTEXT() { | |
171 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) { | |
172 DNSBLP d = (*i).second; | |
173 // delete the underlying DNSBL objects. | |
174 delete d; | |
175 } | |
176 } | |
177 | |
178 | |
76 | 179 bool CONTEXT::is_parent(CONTEXTP p) { |
180 if (p == parent) return true; | |
181 if (!parent) return false; | |
182 return parent->is_parent(p); | |
183 } | |
184 | |
185 | |
71 | 186 char *CONTEXT::get_full_name(char *buffer, int size) { |
187 if (!parent) return name; | |
188 char buf[maxlen]; | |
189 snprintf(buffer, size, "%s.%s", parent->get_full_name(buf, maxlen), name); | |
190 return buffer; | |
191 } | |
192 | |
193 | |
194 bool CONTEXT::cover_env_to(char *to) { | |
195 char buffer[maxlen]; | |
196 char *x = strchr(to, '@'); | |
197 if (x) x++; | |
198 else x = to; | |
75 | 199 if (*x == '\0') return true; // always allow covering addresses with no domain name, eg abuse@ |
71 | 200 string_set::iterator i = env_to.find(x); |
201 if (i != env_to.end()) return true; | |
75 | 202 return false; |
71 | 203 } |
204 | |
205 | |
206 char *CONTEXT::find_from(char *from) { | |
76 | 207 char *rc = token_inherit; |
71 | 208 string_map::iterator i = env_from.find(from); |
76 | 209 if (i != env_from.end()) rc = (*i).second; // found user@domain.tld key |
210 else { | |
211 char *x = strchr(from, '@'); | |
212 if (x) { | |
213 x++; | |
214 i = env_from.find(x); | |
215 if (i != env_from.end()) rc = (*i).second; // found domain.tld key | |
216 else { | |
217 char y = *x; | |
218 *x = '\0'; | |
219 i = env_from.find(from); | |
220 *x = y; | |
221 if (i != env_from.end()) rc = (*i).second; // found user@ key | |
222 } | |
223 } | |
71 | 224 } |
76 | 225 if (rc == token_inherit) rc = env_from_default; |
226 if ((rc == token_inherit) && parent) return parent->find_from(from); | |
227 return (rc == token_inherit) ? token_unknown : rc; | |
71 | 228 } |
229 | |
230 | |
75 | 231 CONTEXTP CONTEXT::find_context(char *from) { |
232 context_map::iterator i = env_from_context.find(from); | |
233 if (i != env_from_context.end()) return (*i).second; // found user@domain.tld key | |
71 | 234 char *x = strchr(from, '@'); |
235 if (x) { | |
236 x++; | |
75 | 237 i = env_from_context.find(x); |
238 if (i != env_from_context.end()) return (*i).second; // found domain.tld key | |
239 char y = *x; | |
240 *x = '\0'; | |
241 i = env_from_context.find(from); | |
242 *x = y; | |
243 if (i != env_from_context.end()) return (*i).second; // found user@ key | |
71 | 244 } |
245 return this; | |
246 } | |
247 | |
248 | |
249 CONTEXTP CONTEXT::find_from_context_name(char *name) { | |
250 context_map::iterator i = children.find(name); | |
251 if (i != children.end()) return (*i).second; | |
252 return NULL; | |
253 } | |
254 | |
255 | |
256 DNSBLP CONTEXT::find_dnsbl(char *name) { | |
257 dnsblp_map::iterator i = dnsbl_names.find(name); | |
258 if (i != dnsbl_names.end()) return (*i).second; | |
259 if (parent) return parent->find_dnsbl(name); | |
260 return NULL; | |
261 } | |
262 | |
263 | |
76 | 264 char* CONTEXT::get_content_suffix() { |
265 if (!content_suffix && parent) return parent->get_content_suffix(); | |
266 return content_suffix; | |
267 } | |
268 | |
269 | |
270 char* CONTEXT::get_content_message() { | |
271 if (!content_message && parent) return parent->get_content_message(); | |
272 return content_message; | |
273 } | |
274 | |
275 | |
276 string_set& CONTEXT::get_content_host_ignore() { | |
277 if (content_host_ignore.empty() && parent) return parent->get_content_host_ignore(); | |
278 return content_host_ignore; | |
279 } | |
280 | |
281 | |
282 string_set& CONTEXT::get_content_tlds() { | |
283 if (content_tlds.empty() && parent) return parent->get_content_tlds(); | |
284 return content_tlds; | |
285 } | |
286 | |
287 | |
288 string_set& CONTEXT::get_html_tags() { | |
289 if (html_tags.empty() && parent) return parent->get_html_tags(); | |
290 return html_tags; | |
291 } | |
292 | |
293 | |
294 dnsblp_list& CONTEXT::get_dnsbl_list() { | |
295 if (dnsbl_list.empty() && parent) return parent->get_dnsbl_list(); | |
296 return dnsbl_list; | |
297 } | |
298 | |
299 | |
72 | 300 bool CONTEXT::acceptable_content(recorder &memory, char *&msg) { |
301 if (memory.excessive_bad_tags(tag_limit)) { | |
302 msg = tag_limit_message; | |
303 return false; | |
304 } | |
305 if (!host_random && memory.excessive_hosts(host_limit)) { | |
306 msg = host_limit_message; | |
307 return false; | |
308 } | |
309 } | |
310 | |
311 | |
71 | 312 void CONTEXT::dump(int level) { |
313 char indent[maxlen]; | |
314 int i = min(maxlen-1, level*4); | |
315 memset(indent, ' ', i); | |
316 indent[i] = '\0'; | |
75 | 317 char buf[maxlen]; |
318 char *fullname = get_full_name(buf,maxlen); | |
319 printf("%s context %s { \t// %s\n", indent, name, fullname); | |
71 | 320 |
321 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) { | |
322 char *n = (*i).first; | |
323 DNSBL &d = *(*i).second; | |
324 printf("%s dnsbl %s %s \"%s\"; \n", indent, n, d.suffix, d.message); | |
325 } | |
326 | |
327 if (!dnsbl_list.empty()) { | |
328 printf("%s dnsbl_list", indent); | |
329 for (dnsblp_list::iterator i=dnsbl_list.begin(); i!=dnsbl_list.end(); i++) { | |
330 DNSBL &d = *(*i); | |
331 printf(" %s", d.name); | |
332 } | |
333 printf("; \n"); | |
334 } | |
335 | |
336 if (content_filtering) { | |
337 printf("%s content on { \n", indent, env_from_default); | |
338 if (content_suffix) { | |
339 printf("%s filter %s \"%s\"; \n", indent, content_suffix, content_message); | |
340 } | |
341 if (!content_host_ignore.empty()) { | |
342 printf("%s ignore { \n", indent); | |
343 for (string_set::iterator i=content_host_ignore.begin(); i!=content_host_ignore.end(); i++) { | |
344 printf("%s %s; \n", indent, *i); | |
345 } | |
346 printf("%s }; \n", indent); | |
347 } | |
348 if (!content_tlds.empty()) { | |
349 printf("%s tld { \n", indent); | |
350 printf("%s ", indent); | |
351 for (string_set::iterator i=content_tlds.begin(); i!=content_tlds.end(); i++) { | |
352 printf("%s; ", *i); | |
353 } | |
354 printf("\n%s }; \n", indent); | |
355 } | |
356 if (!html_tags.empty()) { | |
357 printf("%s html_tags { \n", indent); | |
358 printf("%s ", indent); | |
359 for (string_set::iterator i=html_tags.begin(); i!=html_tags.end(); i++) { | |
360 printf("%s; ", *i); | |
361 } | |
362 printf("\n%s }; \n", indent); | |
363 } | |
364 if (host_limit_message) { | |
365 printf("%s host_limit on %d \"%s\"; \n", indent, host_limit, host_limit_message); | |
366 } | |
367 else if (host_random) { | |
368 printf("%s host_limit soft %d; \n", indent, host_limit); | |
369 } | |
370 else { | |
371 printf("%s host_limit off; \n", indent); | |
372 } | |
373 if (tag_limit_message) { | |
75 | 374 printf("%s html_limit on %d \"%s\"; \n", indent, tag_limit, tag_limit_message); |
71 | 375 } |
376 else { | |
75 | 377 printf("%s html_limit off; \n", indent); |
71 | 378 } |
379 printf("%s }; \n", indent); | |
380 } | |
381 else { | |
382 printf("%s content off {}; \n", indent, env_from_default); | |
383 } | |
384 | |
75 | 385 printf("%s env_to { \t// %s\n", indent, fullname); |
71 | 386 for (string_set::iterator i=env_to.begin(); i!=env_to.end(); i++) { |
387 printf("%s %s; \n", indent, *i); | |
388 } | |
389 printf("%s }; \n", indent); | |
390 | |
391 for (context_map::iterator i=children.begin(); i!=children.end(); i++) { | |
392 CONTEXTP c = (*i).second; | |
393 c->dump(level+1); | |
394 } | |
395 | |
75 | 396 printf("%s env_from %s { \t// %s\n", indent, env_from_default, fullname); |
71 | 397 if (!env_from.empty()) { |
398 printf("%s // white/black/unknown \n", indent); | |
399 for (string_map::iterator i=env_from.begin(); i!=env_from.end(); i++) { | |
400 char *f = (*i).first; | |
401 char *t = (*i).second; | |
75 | 402 printf("%s %s \t%s; \n", indent, f, t); |
71 | 403 } |
404 } | |
405 if (!env_from_context.empty()) { | |
406 printf("%s // child contexts \n", indent); | |
407 for (context_map::iterator j=env_from_context.begin(); j!=env_from_context.end(); j++) { | |
408 char *f = (*j).first; | |
409 CONTEXTP t = (*j).second; | |
75 | 410 printf("%s %s \t%s; \n", indent, f, t->name); |
71 | 411 } |
412 } | |
413 printf("%s }; \n", indent); | |
414 | |
415 printf("%s }; \n", indent); | |
416 } | |
417 | |
418 | |
419 //////////////////////////////////////////////// | |
420 // helper to discard the strings held by a string_set | |
421 // | |
74 | 422 void discard(string_set &s) { |
71 | 423 for (string_set::iterator i=s.begin(); i!=s.end(); i++) { |
424 free(*i); | |
425 } | |
426 s.clear(); | |
427 } | |
428 | |
429 | |
430 //////////////////////////////////////////////// | |
431 // helper to register a string in a string set | |
432 // | |
433 char* register_string(string_set &s, char *name) { | |
434 string_set::iterator i = s.find(name); | |
435 if (i != s.end()) return *i; | |
436 char *x = strdup(name); | |
437 s.insert(x); | |
438 return x; | |
439 } | |
440 | |
441 | |
442 //////////////////////////////////////////////// | |
443 // register a global string | |
444 // | |
445 char* register_string(char *name) { | |
446 return register_string(all_strings, name); | |
447 } | |
448 | |
449 | |
450 //////////////////////////////////////////////// | |
451 // | |
452 bool tsa(TOKEN &tok, char *token); | |
453 bool tsa(TOKEN &tok, char *token) { | |
454 char *have = tok.next(); | |
455 if (have == token) return true; | |
456 tok.token_error(token, have); | |
457 return false; | |
458 } | |
459 | |
460 | |
461 //////////////////////////////////////////////// | |
462 // | |
463 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me); | |
464 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | |
465 char *name = tok.next(); | |
466 char *suf = tok.next(); | |
467 char *msg = tok.next(); | |
468 if (!tsa(tok, token_semi)) return false; | |
86
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
469 DNSBLP dnsnew = new DNSBL(name, suf, msg); |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
470 DNSBLP dnsold = me.find_dnsbl(name); |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
471 if (dnsold && (*dnsold == *dnsnew)) { |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
472 // duplicate redefinition, ignore it |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
473 delete dnsnew; |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
474 return true; |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
475 } |
c1280cd3e248
add multiple debug syslog levels, remove duplicate dnsbl definitions
carl
parents:
82
diff
changeset
|
476 me.add_dnsbl(name, dnsnew); |
71 | 477 return true; |
478 } | |
479 | |
480 | |
481 //////////////////////////////////////////////// | |
482 // | |
483 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me); | |
484 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | |
485 while (true) { | |
486 char *have = tok.next(); | |
487 if (!have) break; | |
488 if (have == token_semi) break; | |
489 DNSBLP dns = me.find_dnsbl(have); | |
490 if (dns) { | |
491 me.add_dnsbl(dns); | |
492 } | |
493 else { | |
494 tok.token_error("dnsbl name", have); | |
495 return false; | |
496 } | |
497 } | |
498 return true; | |
499 } | |
500 | |
501 | |
502 //////////////////////////////////////////////// | |
503 // | |
504 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me); | |
505 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | |
506 char *setting = tok.next(); | |
507 if (setting == token_on) { | |
508 me.set_content_filtering(true); | |
509 } | |
510 else if (setting == token_off) { | |
511 me.set_content_filtering(false); | |
512 } | |
513 else { | |
514 tok.token_error("on/off", setting); | |
515 return false; | |
516 } | |
517 if (!tsa(tok, token_lbrace)) return false; | |
518 while (true) { | |
519 char *have = tok.next(); | |
520 if (!have) break; | |
521 if (have == token_filter) { | |
75 | 522 char *suffix = tok.next(); |
523 char *messag = tok.next(); | |
76 | 524 me.set_content_suffix(suffix); |
525 me.set_content_message(messag); | |
71 | 526 if (!tsa(tok, token_semi)) return false; |
527 } | |
528 else if (have == token_ignore) { | |
529 if (!tsa(tok, token_lbrace)) return false; | |
530 while (true) { | |
531 if (!have) break; | |
532 char *have = tok.next(); | |
76 | 533 if (have == token_rbrace) break; // done |
534 me.add_ignore(have); | |
71 | 535 } |
536 if (!tsa(tok, token_semi)) return false; | |
537 } | |
538 else if (have == token_tld) { | |
539 if (!tsa(tok, token_lbrace)) return false; | |
540 while (true) { | |
541 char *have = tok.next(); | |
542 if (!have) break; | |
76 | 543 if (have == token_rbrace) break; // done |
544 me.add_tld(have); | |
71 | 545 } |
546 if (!tsa(tok, token_semi)) return false; | |
547 } | |
548 else if (have == token_html_limit) { | |
549 have = tok.next(); | |
550 if (have == token_on) { | |
551 me.set_tag_limit(tok.nextint()); | |
552 me.set_tag_message(tok.next()); | |
553 } | |
554 else if (have == token_off) { | |
555 me.set_tag_limit(0); | |
556 me.set_tag_message(NULL); | |
557 } | |
558 else { | |
559 tok.token_error("on/off", have); | |
560 return false; | |
561 } | |
562 if (!tsa(tok, token_semi)) return false; | |
563 } | |
564 else if (have == token_html_tags) { | |
565 if (!tsa(tok, token_lbrace)) return false; | |
566 while (true) { | |
567 char *have = tok.next(); | |
568 if (!have) break; | |
569 if (have == token_rbrace) { | |
570 break; // done | |
571 } | |
572 else { | |
79 | 573 me.add_tag(have); // base version |
574 char buf[200]; | |
575 snprintf(buf, sizeof(buf), "/%s", have); | |
576 me.add_tag(register_string(buf)); // leading / | |
577 snprintf(buf, sizeof(buf), "%s/", have); | |
578 me.add_tag(register_string(buf)); // trailing / | |
71 | 579 } |
580 } | |
581 if (!tsa(tok, token_semi)) return false; | |
582 } | |
583 else if (have == token_host_limit) { | |
584 have = tok.next(); | |
585 if (have == token_on) { | |
586 me.set_host_limit(tok.nextint()); | |
587 me.set_host_message(tok.next()); | |
588 me.set_host_random(false); | |
589 } | |
590 else if (have == token_off) { | |
591 me.set_host_limit(0); | |
592 me.set_host_message(NULL); | |
593 me.set_host_random(false); | |
594 } | |
595 else if (have == token_soft) { | |
596 me.set_host_limit(tok.nextint()); | |
597 me.set_host_message(NULL); | |
598 me.set_host_random(true); | |
599 } | |
600 else { | |
601 tok.token_error("on/off/soft", have); | |
602 return false; | |
603 } | |
604 if (!tsa(tok, token_semi)) return false; | |
605 } | |
606 else if (have == token_rbrace) { | |
607 break; // done | |
608 } | |
609 else { | |
610 tok.token_error("content keyword", have); | |
611 return false; | |
612 } | |
613 } | |
614 return tsa(tok, token_semi); | |
615 } | |
616 | |
617 | |
618 //////////////////////////////////////////////// | |
619 // | |
620 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me); | |
621 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | |
622 if (!tsa(tok, token_lbrace)) return false; | |
623 while (true) { | |
624 char *have = tok.next(); | |
625 if (!have) break; | |
626 if (have == token_rbrace) break; | |
627 if (have == token_semi) { | |
628 // optional separators | |
629 } | |
630 else if (have == token_dccto) { | |
631 char *flavor = tok.next(); | |
632 if (!tsa(tok, token_lbrace)) return false; | |
633 bool keeping = false; | |
634 while (true) { | |
635 char *have = tok.next(); | |
636 if (!have) break; | |
637 if (have == token_rbrace) break; | |
638 if (have == flavor) { | |
639 keeping = true; | |
640 continue; | |
641 } | |
642 else if ((have == token_ok) || (have == token_ok2) || (have == token_many)) { | |
643 keeping = false; | |
644 continue; | |
645 } | |
646 if (have == token_envto) { | |
647 have = tok.next(); | |
648 if (keeping) { | |
649 if (me.allow_env_to(have)) { | |
650 me.add_to(have); | |
651 dc.add_to(have, &me); | |
652 } | |
653 } | |
654 } | |
75 | 655 else if (have == token_substitute) { |
656 if (tok.next() == token_mailhost) { | |
657 have = tok.next(); | |
658 if (keeping) { | |
659 if (me.allow_env_to(have)) { | |
660 me.add_to(have); | |
661 dc.add_to(have, &me); | |
662 } | |
663 } | |
664 } | |
665 } | |
71 | 666 tok.skipeol(); |
667 } | |
668 } | |
669 else if (me.allow_env_to(have)) { | |
670 me.add_to(have); | |
671 dc.add_to(have, &me); | |
672 } | |
673 else { | |
75 | 674 tok.token_error("user@ or user@domain.tld or domain.tld where domain.tld allowed by parent context", have); |
71 | 675 return false; |
676 } | |
677 } | |
678 return tsa(tok, token_semi); | |
679 } | |
680 | |
681 | |
682 //////////////////////////////////////////////// | |
683 // | |
684 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me); | |
685 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | |
686 char *st = tok.next(); | |
75 | 687 if ((st == token_black) || (st == token_white) || (st == token_unknown) || (st == token_inherit)) { |
71 | 688 me.set_from_default(st); |
689 } | |
690 else { | |
691 tok.push(st); | |
692 } | |
693 if (!tsa(tok, token_lbrace)) return false; | |
694 while (true) { | |
695 char *have = tok.next(); | |
696 if (!have) break; | |
697 if (have == token_rbrace) break; | |
698 if (have == token_semi) { | |
699 // optional separators | |
700 } | |
701 else if (have == token_dccfrom) { | |
702 if (!tsa(tok, token_lbrace)) return false; | |
703 bool keeping = false; | |
704 bool many = false; | |
705 while (true) { | |
706 char *have = tok.next(); | |
707 if (!have) break; | |
708 if (have == token_rbrace) break; | |
709 if (have == token_ok) { | |
710 keeping = true; | |
711 many = false; | |
712 continue; | |
713 } | |
714 else if (have == token_many) { | |
715 keeping = true; | |
716 many = true; | |
717 continue; | |
718 } | |
719 else if (have == token_ok2) { | |
720 keeping = false; | |
721 continue; | |
722 } | |
723 if (have == token_envfrom) { | |
724 have = tok.next(); | |
725 if (keeping) { | |
726 me.add_from(have, (many) ? token_black : token_white); | |
727 } | |
728 } | |
75 | 729 else if (have == token_substitute) { |
730 if (tok.next() == token_mailhost) { | |
731 have = tok.next(); | |
732 me.add_from(have, (many) ? token_black : token_white); | |
733 } | |
734 } | |
71 | 735 tok.skipeol(); |
736 } | |
737 } | |
738 else { | |
739 // may be a valid email address or domain name | |
740 char *st = tok.next(); | |
741 if ((st == token_black) || (st == token_white) || (st == token_unknown)) { | |
742 me.add_from(have, st); | |
743 } | |
744 else { | |
745 CONTEXTP con = me.find_from_context_name(st); | |
746 if (con) { | |
747 me.add_from_context(have, con); | |
748 } | |
749 else { | |
750 tok.token_error("white/black/unknown or child context name", st); | |
751 return false; | |
752 } | |
753 } | |
754 } | |
755 } | |
756 return tsa(tok, token_semi); | |
757 } | |
758 | |
759 | |
760 //////////////////////////////////////////////// | |
761 // | |
762 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent); | |
763 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent) { | |
764 char *name = tok.next(); | |
765 if (!tsa(tok, token_lbrace)) return false; | |
766 CONTEXTP con = new CONTEXT(parent, name); | |
767 | |
768 while (true) { | |
769 char *have = tok.next(); | |
770 if (!have) break; | |
771 if (have == token_rbrace) break; // done | |
772 if (have == token_dnsbl) { | |
773 if (!parse_dnsbl(tok, dc, *con)) return false; | |
774 } | |
775 else if (have == token_dnsbll) { | |
776 if (!parse_dnsbll(tok, dc, *con)) return false; | |
777 } | |
778 else if (have == token_content) { | |
779 if (!parse_content(tok, dc, *con)) return false; | |
780 } | |
781 else if (have == token_envto) { | |
782 if (!parse_envto(tok, dc, *con)) return false; | |
783 } | |
784 else if (have == token_envfrom) { | |
785 if (!parse_envfrom(tok, dc, *con)) return false; | |
786 } | |
787 else if (have == token_context) { | |
788 if (!parse_context(tok, dc, con)) return false; | |
789 } | |
790 else { | |
791 tok.token_error("context keyword", have); | |
792 return false; | |
793 } | |
794 } | |
795 | |
796 if (!tsa(tok, token_semi)) { | |
797 delete con; | |
798 return false; | |
799 } | |
800 dc.add_context(con); | |
801 if (parent) parent->add_context(con); | |
802 return true; | |
803 } | |
804 | |
805 | |
806 //////////////////////////////////////////////// | |
807 // parse a config file | |
808 // | |
809 bool load_conf(CONFIG &dc, char *fn) { | |
810 TOKEN tok(fn, &dc.config_files); | |
811 while (true) { | |
812 char *have = tok.next(); | |
813 if (!have) break; | |
814 if (have == token_context) { | |
815 if (!parse_context(tok, dc, NULL)) { | |
816 return false; | |
817 } | |
818 } | |
819 else { | |
820 tok.token_error(token_context, have); | |
821 return false; | |
822 } | |
823 } | |
72 | 824 return (dc.default_context) ? true : false; |
71 | 825 } |
826 | |
827 | |
828 //////////////////////////////////////////////// | |
829 // init the tokens | |
830 // | |
831 void token_init() { | |
832 token_black = register_string("black"); | |
833 token_content = register_string("content"); | |
834 token_context = register_string("context"); | |
835 token_dccfrom = register_string("dcc_from"); | |
836 token_dccto = register_string("dcc_to"); | |
837 token_default = register_string("default"); | |
838 token_dnsbl = register_string("dnsbl"); | |
839 token_dnsbll = register_string("dnsbl_list"); | |
840 token_envfrom = register_string("env_from"); | |
841 token_envto = register_string("env_to"); | |
842 token_filter = register_string("filter"); | |
843 token_host_limit = register_string("host_limit"); | |
844 token_html_limit = register_string("html_limit"); | |
845 token_html_tags = register_string("html_tags"); | |
846 token_ignore = register_string("ignore"); | |
847 token_include = register_string("include"); | |
848 token_inherit = register_string("inherit"); | |
849 token_lbrace = register_string("{"); | |
75 | 850 token_mailhost = register_string("mail_host"); |
71 | 851 token_many = register_string("many"); |
852 token_off = register_string("off"); | |
853 token_ok = register_string("ok"); | |
854 token_ok2 = register_string("ok2"); | |
855 token_on = register_string("on"); | |
856 token_rbrace = register_string("}"); | |
857 token_semi = register_string(";"); | |
858 token_soft = register_string("soft"); | |
75 | 859 token_substitute = register_string("substitute"); |
71 | 860 token_tld = register_string("tld"); |
861 token_unknown = register_string("unknown"); | |
862 token_white = register_string("white"); | |
863 } |