comparison src/context.cpp @ 192:8f4a9a37d4d9

delay autowhitelisting to avoid out of office reply bots
author carl
date Sun, 11 Nov 2007 12:49:25 -0800
parents 7a722f482bfb
children 797299e9fffc
comparison
equal deleted inserted replaced
191:2a67d31099c3 192:8f4a9a37d4d9
65 char *token_white; 65 char *token_white;
66 char *token_yes; 66 char *token_yes;
67 67
68 char *token_myhostname; 68 char *token_myhostname;
69 #ifndef HOST_NAME_MAX 69 #ifndef HOST_NAME_MAX
70 #define HOST_NAME_MAX 255 70 #define HOST_NAME_MAX 255
71 #endif 71 #endif
72 char myhostname[HOST_NAME_MAX+1]; 72 char myhostname[HOST_NAME_MAX+1];
73 73
74 pthread_mutex_t verifier_mutex; // protect the verifier map 74 pthread_mutex_t verifier_mutex; // protect the verifier map
75 verify_map verifiers; 75 verify_map verifiers;
76 76
77 pthread_mutex_t whitelister_mutex; // protect the whitelisters map 77 pthread_mutex_t whitelister_mutex; // protect the whitelisters map
78 whitelister_map whitelisters; 78 whitelister_map whitelisters;
79 79
80 string_set all_strings; // owns all the strings, only modified by the config loader thread 80 string_set all_strings; // owns all the strings, only modified by the config loader thread
81 const int maxlen = 1000; // used for snprintf buffers 81 const int maxlen = 1000; // used for snprintf buffers
82 const int maxsmtp_age = 60;// smtp verify sockets older than this are ancient 82 const int maxsmtp_age = 60;// smtp verify sockets older than this are ancient
83 const int maxauto_age = 600;// auto whitelister delay before flushing to file 83 const int maxauto_age = 600;// auto whitelister delay before flushing to file
84 extern int NULL_SOCKET; 84 extern int NULL_SOCKET;
85 const time_t ERROR_SMTP_SOCKET_TIME = 600; // number of seconds between attempts to open a socket to an smtp server 85 const time_t ERROR_SMTP_SOCKET_TIME = 600; // number of seconds between attempts to open a socket to an smtp server
86 86
87 87
88 int SMTP::writer() { 88 int SMTP::writer() {
89 #ifdef VERIFY_DEBUG 89 #ifdef VERIFY_DEBUG
90 log("writer() sees buffer with %s", buffer); 90 log("writer() sees buffer with %s", buffer);
91 log("writer() sees error %d", (int)error); 91 log("writer() sees error %d", (int)error);
92 #endif 92 #endif
93 int rs = 0; 93 int rs = 0;
94 if (!error) { 94 if (!error) {
95 int len = strlen(buffer); 95 int len = strlen(buffer);
96 while (rs < len) { 96 while (rs < len) {
97 int ws = write(fd, buffer+rs, len-rs); 97 int ws = write(fd, buffer+rs, len-rs);
98 if (ws > 0) { 98 if (ws > 0) {
99 rs += ws; 99 rs += ws;
100 } 100 }
101 else { 101 else {
102 // peer closed the socket! 102 // peer closed the socket!
103 rs = 0; 103 rs = 0;
104 error = true; 104 error = true;
105 break; 105 break;
106 } 106 }
107 } 107 }
108 } 108 }
109 return rs; 109 return rs;
110 } 110 }
111 111
112 112
113 int SMTP::reader() { 113 int SMTP::reader() {
114 // read some bytes terminated by lf or end of buffer. 114 // read some bytes terminated by lf or end of buffer.
115 // we may have a multi line response or part thereof in the buffer. 115 // we may have a multi line response or part thereof in the buffer.
116 #ifdef VERIFY_DEBUG 116 #ifdef VERIFY_DEBUG
117 log("reader() sees error %d", (int)error); 117 log("reader() sees error %d", (int)error);
118 #endif 118 #endif
119 if (error) return 0; 119 if (error) return 0;
120 int len = maxlen-1; // room for null terminator 120 int len = maxlen-1; // room for null terminator
121 while (pending < len) { 121 while (pending < len) {
122 int ws = read(fd, buffer+pending, len-pending); 122 int ws = read(fd, buffer+pending, len-pending);
123 if (ws > 0) { 123 if (ws > 0) {
124 pending += ws; 124 pending += ws;
125 if (buffer[pending-1] == '\n') break; 125 if (buffer[pending-1] == '\n') break;
126 } 126 }
127 else { 127 else {
128 // peer closed the socket! 128 // peer closed the socket!
129 pending = 0; 129 pending = 0;
130 error = true; 130 error = true;
131 break; 131 break;
132 } 132 }
133 } 133 }
134 buffer[pending] = '\0'; 134 buffer[pending] = '\0';
135 #ifdef VERIFY_DEBUG 135 #ifdef VERIFY_DEBUG
136 log("reader() sees buffer with %s", buffer); 136 log("reader() sees buffer with %s", buffer);
137 #endif 137 #endif
138 return pending; 138 return pending;
139 } 139 }
140 140
141 141
142 int SMTP::read_line() { 142 int SMTP::read_line() {
143 char *lf = strchr(buffer, '\n'); 143 char *lf = strchr(buffer, '\n');
144 if (!lf) { 144 if (!lf) {
145 reader(); // get a lf 145 reader(); // get a lf
146 lf = strchr(buffer, '\n'); 146 lf = strchr(buffer, '\n');
147 if (!lf) lf = buffer + pending - 1; 147 if (!lf) lf = buffer + pending - 1;
148 } 148 }
149 return (lf-buffer)+1; // number of bytes in this line 149 return (lf-buffer)+1; // number of bytes in this line
150 } 150 }
151 151
152 152
153 void SMTP::flush_line(int r) { 153 void SMTP::flush_line(int r) {
154 if (pending > r) memmove(buffer, buffer+r, pending-r); 154 if (pending > r) memmove(buffer, buffer+r, pending-r);
155 pending -= r; 155 pending -= r;
156 } 156 }
157 157
158 158
159 int SMTP::read_response() { 159 int SMTP::read_response() {
160 pending = 0; 160 pending = 0;
161 buffer[pending] = '\0'; 161 buffer[pending] = '\0';
162 while (true) { 162 while (true) {
163 int r = read_line(); 163 int r = read_line();
164 #ifdef VERIFY_DEBUG 164 #ifdef VERIFY_DEBUG
165 log("read_response() sees line with %s", buffer); 165 log("read_response() sees line with %s", buffer);
166 log("read_response() sees line length %d", r); 166 log("read_response() sees line length %d", r);
167 #endif 167 #endif
168 if (r == 0) return 0; // failed to read any bytes 168 if (r == 0) return 0; // failed to read any bytes
169 if ((r > 4) && (buffer[3] == '-')) { 169 if ((r > 4) && (buffer[3] == '-')) {
170 flush_line(r); 170 flush_line(r);
171 continue; 171 continue;
172 } 172 }
173 return atoi(buffer); 173 return atoi(buffer);
174 } 174 }
175 return 0; 175 return 0;
176 } 176 }
177 177
178 178
179 int SMTP::cmd(char *c) { 179 int SMTP::cmd(char *c) {
180 if (c) { 180 if (c) {
181 init(); 181 init();
182 append(c); 182 append(c);
183 } 183 }
184 append("\r\n"); 184 append("\r\n");
185 writer(); 185 writer();
186 return read_response(); 186 return read_response();
187 } 187 }
188 188
189 189
190 int SMTP::helo() { 190 int SMTP::helo() {
191 if (read_response() != 220) return 0; 191 if (read_response() != 220) return 0;
192 init(); 192 init();
193 append("HELO "); 193 append("HELO ");
194 append(token_myhostname); 194 append(token_myhostname);
195 return cmd(NULL); 195 return cmd(NULL);
196 } 196 }
197 197
198 198
199 int SMTP::rset() { 199 int SMTP::rset() {
200 int rc = cmd("RSET"); 200 int rc = cmd("RSET");
201 efrom[0] = '\0'; 201 efrom[0] = '\0';
202 return rc; 202 return rc;
203 } 203 }
204 204
205 205
206 int SMTP::from(char *f) { 206 int SMTP::from(char *f) {
207 // the mail from address was originally passed in from sendmail enclosed in 207 // the mail from address was originally passed in from sendmail enclosed in
208 // <>. to_lower_string() removed the <> and converted the rest to lowercase, 208 // <>. to_lower_string() removed the <> and converted the rest to lowercase,
209 // except in the case of an empty return path, which was left as the two 209 // except in the case of an empty return path, which was left as the two
210 // character string <>. 210 // character string <>.
211 if (strncmp(efrom, f, maxlen)) { 211 if (strncmp(efrom, f, maxlen)) {
212 rset(); 212 rset();
213 strncpy(efrom, f, maxlen); 213 strncpy(efrom, f, maxlen);
214 init(); 214 init();
215 append("MAIL FROM:<"); 215 append("MAIL FROM:<");
216 if (*f != '<') append(f); 216 if (*f != '<') append(f);
217 append(">"); 217 append(">");
218 return cmd(NULL); 218 return cmd(NULL);
219 } 219 }
220 return 250; // pretend it worked 220 return 250; // pretend it worked
221 } 221 }
222 222
223 223
224 int SMTP::rcpt(char *t) { 224 int SMTP::rcpt(char *t) {
225 init(); 225 init();
226 append("RCPT TO:<"); 226 append("RCPT TO:<");
227 append(t); 227 append(t);
228 append(">"); 228 append(">");
229 return cmd(NULL); 229 return cmd(NULL);
230 } 230 }
231 231
232 232
233 int SMTP::quit() { 233 int SMTP::quit() {
234 return cmd("QUIT"); 234 return cmd("QUIT");
235 } 235 }
236 236
237 237
238 void SMTP::closefd() { 238 void SMTP::closefd() {
239 shutdown(fd, SHUT_RDWR); 239 shutdown(fd, SHUT_RDWR);
240 close(fd); 240 close(fd);
241 } 241 }
242 242
243 243
244 #ifdef VERIFY_DEBUG 244 #ifdef VERIFY_DEBUG
245 void SMTP::log(char *m, int v) { 245 void SMTP::log(char *m, int v) {
246 char buf[maxlen]; 246 char buf[maxlen];
247 snprintf(buf, maxlen, m, v); 247 snprintf(buf, maxlen, m, v);
248 my_syslog(buf); 248 my_syslog(buf);
249 } 249 }
250 250
251 251
252 void SMTP::log(char *m, char *v) { 252 void SMTP::log(char *m, char *v) {
253 char buf[maxlen]; 253 char buf[maxlen];
254 snprintf(buf, maxlen, m, v); 254 snprintf(buf, maxlen, m, v);
255 my_syslog(buf); 255 my_syslog(buf);
256 } 256 }
257 #endif 257 #endif
258 258
259 259
260 //////////////////////////////////////////////// 260 ////////////////////////////////////////////////
261 // smtp verifier so backup mx machines can see the valid users 261 // smtp verifier so backup mx machines can see the valid users
262 // 262 //
263 VERIFY::VERIFY(char *h) { 263 VERIFY::VERIFY(char *h) {
264 host = h; 264 host = h;
265 last_err = 0; 265 last_err = 0;
266 pthread_mutex_init(&mutex, 0); 266 pthread_mutex_init(&mutex, 0);
267 } 267 }
268 268
269 269
270 void VERIFY::closer() { 270 void VERIFY::closer() {
271 bool ok = true; 271 bool ok = true;
272 while (ok) { 272 while (ok) {
273 SMTP *conn = NULL; 273 SMTP *conn = NULL;
274 pthread_mutex_lock(&mutex); 274 pthread_mutex_lock(&mutex);
275 if (connections.empty()) { 275 if (connections.empty()) {
276 ok = false; 276 ok = false;
277 } 277 }
278 else { 278 else {
279 conn = connections.front(); 279 conn = connections.front();
280 time_t now = time(NULL); 280 time_t now = time(NULL);
281 if ((now - conn->get_stamp()) > maxsmtp_age) { 281 if ((now - conn->get_stamp()) > maxsmtp_age) {
282 // this connection is ancient, remove it 282 // this connection is ancient, remove it
283 connections.pop_front(); 283 connections.pop_front();
284 } 284 }
285 else { 285 else {
286 ok = false; 286 ok = false;
287 conn = NULL; 287 conn = NULL;
288 } 288 }
289 } 289 }
290 pthread_mutex_unlock(&mutex); 290 pthread_mutex_unlock(&mutex);
291 // avoid doing this work inside the mutex lock 291 // avoid doing this work inside the mutex lock
292 if (conn) { 292 if (conn) {
293 #ifdef VERIFY_DEBUG 293 #ifdef VERIFY_DEBUG
294 conn->log("closer() closes ancient %d", conn->get_fd()); 294 conn->log("closer() closes ancient %d", conn->get_fd());
295 #endif 295 #endif
296 delete conn; 296 delete conn;
297 } 297 }
298 } 298 }
299 } 299 }
300 300
301 301
302 SMTP* VERIFY::get_connection() { 302 SMTP* VERIFY::get_connection() {
303 SMTP *conn = NULL; 303 SMTP *conn = NULL;
304 pthread_mutex_lock(&mutex); 304 pthread_mutex_lock(&mutex);
305 if (!connections.empty()) { 305 if (!connections.empty()) {
306 conn = connections.front(); 306 conn = connections.front();
307 connections.pop_front(); 307 connections.pop_front();
308 #ifdef VERIFY_DEBUG 308 #ifdef VERIFY_DEBUG
309 conn->log("get_connection() %d from cache", conn->get_fd()); 309 conn->log("get_connection() %d from cache", conn->get_fd());
310 #endif 310 #endif
311 } 311 }
312 pthread_mutex_unlock(&mutex); 312 pthread_mutex_unlock(&mutex);
313 if (conn) return conn; 313 if (conn) return conn;
314 int sock = NULL_SOCKET; 314 int sock = NULL_SOCKET;
315 if ((time(NULL) - last_err) > ERROR_SMTP_SOCKET_TIME) { 315 if ((time(NULL) - last_err) > ERROR_SMTP_SOCKET_TIME) {
316 // nothing recent, maybe this time it will work 316 // nothing recent, maybe this time it will work
317 hostent *h = gethostbyname(host); 317 hostent *h = gethostbyname(host);
318 if (h) { 318 if (h) {
319 sockaddr_in server; 319 sockaddr_in server;
320 server.sin_family = h->h_addrtype; 320 server.sin_family = h->h_addrtype;
321 server.sin_port = htons(25); 321 server.sin_port = htons(25);
322 memcpy(&server.sin_addr, h->h_addr_list[0], h->h_length); 322 memcpy(&server.sin_addr, h->h_addr_list[0], h->h_length);
323 sock = socket(PF_INET, SOCK_STREAM, 0); 323 sock = socket(PF_INET, SOCK_STREAM, 0);
324 if (sock != NULL_SOCKET) { 324 if (sock != NULL_SOCKET) {
325 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0); 325 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0);
326 if (!rc) { 326 if (!rc) {
327 shutdown(sock, SHUT_RDWR); 327 shutdown(sock, SHUT_RDWR);
328 close(sock); 328 close(sock);
329 sock = NULL_SOCKET; 329 sock = NULL_SOCKET;
330 last_err = time(NULL); 330 last_err = time(NULL);
331 } 331 }
332 } 332 }
333 else last_err = time(NULL); 333 else last_err = time(NULL);
334 } 334 }
335 else last_err = time(NULL); 335 else last_err = time(NULL);
336 } 336 }
337 if (sock != NULL_SOCKET) { 337 if (sock != NULL_SOCKET) {
338 conn = new SMTP(sock); 338 conn = new SMTP(sock);
339 #ifdef VERIFY_DEBUG 339 #ifdef VERIFY_DEBUG
340 conn->log("get_connection() %d new socket", conn->get_fd()); 340 conn->log("get_connection() %d new socket", conn->get_fd());
341 #endif 341 #endif
342 if (conn->helo() == 250) return conn; 342 if (conn->helo() == 250) return conn;
343 delete conn; 343 delete conn;
344 } 344 }
345 return NULL; 345 return NULL;
346 } 346 }
347 347
348 348
349 void VERIFY::put_connection(SMTP *conn) { 349 void VERIFY::put_connection(SMTP *conn) {
350 if (conn->err()) { 350 if (conn->err()) {
351 #ifdef VERIFY_DEBUG 351 #ifdef VERIFY_DEBUG
352 conn->log("put_socket() %d with error, close it", conn->get_fd()); 352 conn->log("put_socket() %d with error, close it", conn->get_fd());
353 #endif 353 #endif
354 delete conn; 354 delete conn;
355 last_err = time(NULL); 355 last_err = time(NULL);
356 } 356 }
357 else { 357 else {
358 #ifdef VERIFY_DEBUG 358 #ifdef VERIFY_DEBUG
359 conn->log("put_socket() %d", conn->get_fd()); 359 conn->log("put_socket() %d", conn->get_fd());
360 #endif 360 #endif
361 conn->now(); 361 conn->now();
362 pthread_mutex_lock(&mutex); 362 pthread_mutex_lock(&mutex);
363 connections.push_back(conn); 363 connections.push_back(conn);
364 pthread_mutex_unlock(&mutex); 364 pthread_mutex_unlock(&mutex);
365 } 365 }
366 } 366 }
367 367
368 368
369 bool VERIFY::ok(char *from, char *to) { 369 bool VERIFY::ok(char *from, char *to) {
370 if (host == token_myhostname) return true; 370 if (host == token_myhostname) return true;
371 SMTP *conn = get_connection(); 371 SMTP *conn = get_connection();
372 if (!conn) return true; // cannot verify right now, we have socket errors 372 if (!conn) return true; // cannot verify right now, we have socket errors
373 int rc; 373 int rc;
374 rc = conn->from(from); 374 rc = conn->from(from);
375 #ifdef VERIFY_DEBUG 375 #ifdef VERIFY_DEBUG
376 conn->log("verify::ok() from sees %d", rc); 376 conn->log("verify::ok() from sees %d", rc);
377 #endif 377 #endif
378 if (rc != 250) { 378 if (rc != 250) {
379 conn->rset(); 379 conn->rset();
380 put_connection(conn); 380 put_connection(conn);
381 return (rc >= 500) ? false : true; 381 return (rc >= 500) ? false : true;
382 } 382 }
383 rc = conn->rcpt(to); 383 rc = conn->rcpt(to);
384 #ifdef VERIFY_DEBUG 384 #ifdef VERIFY_DEBUG
385 conn->log("verify::ok() rcpt sees %d", rc); 385 conn->log("verify::ok() rcpt sees %d", rc);
386 #endif 386 #endif
387 put_connection(conn); 387 put_connection(conn);
388 return (rc >= 500) ? false : true; 388 return (rc >= 500) ? false : true;
389 } 389 }
390 390
391 391
392 //////////////////////////////////////////////// 392 ////////////////////////////////////////////////
393 // setup a new smtp verify host 393 // setup a new smtp verify host
394 // 394 //
395 VERIFYP add_verify_host(char *host); 395 VERIFYP add_verify_host(char *host);
396 VERIFYP add_verify_host(char *host) { 396 VERIFYP add_verify_host(char *host) {
397 VERIFYP rc = NULL; 397 VERIFYP rc = NULL;
398 pthread_mutex_lock(&verifier_mutex); 398 pthread_mutex_lock(&verifier_mutex);
399 verify_map::iterator i = verifiers.find(host); 399 verify_map::iterator i = verifiers.find(host);
400 if (i == verifiers.end()) { 400 if (i == verifiers.end()) {
401 rc = new VERIFY(host); 401 rc = new VERIFY(host);
402 verifiers[host] = rc; 402 verifiers[host] = rc;
403 } 403 }
404 else rc = (*i).second; 404 else rc = (*i).second;
405 pthread_mutex_unlock(&verifier_mutex); 405 pthread_mutex_unlock(&verifier_mutex);
406 return rc; 406 return rc;
407 } 407 }
408 408
409 409
410 //////////////////////////////////////////////// 410 ////////////////////////////////////////////////
411 // thread to check for verify hosts with old sockets that we can close 411 // thread to check for verify hosts with old sockets that we can close
412 // 412 //
413 void* verify_closer(void *arg) { 413 void* verify_closer(void *arg) {
414 while (true) { 414 while (true) {
415 sleep(maxsmtp_age); 415 sleep(maxsmtp_age);
416 pthread_mutex_lock(&verifier_mutex); 416 pthread_mutex_lock(&verifier_mutex);
417 for (verify_map::iterator i=verifiers.begin(); i!=verifiers.end(); i++) { 417 for (verify_map::iterator i=verifiers.begin(); i!=verifiers.end(); i++) {
418 VERIFYP v = (*i).second; 418 VERIFYP v = (*i).second;
419 v->closer(); 419 v->closer();
420 } 420 }
421 pthread_mutex_unlock(&verifier_mutex); 421 pthread_mutex_unlock(&verifier_mutex);
422 } 422 }
423 return NULL; 423 return NULL;
424 } 424 }
425 425
426 426
427 //////////////////////////////////////////////// 427 ////////////////////////////////////////////////
428 // automatic whitelister 428 // automatic whitelister
429 // 429 //
430 WHITELISTER::WHITELISTER(char *f, int d) { 430 WHITELISTER::WHITELISTER(char *f, int d) {
431 fn = f; 431 fn = f;
432 days = d; 432 days = d;
433 pthread_mutex_init(&mutex, 0); 433 pthread_mutex_init(&mutex, 0);
434 need = false; 434 need = false;
435 loaded = time(NULL); 435 loaded = time(NULL);
436 merge(); 436 merge();
437 } 437 }
438 438
439 439
440 void WHITELISTER::merge() { 440 void WHITELISTER::merge() {
441 time_t now = time(NULL); 441 time_t now = time(NULL);
442 ifstream ifs; 442 ifstream ifs;
443 ifs.open(fn); 443 ifs.open(fn);
444 if (!ifs.fail()) { 444 if (!ifs.fail()) {
445 const int maxlen = 1000; 445 const int maxlen = 1000;
446 char buf[maxlen]; 446 char buf[maxlen];
447 while (ifs.getline(buf, maxlen)) { 447 while (ifs.getline(buf, maxlen)) {
448 char *p = strchr(buf, ' '); 448 char *p = strchr(buf, ' ');
449 if (p) { 449 if (p) {
450 *p = '\0'; 450 *p = '\0';
451 char *who = strdup(buf); 451 char *who = strdup(buf);
452 time_t when = atoi(p+1); 452 time_t when = atoi(p+1);
453 if ((when == 0) || (when > now)) when = now; 453 if ((when == 0) || (when > now)) when = now;
454 autowhite_sent::iterator i = rcpts.find(who); 454 autowhite_sent::iterator i = rcpts.find(who);
455 if (i == rcpts.end()) { 455 if (i == rcpts.end()) {
456 rcpts[who] = when; 456 rcpts[who] = when;
457 } 457 }
458 else { 458 else {
459 time_t wh = (*i).second; 459 time_t wh = (*i).second;
460 if ((when == 1) || (when > wh)) (*i).second = when; 460 if ((when == 1) || (when > wh)) (*i).second = when;
461 free(who); 461 free(who);
462 } 462 }
463 } 463 }
464 } 464 }
465 } 465 }
466 ifs.close(); 466 ifs.close();
467 } 467 }
468 468
469 469
470 void WHITELISTER::writer() { 470 void WHITELISTER::writer() {
471 pthread_mutex_lock(&mutex); 471 pthread_mutex_lock(&mutex);
472 time_t limit = time(NULL) - days*86400; 472 time_t limit = time(NULL) - days*86400;
473 473
474 // check for manually modified autowhitelist file 474 // check for manually modified autowhitelist file
475 struct stat st; 475 struct stat st;
476 if (stat(fn, &st)) need = true; // file has disappeared 476 if (stat(fn, &st)) need = true; // file has disappeared
477 else if (st.st_mtime > loaded) { 477 else if (st.st_mtime > loaded) {
478 // file has been manually updated, merge new entries 478 // file has been manually updated, merge new entries
479 merge(); 479 merge();
480 need = true; 480 need = true;
481 } 481 }
482 482
483 // purge old entries 483 // purge old entries
484 for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end();) { 484 for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end();) {
485 time_t when = (*i).second; 485 time_t when = (*i).second;
486 if (when < limit) { 486 if (when < limit) {
487 char *who = (*i).first; 487 char *who = (*i).first;
488 free(who); 488 free(who);
489 autowhite_sent::iterator j = i; 489 autowhite_sent::iterator j = i;
490 j++; 490 j++;
491 rcpts.erase(i); 491 rcpts.erase(i);
492 i = j; 492 i = j;
493 need = true; 493 need = true;
494 } 494 }
495 else i++; 495 else i++;
496 } 496 }
497 497
498 if (need) { 498 if (need) {
499 // dump the file 499 // dump the file
500 ofstream ofs; 500 ofstream ofs;
501 ofs.open(fn); 501 ofs.open(fn);
502 if (!ofs.fail()) { 502 if (!ofs.fail()) {
503 for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end(); i++) { 503 for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end(); i++) {
504 char *who = (*i).first; 504 char *who = (*i).first;
505 int when = (*i).second; 505 int when = (*i).second;
506 if (!strchr(who, ' ')) { 506 if (!strchr(who, ' ')) {
507 ofs << who << " " << when << endl; 507 ofs << who << " " << when << endl;
508 } 508 }
509 } 509 }
510 } 510 }
511 ofs.close(); 511 ofs.close();
512 need = false; 512 need = false;
513 loaded = time(NULL); // update load time 513 loaded = time(NULL); // update load time
514 } 514 }
515 pthread_mutex_unlock(&mutex); 515 pthread_mutex_unlock(&mutex);
516 } 516 }
517 517
518 518
519 void WHITELISTER::sent(char *to) { 519 void WHITELISTER::sent(char *to) {
520 // we take ownership of the string 520 // we take ownership of the string
521 pthread_mutex_lock(&mutex); 521 pthread_mutex_lock(&mutex);
522 need = true; 522 need = true;
523 autowhite_sent::iterator i = rcpts.find(to); 523 autowhite_sent::iterator i = rcpts.find(to);
524 if (i == rcpts.end()) { 524 if (i == rcpts.end()) {
525 rcpts[to] = time(NULL); 525 rcpts[to] = time(NULL);
526 } 526 }
527 else { 527 else {
528 (*i).second = time(NULL); 528 (*i).second = time(NULL);
529 free(to); 529 free(to);
530 } 530 }
531 pthread_mutex_unlock(&mutex); 531 pthread_mutex_unlock(&mutex);
532 } 532 }
533 533
534 534
535 bool WHITELISTER::is_white(char *from) { 535 bool WHITELISTER::is_white(char *from) {
536 pthread_mutex_lock(&mutex); 536 pthread_mutex_lock(&mutex);
537 autowhite_sent::iterator i = rcpts.find(from); 537 autowhite_sent::iterator i = rcpts.find(from);
538 bool rc = (i != rcpts.end()); 538 bool rc = (i != rcpts.end());
539 pthread_mutex_unlock(&mutex); 539 pthread_mutex_unlock(&mutex);
540 return rc; 540 return rc;
541 } 541 }
542 542
543 543
544 //////////////////////////////////////////////// 544 ////////////////////////////////////////////////
545 // setup a new auto whitelister file 545 // setup a new auto whitelister file
546 // 546 //
547 WHITELISTERP add_whitelister_file(char *fn, int days); 547 WHITELISTERP add_whitelister_file(char *fn, int days);
548 WHITELISTERP add_whitelister_file(char *fn, int days) { 548 WHITELISTERP add_whitelister_file(char *fn, int days) {
549 WHITELISTERP rc = NULL; 549 WHITELISTERP rc = NULL;
550 pthread_mutex_lock(&whitelister_mutex); 550 pthread_mutex_lock(&whitelister_mutex);
551 whitelister_map::iterator i = whitelisters.find(fn); 551 whitelister_map::iterator i = whitelisters.find(fn);
552 if (i == whitelisters.end()) { 552 if (i == whitelisters.end()) {
553 rc = new WHITELISTER(fn, days); 553 rc = new WHITELISTER(fn, days);
554 whitelisters[fn] = rc; 554 whitelisters[fn] = rc;
555 } 555 }
556 else { 556 else {
557 rc = (*i).second; 557 rc = (*i).second;
558 rc->set_days(days); 558 rc->set_days(days);
559 } 559 }
560 pthread_mutex_unlock(&whitelister_mutex); 560 pthread_mutex_unlock(&whitelister_mutex);
561 return rc; 561 return rc;
562 } 562 }
563 563
564 564
565 //////////////////////////////////////////////// 565 ////////////////////////////////////////////////
566 // thread to check for whitelister hosts with old sockets that we can close 566 // thread to check for whitelister hosts with old sockets that we can close
567 // 567 //
568 void* whitelister_writer(void *arg) { 568 void* whitelister_writer(void *arg) {
569 while (true) { 569 while (true) {
570 sleep(maxauto_age); 570 sleep(maxauto_age);
571 pthread_mutex_lock(&whitelister_mutex); 571 pthread_mutex_lock(&whitelister_mutex);
572 for (whitelister_map::iterator i=whitelisters.begin(); i!=whitelisters.end(); i++) { 572 for (whitelister_map::iterator i=whitelisters.begin(); i!=whitelisters.end(); i++) {
573 WHITELISTERP v = (*i).second; 573 WHITELISTERP v = (*i).second;
574 v->writer(); 574 v->writer();
575 } 575 }
576 pthread_mutex_unlock(&whitelister_mutex); 576 pthread_mutex_unlock(&whitelister_mutex);
577 } 577 }
578 return NULL; 578 return NULL;
579 }
580
581
582 DELAYWHITE::DELAYWHITE(char *loto_, WHITELISTERP w_, CONTEXTP con_) {
583 loto = loto_;
584 w = w_;
585 con = con_;
579 } 586 }
580 587
581 588
582 DNSBL::DNSBL(char *n, char *s, char *m) { 589 DNSBL::DNSBL(char *n, char *s, char *m) {
583 name = n; 590 name = n;
584 suffix = s; 591 suffix = s;
585 message = m; 592 message = m;
586 } 593 }
587 594
588 595
589 bool DNSBL::operator==(const DNSBL &rhs) { 596 bool DNSBL::operator==(const DNSBL &rhs) {
590 return (strcmp(name, rhs.name) == 0) && 597 return (strcmp(name, rhs.name) == 0) &&
591 (strcmp(suffix, rhs.suffix) == 0) && 598 (strcmp(suffix, rhs.suffix) == 0) &&
592 (strcmp(message, rhs.message) == 0); 599 (strcmp(message, rhs.message) == 0);
593 } 600 }
594 601
595 602
596 CONFIG::CONFIG() { 603 CONFIG::CONFIG() {
597 reference_count = 0; 604 reference_count = 0;
598 generation = 0; 605 generation = 0;
599 load_time = 0; 606 load_time = 0;
600 default_context = NULL; 607 default_context = NULL;
601 } 608 }
602 609
603 610
604 CONFIG::~CONFIG() { 611 CONFIG::~CONFIG() {
605 if (debug_syslog) { 612 if (debug_syslog) {
606 char buf[maxlen]; 613 char buf[maxlen];
607 snprintf(buf, sizeof(buf), "freeing memory for old configuration generation %d", generation); 614 snprintf(buf, sizeof(buf), "freeing memory for old configuration generation %d", generation);
608 my_syslog(buf); 615 my_syslog(buf);
609 } 616 }
610 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { 617 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) {
611 CONTEXT *c = *i; 618 CONTEXT *c = *i;
612 delete c; 619 delete c;
613 } 620 }
614 } 621 }
615 622
616 623
617 void CONFIG::add_context(CONTEXTP con) { 624 void CONFIG::add_context(CONTEXTP con) {
618 contexts.push_back(con); 625 contexts.push_back(con);
619 if (!default_context && !con->get_parent()) { 626 if (!default_context && !con->get_parent()) {
620 // first global context 627 // first global context
621 default_context = con; 628 default_context = con;
622 } 629 }
623 } 630 }
624 631
625 632
626 void CONFIG::add_to(char *to, CONTEXTP con) { 633 void CONFIG::add_to(char *to, CONTEXTP con) {
627 context_map::iterator i = env_to.find(to); 634 context_map::iterator i = env_to.find(to);
628 if (i != env_to.end()) { 635 if (i != env_to.end()) {
629 CONTEXTP c = (*i).second; 636 CONTEXTP c = (*i).second;
630 if ((c != con) && (c != con->get_parent())) { 637 if ((c != con) && (c != con->get_parent())) {
631 if (debug_syslog) { 638 if (debug_syslog) {
632 char oldname[maxlen]; 639 char oldname[maxlen];
633 char newname[maxlen]; 640 char newname[maxlen];
634 char *oldn = c->get_full_name(oldname, maxlen); 641 char *oldn = c->get_full_name(oldname, maxlen);
635 char *newn = con->get_full_name(newname, maxlen); 642 char *newn = con->get_full_name(newname, maxlen);
636 char buf[maxlen*3]; 643 char buf[maxlen*3];
637 snprintf(buf, maxlen*3, "both %s and %s claim envelope to %s, the second one wins", oldn, newn, to); 644 snprintf(buf, maxlen*3, "both %s and %s claim envelope to %s, the second one wins", oldn, newn, to);
638 my_syslog(buf); 645 my_syslog(buf);
639 } 646 }
640 } 647 }
641 } 648 }
642 env_to[to] = con; 649 env_to[to] = con;
643 } 650 }
644 651
645 652
646 CONTEXTP CONFIG::find_context(char *to) { 653 CONTEXTP CONFIG::find_context(char *to) {
647 context_map::iterator i = env_to.find(to); 654 context_map::iterator i = env_to.find(to);
648 if (i != env_to.end()) return (*i).second; // found user@domain key 655 if (i != env_to.end()) return (*i).second; // found user@domain key
649 char *x = strchr(to, '@'); 656 char *x = strchr(to, '@');
650 if (x) { 657 if (x) {
651 x++; 658 x++;
652 i = env_to.find(x); 659 i = env_to.find(x);
653 if (i != env_to.end()) return (*i).second; // found domain key 660 if (i != env_to.end()) return (*i).second; // found domain key
654 char y = *x; 661 char y = *x;
655 *x = '\0'; 662 *x = '\0';
656 i = env_to.find(to); 663 i = env_to.find(to);
657 *x = y; 664 *x = y;
658 if (i != env_to.end()) return (*i).second; // found user@ key 665 if (i != env_to.end()) return (*i).second; // found user@ key
659 } 666 }
660 return default_context; 667 return default_context;
661 } 668 }
662 669
663 670
664 void CONFIG::dump() { 671 void CONFIG::dump() {
665 bool spamass = false; 672 bool spamass = false;
666 if (default_context) default_context->dump(true, spamass); 673 if (default_context) default_context->dump(true, spamass);
667 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { 674 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) {
668 CONTEXTP c = *i; 675 CONTEXTP c = *i;
669 CONTEXTP p = c->get_parent(); 676 CONTEXTP p = c->get_parent();
670 if (!p && (c != default_context)) c->dump(false, spamass); 677 if (!p && (c != default_context)) c->dump(false, spamass);
671 } 678 }
672 char buf[maxlen]; 679 char buf[maxlen];
673 for (context_map::iterator i=env_to.begin(); i!=env_to.end(); i++) { 680 for (context_map::iterator i=env_to.begin(); i!=env_to.end(); i++) {
674 char *to = (*i).first; 681 char *to = (*i).first;
675 CONTEXTP con = (*i).second; 682 CONTEXTP con = (*i).second;
676 printf("// envelope to %s \t-> context %s \n", to, con->get_full_name(buf,maxlen)); 683 printf("// envelope to %s \t-> context %s \n", to, con->get_full_name(buf,maxlen));
677 } 684 }
678 if (spamass && (spamc == spamc_empty)) { 685 if (spamass && (spamc == spamc_empty)) {
679 printf("// *** warning - spamassassin filtering requested, but spamc not found by autoconf.\n"); 686 printf("// *** warning - spamassassin filtering requested, but spamc not found by autoconf.\n");
680 } 687 }
681 } 688 }
682 689
683 690
684 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) { 691 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) {
685 parent = parent_; 692 parent = parent_;
686 name = name_; 693 name = name_;
687 verify_host = NULL; 694 verify_host = NULL;
688 verifier = NULL; 695 verifier = NULL;
689 generic_regx = NULL; 696 generic_regx = NULL;
690 generic_message = NULL; 697 generic_message = NULL;
691 autowhite_file = NULL; 698 autowhite_file = NULL;
692 whitelister = NULL; 699 whitelister = NULL;
693 env_from_default = (parent) ? token_inherit : token_unknown; 700 env_from_default = (parent) ? token_inherit : token_unknown;
694 content_filtering = (parent) ? parent->content_filtering : false; 701 content_filtering = (parent) ? parent->content_filtering : false;
695 content_suffix = NULL; 702 content_suffix = NULL;
696 content_message = NULL; 703 content_message = NULL;
697 uribl_suffix = NULL; 704 uribl_suffix = NULL;
698 uribl_message = NULL; 705 uribl_message = NULL;
699 host_limit = (parent) ? parent->host_limit : 0; 706 host_limit = (parent) ? parent->host_limit : 0;
700 host_limit_message = NULL; 707 host_limit_message = NULL;
701 host_random = (parent) ? parent->host_random : false; 708 host_random = (parent) ? parent->host_random : false;
702 tag_limit = (parent) ? parent->tag_limit : 0; 709 tag_limit = (parent) ? parent->tag_limit : 0;
703 tag_limit_message = NULL; 710 tag_limit_message = NULL;
704 spamassassin_limit = (parent) ? parent->spamassassin_limit : 0; 711 spamassassin_limit = (parent) ? parent->spamassassin_limit : 0;
705 require_match = (parent) ? parent->require_match : false; 712 require_match = (parent) ? parent->require_match : false;
706 dcc_greylist = (parent) ? parent->dcc_greylist : false; 713 dcc_greylist = (parent) ? parent->dcc_greylist : false;
707 dcc_bulk_threshold = (parent) ? parent->dcc_bulk_threshold : 0; 714 dcc_bulk_threshold = (parent) ? parent->dcc_bulk_threshold : 0;
708 default_rcpt_rate = INT_MAX; 715 default_rcpt_rate = INT_MAX;
709 } 716 }
710 717
711 718
712 CONTEXT::~CONTEXT() { 719 CONTEXT::~CONTEXT() {
713 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) { 720 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) {
714 DNSBLP d = (*i).second; 721 DNSBLP d = (*i).second;
715 // delete the underlying DNSBL objects. 722 // delete the underlying DNSBL objects.
716 delete d; 723 delete d;
717 } 724 }
718 if (generic_regx) regfree(&generic_pattern); 725 if (generic_regx) regfree(&generic_pattern);
719 } 726 }
720 727
721 728
722 bool CONTEXT::is_parent(CONTEXTP p) { 729 bool CONTEXT::is_parent(CONTEXTP p) {
723 if (p == parent) return true; 730 if (p == parent) return true;
724 if (!parent) return false; 731 if (!parent) return false;
725 return parent->is_parent(p); 732 return parent->is_parent(p);
726 } 733 }
727 734
728 735
729 char *CONTEXT::get_full_name(char *buffer, int size) { 736 char *CONTEXT::get_full_name(char *buffer, int size) {
730 if (!parent) return name; 737 if (!parent) return name;
731 char buf[maxlen]; 738 char buf[maxlen];
732 snprintf(buffer, size, "%s.%s", parent->get_full_name(buf, maxlen), name); 739 snprintf(buffer, size, "%s.%s", parent->get_full_name(buf, maxlen), name);
733 return buffer; 740 return buffer;
734 } 741 }
735 742
736 743
737 bool CONTEXT::set_generic(char *regx, char *msg) 744 bool CONTEXT::set_generic(char *regx, char *msg)
738 { 745 {
739 int rc = 0; 746 int rc = 0;
740 if (generic_regx) regfree(&generic_pattern); 747 if (generic_regx) regfree(&generic_pattern);
741 generic_regx = regx; 748 generic_regx = regx;
742 generic_message = msg; 749 generic_message = msg;
743 if (generic_regx) { 750 if (generic_regx) {
744 rc = regcomp(&generic_pattern, regx, REG_NOSUB | REG_ICASE | REG_EXTENDED); 751 rc = regcomp(&generic_pattern, regx, REG_NOSUB | REG_ICASE | REG_EXTENDED);
745 } 752 }
746 return rc; // true iff bad pattern 753 return rc; // true iff bad pattern
747 } 754 }
748 755
749 756
750 char *CONTEXT::generic_match(char *client) 757 char *CONTEXT::generic_match(char *client)
751 { 758 {
752 if (parent && !generic_regx) return parent->generic_match(client); 759 if (parent && !generic_regx) return parent->generic_match(client);
753 if (!generic_regx) return NULL; 760 if (!generic_regx) return NULL;
754 if (0 == regexec(&generic_pattern, client, 0, NULL, 0)) { 761 if (0 == regexec(&generic_pattern, client, 0, NULL, 0)) {
755 return generic_message; 762 return generic_message;
756 } 763 }
757 return NULL; 764 return NULL;
758 } 765 }
759 766
760 767
761 bool CONTEXT::cover_env_to(char *to) { 768 bool CONTEXT::cover_env_to(char *to) {
762 char buffer[maxlen]; 769 char buffer[maxlen];
763 char *x = strchr(to, '@'); 770 char *x = strchr(to, '@');
764 if (x) x++; 771 if (x) x++;
765 else x = to; 772 else x = to;
766 if (*x == '\0') return true; // always allow covering addresses with no domain name, eg abuse@ 773 if (*x == '\0') return true; // always allow covering addresses with no domain name, eg abuse@
767 if (!parent && env_to.empty()) return true; // empty env_to at global level covers everything 774 if (!parent && env_to.empty()) return true; // empty env_to at global level covers everything
768 string_set::iterator i = env_to.find(x); 775 string_set::iterator i = env_to.find(x);
769 if (i != env_to.end()) return true; // we cover the entire domain 776 if (i != env_to.end()) return true; // we cover the entire domain
770 if (x != to) { 777 if (x != to) {
771 i = env_to.find(to); 778 i = env_to.find(to);
772 if (i != env_to.end()) return true; // we cover the specific email address 779 if (i != env_to.end()) return true; // we cover the specific email address
773 } 780 }
774 return false; 781 return false;
775 } 782 }
776 783
777 784
778 VERIFYP CONTEXT::find_verify(char *to) { 785 VERIFYP CONTEXT::find_verify(char *to) {
779 if (verifier && (verify_host != token_myhostname) && cover_env_to(to)) 786 if (verifier && (verify_host != token_myhostname) && cover_env_to(to))
780 return verifier; 787 return verifier;
781 else if (parent) 788 else if (parent)
782 return parent->find_verify(to); 789 return parent->find_verify(to);
783 else 790 else
784 return NULL; 791 return NULL;
785 } 792 }
786 793
787 794
788 WHITELISTERP CONTEXT::find_autowhite(char *from, char *to) { 795 WHITELISTERP CONTEXT::find_autowhite(char *from, char *to) {
789 if (whitelister && cover_env_to(to) && !cover_env_to(from)) 796 if (whitelister && cover_env_to(to) && !cover_env_to(from))
790 return whitelister; 797 return whitelister;
791 else if (parent) 798 else if (parent)
792 return parent->find_autowhite(from, to); 799 return parent->find_autowhite(from, to);
793 else 800 else
794 return NULL; 801 return NULL;
795 } 802 }
796 803
797 804
798 int CONTEXT::find_rate(char *user) { 805 int CONTEXT::find_rate(char *user) {
799 if (rcpt_per_hour.empty()) return default_rcpt_rate; 806 if (rcpt_per_hour.empty()) return default_rcpt_rate;
800 rcpt_rates::iterator i = rcpt_per_hour.find(user); 807 rcpt_rates::iterator i = rcpt_per_hour.find(user);
801 return (i == rcpt_per_hour.end()) ? default_rcpt_rate : (*i).second; 808 return (i == rcpt_per_hour.end()) ? default_rcpt_rate : (*i).second;
802 } 809 }
803 810
804 811
805 char *CONTEXT::find_from(char *from, bool update_white) { 812 char *CONTEXT::find_from(char *from, bool update_white) {
806 if (whitelister && whitelister->is_white(from)) { 813 if (whitelister && whitelister->is_white(from)) {
807 if (update_white) { 814 if (update_white) {
808 // update senders timestamp to extend the whitelisting period 815 // update senders timestamp to extend the whitelisting period
809 if (debug_syslog > 1) { 816 if (debug_syslog > 1) {
810 char buf[maxlen]; 817 char buf[maxlen];
811 char msg[maxlen]; 818 char msg[maxlen];
812 snprintf(msg, sizeof(msg), "extend whitelist reply from <%s> in context %s", from, get_full_name(buf,maxlen)); 819 snprintf(msg, sizeof(msg), "extend whitelist reply from <%s> in context %s", from, get_full_name(buf,maxlen));
813 my_syslog(msg); 820 my_syslog(msg);
814 } 821 }
815 whitelister->sent(strdup(from)); 822 whitelister->sent(strdup(from));
816 } 823 }
817 return token_white; 824 return token_white;
818 } 825 }
819 char *rc = env_from_default; 826 char *rc = env_from_default;
820 string_map::iterator i = env_from.find(from); 827 string_map::iterator i = env_from.find(from);
821 if (i != env_from.end()) rc = (*i).second; // found user@domain key 828 if (i != env_from.end()) rc = (*i).second; // found user@domain key
822 else { 829 else {
823 char *x = strchr(from, '@'); 830 char *x = strchr(from, '@');
824 if (x) { 831 if (x) {
825 x++; 832 x++;
826 i = env_from.find(x); 833 i = env_from.find(x);
827 if (i != env_from.end()) rc = (*i).second; // found domain key 834 if (i != env_from.end()) rc = (*i).second; // found domain key
828 else { 835 else {
829 char y = *x; 836 char y = *x;
830 *x = '\0'; 837 *x = '\0';
831 i = env_from.find(from); 838 i = env_from.find(from);
832 *x = y; 839 *x = y;
833 if (i != env_from.end()) rc = (*i).second; // found user@ key 840 if (i != env_from.end()) rc = (*i).second; // found user@ key
834 } 841 }
835 } 842 }
836 } 843 }
837 if ((rc == token_inherit) && parent) return parent->find_from(from); 844 if ((rc == token_inherit) && parent) return parent->find_from(from);
838 return (rc == token_inherit) ? token_unknown : rc; 845 return (rc == token_inherit) ? token_unknown : rc;
839 } 846 }
840 847
841 848
842 CONTEXTP CONTEXT::find_context(char *from) { 849 CONTEXTP CONTEXT::find_context(char *from) {
843 context_map::iterator i = env_from_context.find(from); 850 context_map::iterator i = env_from_context.find(from);
844 if (i != env_from_context.end()) return (*i).second; // found user@domain key 851 if (i != env_from_context.end()) return (*i).second; // found user@domain key
845 char *x = strchr(from, '@'); 852 char *x = strchr(from, '@');
846 if (x) { 853 if (x) {
847 x++; 854 x++;
848 i = env_from_context.find(x); 855 i = env_from_context.find(x);
849 if (i != env_from_context.end()) return (*i).second; // found domain key 856 if (i != env_from_context.end()) return (*i).second; // found domain key
850 char y = *x; 857 char y = *x;
851 *x = '\0'; 858 *x = '\0';
852 i = env_from_context.find(from); 859 i = env_from_context.find(from);
853 *x = y; 860 *x = y;
854 if (i != env_from_context.end()) return (*i).second; // found user@ key 861 if (i != env_from_context.end()) return (*i).second; // found user@ key
855 } 862 }
856 return this; 863 return this;
857 } 864 }
858 865
859 866
860 CONTEXTP CONTEXT::find_from_context_name(char *name) { 867 CONTEXTP CONTEXT::find_from_context_name(char *name) {
861 context_map::iterator i = children.find(name); 868 context_map::iterator i = children.find(name);
862 if (i != children.end()) return (*i).second; 869 if (i != children.end()) return (*i).second;
863 return NULL; 870 return NULL;
864 } 871 }
865 872
866 873
867 DNSBLP CONTEXT::find_dnsbl(char *name) { 874 DNSBLP CONTEXT::find_dnsbl(char *name) {
868 dnsblp_map::iterator i = dnsbl_names.find(name); 875 dnsblp_map::iterator i = dnsbl_names.find(name);
869 if (i != dnsbl_names.end()) return (*i).second; 876 if (i != dnsbl_names.end()) return (*i).second;
870 if (parent) return parent->find_dnsbl(name); 877 if (parent) return parent->find_dnsbl(name);
871 return NULL; 878 return NULL;
872 } 879 }
873 880
874 881
875 char* CONTEXT::get_content_suffix() { 882 char* CONTEXT::get_content_suffix() {
876 if (!content_suffix && parent) return parent->get_content_suffix(); 883 if (!content_suffix && parent) return parent->get_content_suffix();
877 return content_suffix; 884 return content_suffix;
878 } 885 }
879 886
880 887
881 char* CONTEXT::get_uribl_suffix() { 888 char* CONTEXT::get_uribl_suffix() {
882 if (!uribl_suffix && parent) return parent->get_uribl_suffix(); 889 if (!uribl_suffix && parent) return parent->get_uribl_suffix();
883 return uribl_suffix; 890 return uribl_suffix;
884 } 891 }
885 892
886 893
887 char* CONTEXT::get_content_message() { 894 char* CONTEXT::get_content_message() {
888 if (!content_message && parent) return parent->get_content_message(); 895 if (!content_message && parent) return parent->get_content_message();
889 return content_message; 896 return content_message;
890 } 897 }
891 898
892 899
893 char* CONTEXT::get_uribl_message() { 900 char* CONTEXT::get_uribl_message() {
894 if (!uribl_message && parent) return parent->get_uribl_message(); 901 if (!uribl_message && parent) return parent->get_uribl_message();
895 return uribl_message; 902 return uribl_message;
896 } 903 }
897 904
898 905
899 string_set& CONTEXT::get_content_host_ignore() { 906 string_set& CONTEXT::get_content_host_ignore() {
900 if (content_host_ignore.empty() && parent) return parent->get_content_host_ignore(); 907 if (content_host_ignore.empty() && parent) return parent->get_content_host_ignore();
901 return content_host_ignore; 908 return content_host_ignore;
902 } 909 }
903 910
904 911
905 string_set& CONTEXT::get_content_cctlds() { 912 string_set& CONTEXT::get_content_cctlds() {
906 if (content_cctlds.empty() && parent) return parent->get_content_cctlds(); 913 if (content_cctlds.empty() && parent) return parent->get_content_cctlds();
907 return content_cctlds; 914 return content_cctlds;
908 } 915 }
909 916
910 string_set& CONTEXT::get_content_tlds() { 917 string_set& CONTEXT::get_content_tlds() {
911 if (content_tlds.empty() && parent) return parent->get_content_tlds(); 918 if (content_tlds.empty() && parent) return parent->get_content_tlds();
912 return content_tlds; 919 return content_tlds;
913 } 920 }
914 921
915 922
916 string_set& CONTEXT::get_html_tags() { 923 string_set& CONTEXT::get_html_tags() {
917 if (html_tags.empty() && parent) return parent->get_html_tags(); 924 if (html_tags.empty() && parent) return parent->get_html_tags();
918 return html_tags; 925 return html_tags;
919 } 926 }
920 927
921 928
922 dnsblp_list& CONTEXT::get_dnsbl_list() { 929 dnsblp_list& CONTEXT::get_dnsbl_list() {
923 if (dnsbl_list.empty() && parent) return parent->get_dnsbl_list(); 930 if (dnsbl_list.empty() && parent) return parent->get_dnsbl_list();
924 return dnsbl_list; 931 return dnsbl_list;
925 } 932 }
926 933
927 934
928 bool CONTEXT::acceptable_content(recorder &memory, int score, int bulk, string& msg) { 935 bool CONTEXT::acceptable_content(recorder &memory, int score, int bulk, string& msg) {
929 if (spamassassin_limit && (score > spamassassin_limit)) { 936 if (spamassassin_limit && (score > spamassassin_limit)) {
930 char buf[maxlen]; 937 char buf[maxlen];
931 snprintf(buf, sizeof(buf), "Mail rejected - spam assassin score %d", score); 938 snprintf(buf, sizeof(buf), "Mail rejected - spam assassin score %d", score);
932 msg = string(buf); 939 msg = string(buf);
933 return false; 940 return false;
934 } 941 }
935 if (dcc_bulk_threshold && (bulk > dcc_bulk_threshold)) { 942 if (dcc_bulk_threshold && (bulk > dcc_bulk_threshold)) {
936 char buf[maxlen]; 943 char buf[maxlen];
937 snprintf(buf, sizeof(buf), "Mail rejected - dcc score %d", bulk); 944 snprintf(buf, sizeof(buf), "Mail rejected - dcc score %d", bulk);
938 msg = string(buf); 945 msg = string(buf);
939 return false; 946 return false;
940 } 947 }
941 if (memory.excessive_bad_tags(tag_limit)) { 948 if (memory.excessive_bad_tags(tag_limit)) {
942 msg = string(tag_limit_message); 949 msg = string(tag_limit_message);
943 return false; 950 return false;
944 } 951 }
945 if (!host_random && memory.excessive_hosts(host_limit)) { 952 if (!host_random && memory.excessive_hosts(host_limit)) {
946 msg = string(host_limit_message); 953 msg = string(host_limit_message);
947 return false; 954 return false;
948 } 955 }
949 return true; 956 return true;
950 } 957 }
951 958
952 959
953 void CONTEXT::dump(bool isdefault, bool &spamass, int level) { 960 void CONTEXT::dump(bool isdefault, bool &spamass, int level) {
954 char indent[maxlen]; 961 char indent[maxlen];
955 int i = min(maxlen-1, level*4); 962 int i = min(maxlen-1, level*4);
956 memset(indent, ' ', i); 963 memset(indent, ' ', i);
957 indent[i] = '\0'; 964 indent[i] = '\0';
958 char buf[maxlen]; 965 char buf[maxlen];
959 char *fullname = get_full_name(buf,maxlen); 966 char *fullname = get_full_name(buf,maxlen);
960 printf("%s context %s { \t// %s\n", indent, name, fullname); 967 printf("%s context %s { \t// %s\n", indent, name, fullname);
961 968
962 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) { 969 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) {
963 char *n = (*i).first; 970 char *n = (*i).first;
964 DNSBL &d = *(*i).second; 971 DNSBL &d = *(*i).second;
965 printf("%s dnsbl %s %s \"%s\"; \n", indent, n, d.suffix, d.message); 972 printf("%s dnsbl %s %s \"%s\"; \n", indent, n, d.suffix, d.message);
966 } 973 }
967 974
968 dnsblp_list dl = get_dnsbl_list(); 975 dnsblp_list dl = get_dnsbl_list();
969 if (!dl.empty()) { 976 if (!dl.empty()) {
970 printf("%s dnsbl_list", indent); 977 printf("%s dnsbl_list", indent);
971 for (dnsblp_list::iterator i=dl.begin(); i!=dl.end(); i++) { 978 for (dnsblp_list::iterator i=dl.begin(); i!=dl.end(); i++) {
972 DNSBL &d = *(*i); 979 DNSBL &d = *(*i);
973 printf(" %s", d.name); 980 printf(" %s", d.name);
974 } 981 }
975 printf("; \n"); 982 printf("; \n");
976 } 983 }
977 984
978 if (content_filtering) { 985 if (content_filtering) {
979 printf("%s content on { \n", indent, env_from_default); 986 printf("%s content on { \n", indent, env_from_default);
980 if (content_suffix) { 987 if (content_suffix) {
981 printf("%s filter %s \"%s\"; \n", indent, content_suffix, content_message); 988 printf("%s filter %s \"%s\"; \n", indent, content_suffix, content_message);
982 } 989 }
983 if (uribl_suffix) { 990 if (uribl_suffix) {
984 printf("%s uribl %s \"%s\"; \n", indent, uribl_suffix, uribl_message); 991 printf("%s uribl %s \"%s\"; \n", indent, uribl_suffix, uribl_message);
985 } 992 }
986 if (!content_host_ignore.empty()) { 993 if (!content_host_ignore.empty()) {
987 printf("%s ignore { \n", indent); 994 printf("%s ignore { \n", indent);
988 for (string_set::iterator i=content_host_ignore.begin(); i!=content_host_ignore.end(); i++) { 995 for (string_set::iterator i=content_host_ignore.begin(); i!=content_host_ignore.end(); i++) {
989 printf("%s %s; \n", indent, *i); 996 printf("%s %s; \n", indent, *i);
990 } 997 }
991 printf("%s }; \n", indent); 998 printf("%s }; \n", indent);
992 } 999 }
993 if (!content_cctlds.empty()) { 1000 if (!content_cctlds.empty()) {
994 printf("%s cctld { \n", indent); 1001 printf("%s cctld { \n", indent);
995 printf("%s ", indent); 1002 printf("%s ", indent);
996 for (string_set::iterator i=content_cctlds.begin(); i!=content_cctlds.end(); i++) { 1003 for (string_set::iterator i=content_cctlds.begin(); i!=content_cctlds.end(); i++) {
997 printf("%s; ", *i); 1004 printf("%s; ", *i);
998 } 1005 }
999 printf("\n%s }; \n", indent); 1006 printf("\n%s }; \n", indent);
1000 } 1007 }
1001 if (!content_tlds.empty()) { 1008 if (!content_tlds.empty()) {
1002 printf("%s tld { \n", indent); 1009 printf("%s tld { \n", indent);
1003 printf("%s ", indent); 1010 printf("%s ", indent);
1004 for (string_set::iterator i=content_tlds.begin(); i!=content_tlds.end(); i++) { 1011 for (string_set::iterator i=content_tlds.begin(); i!=content_tlds.end(); i++) {
1005 printf("%s; ", *i); 1012 printf("%s; ", *i);
1006 } 1013 }
1007 printf("\n%s }; \n", indent); 1014 printf("\n%s }; \n", indent);
1008 } 1015 }
1009 if (!html_tags.empty()) { 1016 if (!html_tags.empty()) {
1010 printf("%s html_tags { \n", indent); 1017 printf("%s html_tags { \n", indent);
1011 printf("%s ", indent); 1018 printf("%s ", indent);
1012 for (string_set::iterator i=html_tags.begin(); i!=html_tags.end(); i++) { 1019 for (string_set::iterator i=html_tags.begin(); i!=html_tags.end(); i++) {
1013 printf("%s; ", *i); 1020 printf("%s; ", *i);
1014 } 1021 }
1015 printf("\n%s }; \n", indent); 1022 printf("\n%s }; \n", indent);
1016 } 1023 }
1017 if (host_limit_message) { 1024 if (host_limit_message) {
1018 printf("%s host_limit on %d \"%s\"; \n", indent, host_limit, host_limit_message); 1025 printf("%s host_limit on %d \"%s\"; \n", indent, host_limit, host_limit_message);
1019 } 1026 }
1020 else if (host_random) { 1027 else if (host_random) {
1021 printf("%s host_limit soft %d; \n", indent, host_limit); 1028 printf("%s host_limit soft %d; \n", indent, host_limit);
1022 } 1029 }
1023 else { 1030 else {
1024 printf("%s host_limit off; \n", indent); 1031 printf("%s host_limit off; \n", indent);
1025 } 1032 }
1026 if (tag_limit_message) { 1033 if (tag_limit_message) {
1027 printf("%s html_limit on %d \"%s\"; \n", indent, tag_limit, tag_limit_message); 1034 printf("%s html_limit on %d \"%s\"; \n", indent, tag_limit, tag_limit_message);
1028 } 1035 }
1029 else { 1036 else {
1030 printf("%s html_limit off; \n", indent); 1037 printf("%s html_limit off; \n", indent);
1031 } 1038 }
1032 printf("%s spamassassin %d; \n", indent, spamassassin_limit); 1039 printf("%s spamassassin %d; \n", indent, spamassassin_limit);
1033 printf("%s require_match %s; \n", indent, (require_match) ? "yes" : "no"); 1040 printf("%s require_match %s; \n", indent, (require_match) ? "yes" : "no");
1034 printf("%s dcc_greylist %s; \n", indent, (dcc_greylist) ? "yes" : "no"); 1041 printf("%s dcc_greylist %s; \n", indent, (dcc_greylist) ? "yes" : "no");
1035 if (dcc_bulk_threshold == 0) printf("%s dcc_bulk_threshold off; \n", indent); 1042 if (dcc_bulk_threshold == 0) printf("%s dcc_bulk_threshold off; \n", indent);
1036 else if (dcc_bulk_threshold >= dccbulk) printf("%s dcc_bulk_threshold many; \n", indent); 1043 else if (dcc_bulk_threshold >= dccbulk) printf("%s dcc_bulk_threshold many; \n", indent);
1037 else printf("%s dcc_bulk_threshold %d; \n", indent, dcc_bulk_threshold); 1044 else printf("%s dcc_bulk_threshold %d; \n", indent, dcc_bulk_threshold);
1038 printf("%s }; \n", indent); 1045 printf("%s }; \n", indent);
1039 spamass |= (spamassassin_limit != 0); 1046 spamass |= (spamassassin_limit != 0);
1040 } 1047 }
1041 else { 1048 else {
1042 printf("%s content off {}; \n", indent, env_from_default); 1049 printf("%s content off {}; \n", indent, env_from_default);
1043 } 1050 }
1044 1051
1045 printf("%s env_to { \t// %s\n", indent, fullname); 1052 printf("%s env_to { \t// %s\n", indent, fullname);
1046 for (string_set::iterator i=env_to.begin(); i!=env_to.end(); i++) { 1053 for (string_set::iterator i=env_to.begin(); i!=env_to.end(); i++) {
1047 printf("%s %s; \n", indent, *i); 1054 printf("%s %s; \n", indent, *i);
1048 } 1055 }
1049 printf("%s }; \n", indent); 1056 printf("%s }; \n", indent);
1050 1057
1051 if (verify_host) { 1058 if (verify_host) {
1052 printf("%s verify %s; \n", indent, verify_host); 1059 printf("%s verify %s; \n", indent, verify_host);
1053 } 1060 }
1054 1061
1055 if (generic_regx) { 1062 if (generic_regx) {
1056 printf("%s generic \"%s\" \n", indent, generic_regx); 1063 printf("%s generic \"%s\" \n", indent, generic_regx);
1057 printf("%s \"%s\"; \n", indent, generic_message); 1064 printf("%s \"%s\"; \n", indent, generic_message);
1058 } 1065 }
1059 1066
1060 if (autowhite_file && whitelister) { 1067 if (autowhite_file && whitelister) {
1061 printf("%s autowhite %d %s; \n", indent, whitelister->get_days(), autowhite_file); 1068 printf("%s autowhite %d %s; \n", indent, whitelister->get_days(), autowhite_file);
1062 } 1069 }
1063 1070
1064 for (context_map::iterator i=children.begin(); i!=children.end(); i++) { 1071 for (context_map::iterator i=children.begin(); i!=children.end(); i++) {
1065 CONTEXTP c = (*i).second; 1072 CONTEXTP c = (*i).second;
1066 c->dump(false, spamass, level+1); 1073 c->dump(false, spamass, level+1);
1067 } 1074 }
1068 1075
1069 printf("%s env_from %s { \t// %s\n", indent, env_from_default, fullname); 1076 printf("%s env_from %s { \t// %s\n", indent, env_from_default, fullname);
1070 if (!env_from.empty()) { 1077 if (!env_from.empty()) {
1071 printf("%s // white/black/unknown \n", indent); 1078 printf("%s // white/black/unknown \n", indent);
1072 for (string_map::iterator i=env_from.begin(); i!=env_from.end(); i++) { 1079 for (string_map::iterator i=env_from.begin(); i!=env_from.end(); i++) {
1073 char *f = (*i).first; 1080 char *f = (*i).first;
1074 char *t = (*i).second; 1081 char *t = (*i).second;
1075 printf("%s %s \t%s; \n", indent, f, t); 1082 printf("%s %s \t%s; \n", indent, f, t);
1076 } 1083 }
1077 } 1084 }
1078 if (!env_from_context.empty()) { 1085 if (!env_from_context.empty()) {
1079 printf("%s // child contexts \n", indent); 1086 printf("%s // child contexts \n", indent);
1080 for (context_map::iterator j=env_from_context.begin(); j!=env_from_context.end(); j++) { 1087 for (context_map::iterator j=env_from_context.begin(); j!=env_from_context.end(); j++) {
1081 char *f = (*j).first; 1088 char *f = (*j).first;
1082 CONTEXTP t = (*j).second; 1089 CONTEXTP t = (*j).second;
1083 printf("%s %s \t%s; \n", indent, f, t->name); 1090 printf("%s %s \t%s; \n", indent, f, t->name);
1084 } 1091 }
1085 } 1092 }
1086 printf("%s }; \n", indent); 1093 printf("%s }; \n", indent);
1087 1094
1088 if (isdefault) { 1095 if (isdefault) {
1089 printf("%s rate_limit %d { \n", indent, default_rcpt_rate); 1096 printf("%s rate_limit %d { \n", indent, default_rcpt_rate);
1090 for (rcpt_rates::iterator j=rcpt_per_hour.begin(); j!=rcpt_per_hour.end(); j++) { 1097 for (rcpt_rates::iterator j=rcpt_per_hour.begin(); j!=rcpt_per_hour.end(); j++) {
1091 char *u = (*j).first; 1098 char *u = (*j).first;
1092 int l = (*j).second; 1099 int l = (*j).second;
1093 printf("%s \"%s\" \t%d; \n", indent, u, l); 1100 printf("%s \"%s\" \t%d; \n", indent, u, l);
1094 } 1101 }
1095 printf("%s }; \n", indent); 1102 printf("%s }; \n", indent);
1096 } 1103 }
1097 1104
1098 printf("%s }; \n", indent); 1105 printf("%s }; \n", indent);
1099 } 1106 }
1100 1107
1101 1108
1102 //////////////////////////////////////////////// 1109 ////////////////////////////////////////////////
1103 // helper to discard the strings held by a string_set 1110 // helper to discard the strings held by a string_set
1104 // 1111 //
1105 void discard(string_set &s) { 1112 void discard(string_set &s) {
1106 for (string_set::iterator i=s.begin(); i!=s.end(); i++) { 1113 for (string_set::iterator i=s.begin(); i!=s.end(); i++) {
1107 free(*i); 1114 free(*i);
1108 } 1115 }
1109 s.clear(); 1116 s.clear();
1110 } 1117 }
1111 1118
1112 1119
1113 //////////////////////////////////////////////// 1120 ////////////////////////////////////////////////
1114 // helper to register a string in a string set 1121 // helper to register a string in a string set
1115 // 1122 //
1116 char* register_string(string_set &s, char *name) { 1123 char* register_string(string_set &s, char *name) {
1117 string_set::iterator i = s.find(name); 1124 string_set::iterator i = s.find(name);
1118 if (i != s.end()) return *i; 1125 if (i != s.end()) return *i;
1119 char *x = strdup(name); 1126 char *x = strdup(name);
1120 s.insert(x); 1127 s.insert(x);
1121 return x; 1128 return x;
1122 } 1129 }
1123 1130
1124 1131
1125 //////////////////////////////////////////////// 1132 ////////////////////////////////////////////////
1126 // register a global string 1133 // register a global string
1127 // 1134 //
1128 char* register_string(char *name) { 1135 char* register_string(char *name) {
1129 return register_string(all_strings, name); 1136 return register_string(all_strings, name);
1130 } 1137 }
1131 1138
1132 1139
1133 //////////////////////////////////////////////// 1140 ////////////////////////////////////////////////
1134 // clear all global strings, helper for valgrind checking 1141 // clear all global strings, helper for valgrind checking
1135 // 1142 //
1136 void clear_strings() { 1143 void clear_strings() {
1137 discard(all_strings); 1144 discard(all_strings);
1138 } 1145 }
1139 1146
1140 1147
1141 //////////////////////////////////////////////// 1148 ////////////////////////////////////////////////
1142 // 1149 //
1143 bool tsa(TOKEN &tok, char *token); 1150 bool tsa(TOKEN &tok, char *token);
1144 bool tsa(TOKEN &tok, char *token) { 1151 bool tsa(TOKEN &tok, char *token) {
1145 char *have = tok.next(); 1152 char *have = tok.next();
1146 if (have == token) return true; 1153 if (have == token) return true;
1147 tok.token_error(token, have); 1154 tok.token_error(token, have);
1148 return false; 1155 return false;
1149 } 1156 }
1150 1157
1151 1158
1152 //////////////////////////////////////////////// 1159 ////////////////////////////////////////////////
1153 // 1160 //
1154 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me); 1161 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me);
1155 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me) { 1162 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
1156 char *name = tok.next(); 1163 char *name = tok.next();
1157 char *suf = tok.next(); 1164 char *suf = tok.next();
1158 char *msg = tok.next(); 1165 char *msg = tok.next();
1159 if (!tsa(tok, token_semi)) return false; 1166 if (!tsa(tok, token_semi)) return false;
1160 DNSBLP dnsnew = new DNSBL(name, suf, msg); 1167 DNSBLP dnsnew = new DNSBL(name, suf, msg);
1161 DNSBLP dnsold = me.find_dnsbl(name); 1168 DNSBLP dnsold = me.find_dnsbl(name);
1162 if (dnsold && (*dnsold == *dnsnew)) { 1169 if (dnsold && (*dnsold == *dnsnew)) {
1163 // duplicate redefinition, ignore it 1170 // duplicate redefinition, ignore it
1164 delete dnsnew; 1171 delete dnsnew;
1165 return true; 1172 return true;
1166 } 1173 }
1167 me.add_dnsbl(name, dnsnew); 1174 me.add_dnsbl(name, dnsnew);
1168 return true; 1175 return true;
1169 } 1176 }
1170 1177
1171 1178
1172 //////////////////////////////////////////////// 1179 ////////////////////////////////////////////////
1173 // 1180 //
1174 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me); 1181 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me);
1175 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me) { 1182 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
1176 while (true) { 1183 while (true) {
1177 char *have = tok.next(); 1184 char *have = tok.next();
1178 if (!have) break; 1185 if (!have) break;
1179 if (have == token_semi) break; 1186 if (have == token_semi) break;
1180 DNSBLP dns = me.find_dnsbl(have); 1187 DNSBLP dns = me.find_dnsbl(have);
1181 if (dns) { 1188 if (dns) {
1182 me.add_dnsbl(dns); 1189 me.add_dnsbl(dns);
1183 } 1190 }
1184 else { 1191 else {
1185 tok.token_error("dnsbl name", have); 1192 tok.token_error("dnsbl name", have);
1186 return false; 1193 return false;
1187 } 1194 }
1188 } 1195 }
1189 return true; 1196 return true;
1190 } 1197 }
1191 1198
1192 1199
1193 //////////////////////////////////////////////// 1200 ////////////////////////////////////////////////
1194 // 1201 //
1195 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me); 1202 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me);
1196 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me) { 1203 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
1197 char *setting = tok.next(); 1204 char *setting = tok.next();
1198 if (setting == token_on) { 1205 if (setting == token_on) {
1199 me.set_content_filtering(true); 1206 me.set_content_filtering(true);
1200 } 1207 }
1201 else if (setting == token_off) { 1208 else if (setting == token_off) {
1202 me.set_content_filtering(false); 1209 me.set_content_filtering(false);
1203 } 1210 }
1204 else { 1211 else {
1205 tok.token_error("on/off", setting); 1212 tok.token_error("on/off", setting);
1206 return false; 1213 return false;
1207 } 1214 }
1208 if (!tsa(tok, token_lbrace)) return false; 1215 if (!tsa(tok, token_lbrace)) return false;
1209 while (true) { 1216 while (true) {
1210 char *have = tok.next(); 1217 char *have = tok.next();
1211 if (!have) break; 1218 if (!have) break;
1212 if (have == token_filter) { 1219 if (have == token_filter) {
1213 char *suffix = tok.next(); 1220 char *suffix = tok.next();
1214 char *messag = tok.next(); 1221 char *messag = tok.next();
1215 me.set_content_suffix(suffix); 1222 me.set_content_suffix(suffix);
1216 me.set_content_message(messag); 1223 me.set_content_message(messag);
1217 if (!tsa(tok, token_semi)) return false; 1224 if (!tsa(tok, token_semi)) return false;
1218 } 1225 }
1219 else if (have == token_uribl) { 1226 else if (have == token_uribl) {
1220 char *suffix = tok.next(); 1227 char *suffix = tok.next();
1221 char *messag = tok.next(); 1228 char *messag = tok.next();
1222 me.set_uribl_suffix(suffix); 1229 me.set_uribl_suffix(suffix);
1223 me.set_uribl_message(messag); 1230 me.set_uribl_message(messag);
1224 if (!tsa(tok, token_semi)) return false; 1231 if (!tsa(tok, token_semi)) return false;
1225 } 1232 }
1226 else if (have == token_ignore) { 1233 else if (have == token_ignore) {
1227 if (!tsa(tok, token_lbrace)) return false; 1234 if (!tsa(tok, token_lbrace)) return false;
1228 while (true) { 1235 while (true) {
1229 if (!have) break; 1236 if (!have) break;
1230 char *have = tok.next(); 1237 char *have = tok.next();
1231 if (have == token_rbrace) break; // done 1238 if (have == token_rbrace) break; // done
1232 me.add_ignore(have); 1239 me.add_ignore(have);
1233 } 1240 }
1234 if (!tsa(tok, token_semi)) return false; 1241 if (!tsa(tok, token_semi)) return false;
1235 } 1242 }
1236 else if (have == token_tld) { 1243 else if (have == token_tld) {
1237 if (!tsa(tok, token_lbrace)) return false; 1244 if (!tsa(tok, token_lbrace)) return false;
1238 while (true) { 1245 while (true) {
1239 char *have = tok.next(); 1246 char *have = tok.next();
1240 if (!have) break; 1247 if (!have) break;
1241 if (have == token_rbrace) break; // done 1248 if (have == token_rbrace) break; // done
1242 me.add_tld(have); 1249 me.add_tld(have);
1243 } 1250 }
1244 if (!tsa(tok, token_semi)) return false; 1251 if (!tsa(tok, token_semi)) return false;
1245 } 1252 }
1246 else if (have == token_cctld) { 1253 else if (have == token_cctld) {
1247 if (!tsa(tok, token_lbrace)) return false; 1254 if (!tsa(tok, token_lbrace)) return false;
1248 while (true) { 1255 while (true) {
1249 char *have = tok.next(); 1256 char *have = tok.next();
1250 if (!have) break; 1257 if (!have) break;
1251 if (have == token_rbrace) break; // done 1258 if (have == token_rbrace) break; // done
1252 me.add_cctld(have); 1259 me.add_cctld(have);
1253 } 1260 }
1254 if (!tsa(tok, token_semi)) return false; 1261 if (!tsa(tok, token_semi)) return false;
1255 } 1262 }
1256 else if (have == token_html_tags) { 1263 else if (have == token_html_tags) {
1257 if (!tsa(tok, token_lbrace)) return false; 1264 if (!tsa(tok, token_lbrace)) return false;
1258 while (true) { 1265 while (true) {
1259 char *have = tok.next(); 1266 char *have = tok.next();
1260 if (!have) break; 1267 if (!have) break;
1261 if (have == token_rbrace) { 1268 if (have == token_rbrace) {
1262 break; // done 1269 break; // done
1263 } 1270 }
1264 else { 1271 else {
1265 me.add_tag(have); // base version 1272 me.add_tag(have); // base version
1266 char buf[200]; 1273 char buf[200];
1267 snprintf(buf, sizeof(buf), "/%s", have); 1274 snprintf(buf, sizeof(buf), "/%s", have);
1268 me.add_tag(register_string(buf)); // leading / 1275 me.add_tag(register_string(buf)); // leading /
1269 snprintf(buf, sizeof(buf), "%s/", have); 1276 snprintf(buf, sizeof(buf), "%s/", have);
1270 me.add_tag(register_string(buf)); // trailing / 1277 me.add_tag(register_string(buf)); // trailing /
1271 } 1278 }
1272 } 1279 }
1273 if (!tsa(tok, token_semi)) return false; 1280 if (!tsa(tok, token_semi)) return false;
1274 } 1281 }
1275 else if (have == token_html_limit) { 1282 else if (have == token_html_limit) {
1276 have = tok.next(); 1283 have = tok.next();
1277 if (have == token_on) { 1284 if (have == token_on) {
1278 me.set_tag_limit(tok.nextint()); 1285 me.set_tag_limit(tok.nextint());
1279 me.set_tag_message(tok.next()); 1286 me.set_tag_message(tok.next());
1280 } 1287 }
1281 else if (have == token_off) { 1288 else if (have == token_off) {
1282 me.set_tag_limit(0); 1289 me.set_tag_limit(0);
1283 me.set_tag_message(NULL); 1290 me.set_tag_message(NULL);
1284 } 1291 }
1285 else { 1292 else {
1286 tok.token_error("on/off", have); 1293 tok.token_error("on/off", have);
1287 return false; 1294 return false;
1288 } 1295 }
1289 if (!tsa(tok, token_semi)) return false; 1296 if (!tsa(tok, token_semi)) return false;
1290 } 1297 }
1291 else if (have == token_host_limit) { 1298 else if (have == token_host_limit) {
1292 have = tok.next(); 1299 have = tok.next();
1293 if (have == token_on) { 1300 if (have == token_on) {
1294 me.set_host_limit(tok.nextint()); 1301 me.set_host_limit(tok.nextint());
1295 me.set_host_message(tok.next()); 1302 me.set_host_message(tok.next());
1296 me.set_host_random(false); 1303 me.set_host_random(false);
1297 } 1304 }
1298 else if (have == token_off) { 1305 else if (have == token_off) {
1299 me.set_host_limit(0); 1306 me.set_host_limit(0);
1300 me.set_host_message(NULL); 1307 me.set_host_message(NULL);
1301 me.set_host_random(false); 1308 me.set_host_random(false);
1302 } 1309 }
1303 else if (have == token_soft) { 1310 else if (have == token_soft) {
1304 me.set_host_limit(tok.nextint()); 1311 me.set_host_limit(tok.nextint());
1305 me.set_host_message(NULL); 1312 me.set_host_message(NULL);
1306 me.set_host_random(true); 1313 me.set_host_random(true);
1307 } 1314 }
1308 else { 1315 else {
1309 tok.token_error("on/off/soft", have); 1316 tok.token_error("on/off/soft", have);
1310 return false; 1317 return false;
1311 } 1318 }
1312 if (!tsa(tok, token_semi)) return false; 1319 if (!tsa(tok, token_semi)) return false;
1313 } 1320 }
1314 else if (have == token_spamassassin) { 1321 else if (have == token_spamassassin) {
1315 me.set_spamassassin_limit(tok.nextint()); 1322 me.set_spamassassin_limit(tok.nextint());
1316 if (!tsa(tok, token_semi)) return false; 1323 if (!tsa(tok, token_semi)) return false;
1317 } 1324 }
1318 else if (have == token_require) { 1325 else if (have == token_require) {
1319 have = tok.next(); 1326 have = tok.next();
1320 if (have == token_yes) me.set_require(true); 1327 if (have == token_yes) me.set_require(true);
1321 else if (have == token_no) me.set_require(false); 1328 else if (have == token_no) me.set_require(false);
1322 else { 1329 else {
1323 tok.token_error("yes/no", have); 1330 tok.token_error("yes/no", have);
1324 return false; 1331 return false;
1325 } 1332 }
1326 if (!tsa(tok, token_semi)) return false; 1333 if (!tsa(tok, token_semi)) return false;
1327 } 1334 }
1328 else if (have == token_dccgrey) { 1335 else if (have == token_dccgrey) {
1329 have = tok.next(); 1336 have = tok.next();
1330 if (have == token_yes) me.set_grey(true); 1337 if (have == token_yes) me.set_grey(true);
1331 else if (have == token_no) me.set_grey(false); 1338 else if (have == token_no) me.set_grey(false);
1332 else { 1339 else {
1333 tok.token_error("yes/no", have); 1340 tok.token_error("yes/no", have);
1334 return false; 1341 return false;
1335 } 1342 }
1336 if (!tsa(tok, token_semi)) return false; 1343 if (!tsa(tok, token_semi)) return false;
1337 } 1344 }
1338 else if (have == token_dccbulk) { 1345 else if (have == token_dccbulk) {
1339 have = tok.next(); 1346 have = tok.next();
1340 if (have == token_off) me.set_bulk(0); 1347 if (have == token_off) me.set_bulk(0);
1341 else if (have == token_many) me.set_bulk(dccbulk); 1348 else if (have == token_many) me.set_bulk(dccbulk);
1342 else { 1349 else {
1343 char *e; 1350 char *e;
1344 long i = strtol(have, &e, 10); 1351 long i = strtol(have, &e, 10);
1345 if (*e != '\0') { 1352 if (*e != '\0') {
1346 tok.token_error("integer", have); 1353 tok.token_error("integer", have);
1347 return false; 1354 return false;
1348 } 1355 }
1349 me.set_bulk((int)i); 1356 me.set_bulk((int)i);
1350 } 1357 }
1351 if (!tsa(tok, token_semi)) return false; 1358 if (!tsa(tok, token_semi)) return false;
1352 } 1359 }
1353 else if (have == token_rbrace) { 1360 else if (have == token_rbrace) {
1354 break; // done 1361 break; // done
1355 } 1362 }
1356 else { 1363 else {
1357 tok.token_error("content keyword", have); 1364 tok.token_error("content keyword", have);
1358 return false; 1365 return false;
1359 } 1366 }
1360 } 1367 }
1361 return tsa(tok, token_semi); 1368 return tsa(tok, token_semi);
1362 } 1369 }
1363 1370
1364 1371
1365 //////////////////////////////////////////////// 1372 ////////////////////////////////////////////////
1366 // 1373 //
1367 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me); 1374 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me);
1368 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me) { 1375 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
1369 if (!tsa(tok, token_lbrace)) return false; 1376 if (!tsa(tok, token_lbrace)) return false;
1370 while (true) { 1377 while (true) {
1371 char *have = tok.next(); 1378 char *have = tok.next();
1372 if (!have) break; 1379 if (!have) break;
1373 if (have == token_rbrace) break; 1380 if (have == token_rbrace) break;
1374 if (have == token_semi) { 1381 if (have == token_semi) {
1375 // optional separators 1382 // optional separators
1376 } 1383 }
1377 else if (have == token_dccto) { 1384 else if (have == token_dccto) {
1378 char *flavor = tok.next(); 1385 char *flavor = tok.next();
1379 if (!tsa(tok, token_lbrace)) return false; 1386 if (!tsa(tok, token_lbrace)) return false;
1380 bool keeping = false; 1387 bool keeping = false;
1381 while (true) { 1388 while (true) {
1382 char *have = tok.next(); 1389 char *have = tok.next();
1383 if (!have) break; 1390 if (!have) break;
1384 if (have == token_rbrace) break; 1391 if (have == token_rbrace) break;
1385 if (have == flavor) { 1392 if (have == flavor) {
1386 keeping = true; 1393 keeping = true;
1387 continue; 1394 continue;
1388 } 1395 }
1389 else if ((have == token_ok) || (have == token_ok2) || (have == token_many)) { 1396 else if ((have == token_ok) || (have == token_ok2) || (have == token_many)) {
1390 keeping = false; 1397 keeping = false;
1391 continue; 1398 continue;
1392 } 1399 }
1393 if (have == token_envto) { 1400 if (have == token_envto) {
1394 have = tok.next(); 1401 have = tok.next();
1395 if (keeping) { 1402 if (keeping) {
1396 if (me.allow_env_to(have)) { 1403 if (me.allow_env_to(have)) {
1397 me.add_to(have); 1404 me.add_to(have);
1398 dc.add_to(have, &me); 1405 dc.add_to(have, &me);
1399 } 1406 }
1400 } 1407 }
1401 } 1408 }
1402 //else if (have == token_substitute) { 1409 //else if (have == token_substitute) {
1403 // if (tok.next() == token_mailhost) { 1410 // if (tok.next() == token_mailhost) {
1404 // have = tok.next(); 1411 // have = tok.next();
1405 // if (keeping) { 1412 // if (keeping) {
1406 // if (me.allow_env_to(have)) { 1413 // if (me.allow_env_to(have)) {
1407 // me.add_to(have); 1414 // me.add_to(have);
1408 // dc.add_to(have, &me); 1415 // dc.add_to(have, &me);
1409 // } 1416 // }
1410 // } 1417 // }
1411 // } 1418 // }
1412 //} 1419 //}
1413 tok.skipeol(); 1420 tok.skipeol();
1414 } 1421 }
1415 } 1422 }
1416 else if (me.allow_env_to(have)) { 1423 else if (me.allow_env_to(have)) {
1417 me.add_to(have); 1424 me.add_to(have);
1418 dc.add_to(have, &me); 1425 dc.add_to(have, &me);
1419 } 1426 }
1420 else { 1427 else {
1421 tok.token_error("user@ or user@domain.tld or domain.tld where domain.tld allowed by parent context", have); 1428 tok.token_error("user@ or user@domain.tld or domain.tld where domain.tld allowed by parent context", have);
1422 return false; 1429 return false;
1423 } 1430 }
1424 } 1431 }
1425 return tsa(tok, token_semi); 1432 return tsa(tok, token_semi);
1426 } 1433 }
1427 1434
1428 1435
1429 //////////////////////////////////////////////// 1436 ////////////////////////////////////////////////
1430 // 1437 //
1431 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me); 1438 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me);
1432 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me) { 1439 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
1433 char *host = tok.next(); 1440 char *host = tok.next();
1434 if (!tsa(tok, token_semi)) return false; 1441 if (!tsa(tok, token_semi)) return false;
1435 me.set_verify(host); 1442 me.set_verify(host);
1436 me.set_verifier(add_verify_host(host)); 1443 me.set_verifier(add_verify_host(host));
1437 return true; 1444 return true;
1438 } 1445 }
1439 1446
1440 1447
1441 //////////////////////////////////////////////// 1448 ////////////////////////////////////////////////
1442 // 1449 //
1443 bool parse_generic(TOKEN &tok, CONFIG &dc, CONTEXT &me); 1450 bool parse_generic(TOKEN &tok, CONFIG &dc, CONTEXT &me);
1444 bool parse_generic(TOKEN &tok, CONFIG &dc, CONTEXT &me) { 1451 bool parse_generic(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
1445 char *regx = tok.next(); 1452 char *regx = tok.next();
1446 char *msg = tok.next(); 1453 char *msg = tok.next();
1447 if (!tsa(tok, token_semi)) return false; 1454 if (!tsa(tok, token_semi)) return false;
1448 if (me.set_generic(regx, msg)) { 1455 if (me.set_generic(regx, msg)) {
1449 tok.token_error("invalid regular expression %s", regx, regx); 1456 tok.token_error("invalid regular expression %s", regx, regx);
1450 return false; 1457 return false;
1451 } 1458 }
1452 return true; 1459 return true;
1453 } 1460 }
1454 1461
1455 1462
1456 //////////////////////////////////////////////// 1463 ////////////////////////////////////////////////
1457 // 1464 //
1458 bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me); 1465 bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me);
1459 bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me) { 1466 bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
1460 int days = tok.nextint(); 1467 int days = tok.nextint();
1461 char *fn = tok.next(); 1468 char *fn = tok.next();
1462 if (!tsa(tok, token_semi)) return false; 1469 if (!tsa(tok, token_semi)) return false;
1463 me.set_autowhite(fn); 1470 me.set_autowhite(fn);
1464 me.set_whitelister(add_whitelister_file(fn, days)); 1471 me.set_whitelister(add_whitelister_file(fn, days));
1465 return true; 1472 return true;
1466 } 1473 }
1467 1474
1468 1475
1469 //////////////////////////////////////////////// 1476 ////////////////////////////////////////////////
1470 // 1477 //
1471 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me); 1478 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me);
1472 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me) { 1479 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
1473 char *st = tok.next(); 1480 char *st = tok.next();
1474 if ((st == token_black) || (st == token_white) || (st == token_unknown) || (st == token_inherit)) { 1481 if ((st == token_black) || (st == token_white) || (st == token_unknown) || (st == token_inherit)) {
1475 me.set_from_default(st); 1482 me.set_from_default(st);
1476 } 1483 }
1477 else { 1484 else {
1478 tok.push(st); 1485 tok.push(st);
1479 } 1486 }
1480 if (!tsa(tok, token_lbrace)) return false; 1487 if (!tsa(tok, token_lbrace)) return false;
1481 while (true) { 1488 while (true) {
1482 char *have = tok.next(); 1489 char *have = tok.next();
1483 if (!have) break; 1490 if (!have) break;
1484 if (have == token_rbrace) break; 1491 if (have == token_rbrace) break;
1485 if (have == token_semi) { 1492 if (have == token_semi) {
1486 // optional separators 1493 // optional separators
1487 } 1494 }
1488 else if (have == token_dccfrom) { 1495 else if (have == token_dccfrom) {
1489 if (!tsa(tok, token_lbrace)) return false; 1496 if (!tsa(tok, token_lbrace)) return false;
1490 bool keeping = false; 1497 bool keeping = false;
1491 bool many = false; 1498 bool many = false;
1492 while (true) { 1499 while (true) {
1493 char *have = tok.next(); 1500 char *have = tok.next();
1494 if (!have) break; 1501 if (!have) break;
1495 if (have == token_rbrace) break; 1502 if (have == token_rbrace) break;
1496 if (have == token_ok) { 1503 if (have == token_ok) {
1497 keeping = true; 1504 keeping = true;
1498 many = false; 1505 many = false;
1499 continue; 1506 continue;
1500 } 1507 }
1501 else if (have == token_many) { 1508 else if (have == token_many) {
1502 keeping = true; 1509 keeping = true;
1503 many = true; 1510 many = true;
1504 continue; 1511 continue;
1505 } 1512 }
1506 else if (have == token_ok2) { 1513 else if (have == token_ok2) {
1507 keeping = false; 1514 keeping = false;
1508 continue; 1515 continue;
1509 } 1516 }
1510 if (have == token_envfrom) { 1517 if (have == token_envfrom) {
1511 have = tok.next(); 1518 have = tok.next();
1512 if (keeping) { 1519 if (keeping) {
1513 me.add_from(have, (many) ? token_black : token_white); 1520 me.add_from(have, (many) ? token_black : token_white);
1514 } 1521 }
1515 } 1522 }
1516 else if (have == token_substitute) { 1523 else if (have == token_substitute) {
1517 if (tok.next() == token_mailhost) { 1524 if (tok.next() == token_mailhost) {
1518 have = tok.next(); 1525 have = tok.next();
1519 me.add_from(have, (many) ? token_black : token_white); 1526 me.add_from(have, (many) ? token_black : token_white);
1520 } 1527 }
1521 } 1528 }
1522 tok.skipeol(); 1529 tok.skipeol();
1523 } 1530 }
1524 } 1531 }
1525 else { 1532 else {
1526 // may be a valid email address or domain name 1533 // may be a valid email address or domain name
1527 char *st = tok.next(); 1534 char *st = tok.next();
1528 if ((st == token_white) || (st == token_black) || (st == token_unknown) || (st == token_inherit)) { 1535 if ((st == token_white) || (st == token_black) || (st == token_unknown) || (st == token_inherit)) {
1529 me.add_from(have, st); 1536 me.add_from(have, st);
1530 } 1537 }
1531 else { 1538 else {
1532 CONTEXTP con = me.find_from_context_name(st); 1539 CONTEXTP con = me.find_from_context_name(st);
1533 if (con) { 1540 if (con) {
1534 me.add_from_context(have, con); 1541 me.add_from_context(have, con);
1535 } 1542 }
1536 else { 1543 else {
1537 tok.token_error("white/black/unknown/inherit or child context name", st); 1544 tok.token_error("white/black/unknown/inherit or child context name", st);
1538 return false; 1545 return false;
1539 } 1546 }
1540 } 1547 }
1541 } 1548 }
1542 } 1549 }
1543 return tsa(tok, token_semi); 1550 return tsa(tok, token_semi);
1544 } 1551 }
1545 1552
1546 1553
1547 //////////////////////////////////////////////// 1554 ////////////////////////////////////////////////
1548 // 1555 //
1549 bool parse_rate(TOKEN &tok, CONFIG &dc, CONTEXT &me); 1556 bool parse_rate(TOKEN &tok, CONFIG &dc, CONTEXT &me);
1550 bool parse_rate(TOKEN &tok, CONFIG &dc, CONTEXT &me) { 1557 bool parse_rate(TOKEN &tok, CONFIG &dc, CONTEXT &me) {
1551 char *def = tok.next(); 1558 char *def = tok.next();
1552 tok.push(def); 1559 tok.push(def);
1553 if (def != token_lbrace) me.set_default_rate(tok.nextint()); 1560 if (def != token_lbrace) me.set_default_rate(tok.nextint());
1554 if (!tsa(tok, token_lbrace)) return false; 1561 if (!tsa(tok, token_lbrace)) return false;
1555 while (true) { 1562 while (true) {
1556 char *have = tok.next(); 1563 char *have = tok.next();
1557 if (!have) break; 1564 if (!have) break;
1558 if (have == token_rbrace) break; 1565 if (have == token_rbrace) break;
1559 if (have == token_semi) { 1566 if (have == token_semi) {
1560 // optional separators 1567 // optional separators
1561 } 1568 }
1562 else { 1569 else {
1563 me.add_rate(have, tok.nextint()); 1570 me.add_rate(have, tok.nextint());
1564 } 1571 }
1565 } 1572 }
1566 return tsa(tok, token_semi); 1573 return tsa(tok, token_semi);
1567 } 1574 }
1568 1575
1569 1576
1570 //////////////////////////////////////////////// 1577 ////////////////////////////////////////////////
1571 // 1578 //
1572 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent); 1579 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent);
1573 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent) { 1580 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent) {
1574 char *name = tok.next(); 1581 char *name = tok.next();
1575 if (!tsa(tok, token_lbrace)) return false; 1582 if (!tsa(tok, token_lbrace)) return false;
1576 CONTEXTP con = new CONTEXT(parent, name); 1583 CONTEXTP con = new CONTEXT(parent, name);
1577 1584
1578 while (true) { 1585 while (true) {
1579 char *have = tok.next(); 1586 char *have = tok.next();
1580 if (!have) break; 1587 if (!have) break;
1581 if (have == token_rbrace) break; // done 1588 if (have == token_rbrace) break; // done
1582 if (have == token_dnsbl) { 1589 if (have == token_dnsbl) {
1583 if (!parse_dnsbl(tok, dc, *con)) return false; 1590 if (!parse_dnsbl(tok, dc, *con)) return false;
1584 } 1591 }
1585 else if (have == token_dnsbll) { 1592 else if (have == token_dnsbll) {
1586 if (!parse_dnsbll(tok, dc, *con)) return false; 1593 if (!parse_dnsbll(tok, dc, *con)) return false;
1587 } 1594 }
1588 else if (have == token_content) { 1595 else if (have == token_content) {
1589 if (!parse_content(tok, dc, *con)) return false; 1596 if (!parse_content(tok, dc, *con)) return false;
1590 } 1597 }
1591 else if (have == token_envto) { 1598 else if (have == token_envto) {
1592 if (!parse_envto(tok, dc, *con)) return false; 1599 if (!parse_envto(tok, dc, *con)) return false;
1593 } 1600 }
1594 else if (have == token_verify) { 1601 else if (have == token_verify) {
1595 if (!parse_verify(tok, dc, *con)) return false; 1602 if (!parse_verify(tok, dc, *con)) return false;
1596 } 1603 }
1597 else if (have == token_generic) { 1604 else if (have == token_generic) {
1598 if (!parse_generic(tok, dc, *con)) return false; 1605 if (!parse_generic(tok, dc, *con)) return false;
1599 } 1606 }
1600 else if (have == token_autowhite) { 1607 else if (have == token_autowhite) {
1601 if (!parse_autowhite(tok, dc, *con)) return false; 1608 if (!parse_autowhite(tok, dc, *con)) return false;
1602 } 1609 }
1603 else if (have == token_envfrom) { 1610 else if (have == token_envfrom) {
1604 if (!parse_envfrom(tok, dc, *con)) return false; 1611 if (!parse_envfrom(tok, dc, *con)) return false;
1605 } 1612 }
1606 else if (have == token_rate) { 1613 else if (have == token_rate) {
1607 if (parent || dc.default_context) tok.token_error("rate limit ignored in non default context"); 1614 if (parent || dc.default_context) tok.token_error("rate limit ignored in non default context");
1608 if (!parse_rate(tok, dc, *con)) return false; 1615 if (!parse_rate(tok, dc, *con)) return false;
1609 } 1616 }
1610 else if (have == token_context) { 1617 else if (have == token_context) {
1611 if (!parse_context(tok, dc, con)) return false; 1618 if (!parse_context(tok, dc, con)) return false;
1612 } 1619 }
1613 else { 1620 else {
1614 tok.token_error("context keyword", have); 1621 tok.token_error("context keyword", have);
1615 return false; 1622 return false;
1616 } 1623 }
1617 } 1624 }
1618 1625
1619 if (!tsa(tok, token_semi)) { 1626 if (!tsa(tok, token_semi)) {
1620 delete con; 1627 delete con;
1621 return false; 1628 return false;
1622 } 1629 }
1623 dc.add_context(con); 1630 dc.add_context(con);
1624 if (parent) parent->add_context(con); 1631 if (parent) parent->add_context(con);
1625 return true; 1632 return true;
1626 } 1633 }
1627 1634
1628 1635
1629 //////////////////////////////////////////////// 1636 ////////////////////////////////////////////////
1630 // parse a config file 1637 // parse a config file
1631 // 1638 //
1632 bool load_conf(CONFIG &dc, char *fn) { 1639 bool load_conf(CONFIG &dc, char *fn) {
1633 int count = 0; 1640 int count = 0;
1634 TOKEN tok(fn, &dc.config_files); 1641 TOKEN tok(fn, &dc.config_files);
1635 while (true) { 1642 while (true) {
1636 char *have = tok.next(); 1643 char *have = tok.next();
1637 if (!have) break; 1644 if (!have) break;
1638 if (have == token_context) { 1645 if (have == token_context) {
1639 if (!parse_context(tok, dc, NULL)) { 1646 if (!parse_context(tok, dc, NULL)) {
1640 tok.token_error("load_conf() failed to parse context"); 1647 tok.token_error("load_conf() failed to parse context");
1641 return false; 1648 return false;
1642 } 1649 }
1643 else count++; 1650 else count++;
1644 } 1651 }
1645 else { 1652 else {
1646 tok.token_error(token_context, have); 1653 tok.token_error(token_context, have);
1647 return false; 1654 return false;
1648 } 1655 }
1649 } 1656 }
1650 tok.token_error("load_conf() found %d contexts in %s", count, fn); 1657 tok.token_error("load_conf() found %d contexts in %s", count, fn);
1651 return (dc.default_context) ? true : false; 1658 return (dc.default_context) ? true : false;
1652 } 1659 }
1653 1660
1654 1661
1655 //////////////////////////////////////////////// 1662 ////////////////////////////////////////////////
1656 // init the tokens 1663 // init the tokens
1657 // 1664 //
1658 void token_init() { 1665 void token_init() {
1659 token_autowhite = register_string("autowhite"); 1666 token_autowhite = register_string("autowhite");
1660 token_black = register_string("black"); 1667 token_black = register_string("black");
1661 token_cctld = register_string("cctld"); 1668 token_cctld = register_string("cctld");
1662 token_content = register_string("content"); 1669 token_content = register_string("content");
1663 token_context = register_string("context"); 1670 token_context = register_string("context");
1664 token_dccbulk = register_string("dcc_bulk_threshold"); 1671 token_dccbulk = register_string("dcc_bulk_threshold");
1665 token_dccfrom = register_string("dcc_from"); 1672 token_dccfrom = register_string("dcc_from");
1666 token_dccgrey = register_string("dcc_greylist"); 1673 token_dccgrey = register_string("dcc_greylist");
1667 token_dccto = register_string("dcc_to"); 1674 token_dccto = register_string("dcc_to");
1668 token_default = register_string("default"); 1675 token_default = register_string("default");
1669 token_dnsbl = register_string("dnsbl"); 1676 token_dnsbl = register_string("dnsbl");
1670 token_dnsbll = register_string("dnsbl_list"); 1677 token_dnsbll = register_string("dnsbl_list");
1671 token_envfrom = register_string("env_from"); 1678 token_envfrom = register_string("env_from");
1672 token_envto = register_string("env_to"); 1679 token_envto = register_string("env_to");
1673 token_filter = register_string("filter"); 1680 token_filter = register_string("filter");
1674 token_generic = register_string("generic"); 1681 token_generic = register_string("generic");
1675 token_host_limit = register_string("host_limit"); 1682 token_host_limit = register_string("host_limit");
1676 token_html_limit = register_string("html_limit"); 1683 token_html_limit = register_string("html_limit");
1677 token_html_tags = register_string("html_tags"); 1684 token_html_tags = register_string("html_tags");
1678 token_ignore = register_string("ignore"); 1685 token_ignore = register_string("ignore");
1679 token_include = register_string("include"); 1686 token_include = register_string("include");
1680 token_inherit = register_string("inherit"); 1687 token_inherit = register_string("inherit");
1681 token_lbrace = register_string("{"); 1688 token_lbrace = register_string("{");
1682 token_mailhost = register_string("mail_host"); 1689 token_mailhost = register_string("mail_host");
1683 token_many = register_string("many"); 1690 token_many = register_string("many");
1684 token_no = register_string("no"); 1691 token_no = register_string("no");
1685 token_off = register_string("off"); 1692 token_off = register_string("off");
1686 token_ok = register_string("ok"); 1693 token_ok = register_string("ok");
1687 token_ok2 = register_string("ok2"); 1694 token_ok2 = register_string("ok2");
1688 token_on = register_string("on"); 1695 token_on = register_string("on");
1689 token_rate = register_string("rate_limit"); 1696 token_rate = register_string("rate_limit");
1690 token_rbrace = register_string("}"); 1697 token_rbrace = register_string("}");
1691 token_require = register_string("require_match"); 1698 token_require = register_string("require_match");
1692 token_semi = register_string(";"); 1699 token_semi = register_string(";");
1693 token_soft = register_string("soft"); 1700 token_soft = register_string("soft");
1694 token_spamassassin = register_string("spamassassin"); 1701 token_spamassassin = register_string("spamassassin");
1695 token_substitute = register_string("substitute"); 1702 token_substitute = register_string("substitute");
1696 token_tld = register_string("tld"); 1703 token_tld = register_string("tld");
1697 token_unknown = register_string("unknown"); 1704 token_unknown = register_string("unknown");
1698 token_uribl = register_string("uribl"); 1705 token_uribl = register_string("uribl");
1699 token_verify = register_string("verify"); 1706 token_verify = register_string("verify");
1700 token_white = register_string("white"); 1707 token_white = register_string("white");
1701 token_yes = register_string("yes"); 1708 token_yes = register_string("yes");
1702 1709
1703 if (gethostname(myhostname, HOST_NAME_MAX+1) != 0) { 1710 if (gethostname(myhostname, HOST_NAME_MAX+1) != 0) {
1704 strncpy(myhostname, "localhost", HOST_NAME_MAX+1); 1711 strncpy(myhostname, "localhost", HOST_NAME_MAX+1);
1705 } 1712 }
1706 myhostname[HOST_NAME_MAX] = '\0'; // ensure null termination 1713 myhostname[HOST_NAME_MAX] = '\0'; // ensure null termination
1707 token_myhostname = register_string(myhostname); 1714 token_myhostname = register_string(myhostname);
1708 } 1715 }