00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "config.h"
00019 #include "defines.h"
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <ctype.h>
00025 #include <time.h>
00026 #include <sys/types.h>
00027
00028 #include "readline.h"
00029 #include "hashlib.h"
00030 #include "utils.h"
00031 #include "configparser.h"
00032 #include "cfcgi.h"
00033 #include "template.h"
00034 #include "clientlib.h"
00035 #include "charconvert.h"
00036
00037
00038
00039 static const u_char *symbols[] = {
00040 "TOK_EOS", "TOK_EQ", "TOK_NE",
00041 "TOK_OR", "TOK_AND", "TOK_ID",
00042 "TOK_STR", "TOK_CONTAINS", "TOK_LPAREN",
00043 "TOK_RPAREN"
00044 };
00045
00046 #define flt_lf_get_type(x) (symbols[x])
00047
00048 #define PREC_ID 60
00049 #define PREC_EQ 50
00050 #define PREC_AND 40
00051 #define PREC_OR 30
00052 #define PREC_PAREN 20
00053
00054 #define TOK_EOS 0x00
00055 #define TOK_EQ 0x01
00056 #define TOK_NE 0x02
00057 #define TOK_OR 0x03
00058 #define TOK_AND 0x04
00059 #define TOK_ID 0x05
00060 #define TOK_STR 0x06
00061 #define TOK_CONTAINS 0x07
00062 #define TOK_LPAREN 0x08
00063 #define TOK_RPAREN 0x09
00064 #define TOK_CONTAINS_NOT 0x0A
00065
00066 typedef struct s_node {
00067 int type,prec;
00068 u_char *content;
00069
00070 struct s_node *left,*right,*parent,*argument;
00071 } t_flt_lf_node;
00072
00073 static t_flt_lf_node *flt_lf_first = NULL;
00074 static int flt_lf_active = 0;
00075
00076 static t_string flt_lf_str = { 0, 0, NULL };
00077
00078 u_char *case_strstr(const u_char *haystack,const u_char *needle) {
00079 size_t len1 = strlen(haystack);
00080 size_t len2 = strlen(needle);
00081 int i;
00082
00083 if(len1 < len2) return NULL;
00084 if(len1 == len2) return cf_strcasecmp(haystack,needle) == 0 ? (u_char *)haystack : NULL;
00085
00086 for(i=0;i<=len1-len2;i++) {
00087 if(cf_strncasecmp(haystack+i,needle,len2) == 0) return (u_char *)(haystack+i);
00088 }
00089
00090 return NULL;
00091 }
00092
00093 int read_string(register u_char *ptr) {
00094 str_init(&flt_lf_str);
00095
00096 for(;*ptr;ptr++) {
00097 switch(*ptr) {
00098 case '\\':
00099 switch(*(++ptr)) {
00100 case 'n':
00101 str_char_append(&flt_lf_str,'\n');
00102 break;
00103 case 't':
00104 str_char_append(&flt_lf_str,'\t');
00105 break;
00106 case '"':
00107 str_char_append(&flt_lf_str,'"');
00108 break;
00109 default:
00110 str_char_append(&flt_lf_str,*ptr);
00111 break;
00112 }
00113 case '"':
00114 return 0;
00115 default:
00116 str_char_append(&flt_lf_str,*ptr);
00117 }
00118 }
00119
00120 return -1;
00121 }
00122
00123 int flt_lf_scanner(u_char *str,u_char **pos) {
00124 register u_char *ptr = *pos;
00125 int ret;
00126
00127 for(;*ptr;ptr++) {
00128
00129 for(;*ptr && isspace(*ptr);ptr++);
00130
00131 *pos = ptr;
00132
00133
00134 switch(*ptr) {
00135 case '=':
00136 if(*(ptr + 1) == '~') {
00137 *pos = ptr + 2;
00138 str_char_set(&flt_lf_str,ptr,2);
00139 return TOK_CONTAINS;
00140 }
00141 else {
00142 *pos = ptr + 1;
00143 str_char_set(&flt_lf_str,ptr,1);
00144 return TOK_EQ;
00145 }
00146 case '(':
00147 str_char_set(&flt_lf_str,ptr,1);
00148 *pos = ptr + 1;
00149 return TOK_LPAREN;
00150 case ')':
00151 str_char_set(&flt_lf_str,ptr,1);
00152 *pos = ptr + 1;
00153 return TOK_RPAREN;
00154 case '!':
00155 str_char_set(&flt_lf_str,ptr,2);
00156 *pos = ptr + 2;
00157
00158 if(*(ptr + 1) == '~') {
00159 return TOK_CONTAINS_NOT;
00160 }
00161 else {
00162 return TOK_NE;
00163 }
00164 case '|':
00165 str_char_set(&flt_lf_str,ptr,1);
00166 *pos = ptr + 1;
00167 return TOK_OR;
00168 case '&':
00169 str_char_set(&flt_lf_str,ptr,1);
00170 *pos = ptr + 1;
00171 return TOK_AND;
00172 case '"':
00173
00174 if((ret = read_string(ptr+1)) != 0) return ret;
00175
00176
00177 *pos = ptr + flt_lf_str.len + 2;
00178
00179
00180 return TOK_STR;
00181 default:
00182 if(*ptr) {
00183
00184 for(;*ptr && isalnum(*ptr);ptr++);
00185
00186
00187 str_char_set(&flt_lf_str,*pos,ptr - *pos);
00188
00189
00190 *pos = ptr;
00191
00192
00193 return TOK_ID;
00194 }
00195 else {
00196 return TOK_EOS;
00197 }
00198 }
00199 }
00200
00201 return TOK_EOS;
00202 }
00203
00204 t_flt_lf_node *flt_lf_insert_node(t_flt_lf_node *cur,t_flt_lf_node *tok,t_flt_lf_node *root) {
00205 t_flt_lf_node *n = cur;
00206
00207 if(!cur) {
00208 if(root) root->argument = tok;
00209 else flt_lf_first = tok;
00210 return tok;
00211 }
00212
00213 if(cur->prec <= tok->prec) {
00214 tok->parent = cur;
00215
00216 if(cur->left) {
00217 cur->right = tok;
00218 }
00219 else {
00220 cur->left = tok;
00221 }
00222 }
00223 else {
00224
00225 while(cur && cur->prec > tok->prec) {
00226 n = cur;
00227 cur = cur->parent;
00228 }
00229
00230 if(!cur) {
00231 if(root) root->argument = tok;
00232 else flt_lf_first = tok;
00233 tok->left = n;
00234 tok->left->parent = tok;
00235 }
00236 else {
00237 tok->parent = cur;
00238
00239 if(cur->right) {
00240 tok->left = cur->right;
00241 tok->left->parent = tok;
00242 cur->right = tok;
00243 }
00244 else {
00245 tok->left = cur->left;
00246 tok->left->parent = tok;
00247 cur->left = tok;
00248 }
00249 }
00250 }
00251
00252 return tok;
00253 }
00254
00255 int flt_lf_parse_string(u_char *str,u_char **pos,t_cf_template *tpl,t_flt_lf_node *node,t_flt_lf_node *root_node,t_configuration *dc) {
00256 int ret = 0;
00257 t_flt_lf_node *current = NULL;
00258 t_name_value *cs = cfg_get_value(dc,"ExternCharset");
00259
00260 while((ret = flt_lf_scanner(str,pos)) > 0) {
00261 current = fo_alloc(NULL,1,sizeof(*current),FO_ALLOC_CALLOC);
00262 current->type = ret;
00263
00264 switch(ret) {
00265 case TOK_STR:
00266 case TOK_ID:
00267 current->prec = PREC_ID;
00268
00269 if(cf_strcmp(cs->values[0],"UTF-8")) {
00270 if((current->content = charset_convert(flt_lf_str.content,flt_lf_str.len,cs->values[0],"UTF-8",NULL)) == NULL) {
00271 current->content = flt_lf_str.content;
00272 str_init(&flt_lf_str);
00273 }
00274 else {
00275 str_cleanup(&flt_lf_str);
00276 }
00277 }
00278 else {
00279 current->content = flt_lf_str.content;
00280 str_init(&flt_lf_str);
00281 }
00282
00283 break;
00284 case TOK_LPAREN:
00285 current->prec = PREC_PAREN;
00286 current->argument = fo_alloc(NULL,1,sizeof(*current->argument),FO_ALLOC_CALLOC);
00287 if((ret = flt_lf_parse_string(str,pos,tpl,NULL,current,dc)) != 0) return ret;
00288 break;
00289 case TOK_RPAREN:
00290 free(current);
00291 return 0;
00292 break;
00293 case TOK_CONTAINS_NOT:
00294 case TOK_CONTAINS:
00295 case TOK_NE:
00296 case TOK_EQ:
00297 current->prec = PREC_EQ;
00298 break;
00299 case TOK_OR:
00300 current->prec = PREC_OR;
00301 break;
00302 case TOK_AND:
00303 current->prec = PREC_AND;
00304 break;
00305 }
00306
00307 node = flt_lf_insert_node(node,current,root_node);
00308 }
00309
00310 return 0;
00311 }
00312
00313 int flt_lf_form(t_cf_hash *head,t_configuration *dc,t_configuration *vc,t_cf_template *begin,t_cf_template *end) {
00314 u_char *filter_str,*pos;
00315
00316 if(flt_lf_active) {
00317 tpl_cf_setvar(begin,"livefilter","1",1,0);
00318
00319 if(head) {
00320 if((filter_str = cf_cgi_get(head,"lf")) != NULL) {
00321 pos = filter_str;
00322 flt_lf_parse_string(filter_str,&pos,begin,NULL,NULL,dc);
00323 tpl_cf_setvar(begin,"lf",filter_str,strlen(filter_str),1);
00324 }
00325 }
00326
00327 return FLT_OK;
00328 }
00329
00330 return FLT_DECLINE;
00331 }
00332
00333 u_char *flt_lf_evaluate(t_flt_lf_node *n,t_message *msg,u_int64_t tid) {
00334 u_char *l = NULL,*r = NULL;
00335 u_char buff[50];
00336 u_char *ret = NULL;
00337
00338 if(!n) return NULL;
00339
00340 switch(n->type) {
00341 case TOK_CONTAINS:
00342 l = flt_lf_evaluate(n->left,msg,tid);
00343 r = flt_lf_evaluate(n->right,msg,tid);
00344
00345 if(l == NULL && r == NULL) {
00346 ret = (u_char *)1;
00347 }
00348 else {
00349 if(l == (u_char *)1 && r == (u_char *)1) {
00350 ret = (u_char *)1;
00351 }
00352 else {
00353 if(l == NULL || r == NULL || l == (u_char *)1 || r == (u_char *)1) {
00354 ret = NULL;
00355 }
00356 else {
00357 if(case_strstr(l,r)) {
00358 ret = (u_char *)1;
00359 }
00360 else {
00361 ret = NULL;
00362 }
00363 }
00364 }
00365 }
00366
00367 return ret;
00368
00369 case TOK_CONTAINS_NOT:
00370 l = flt_lf_evaluate(n->left,msg,tid);
00371 r = flt_lf_evaluate(n->right,msg,tid);
00372
00373 if(l == NULL && r == NULL) {
00374 ret = NULL;
00375 }
00376 else {
00377 if(l == (u_char *)1 && r == (u_char *)1) {
00378 ret = NULL;
00379 }
00380 else {
00381 if(l == NULL || r == NULL || l == (u_char *)1 || r == (u_char *)1) {
00382 ret = (u_char *)1;
00383 }
00384 else {
00385 if(case_strstr(l,r)) {
00386 ret = NULL;
00387 }
00388 else {
00389 ret = (u_char *)1;
00390 }
00391 }
00392 }
00393 }
00394
00395 return ret;
00396
00397 case TOK_EQ:
00398 l = flt_lf_evaluate(n->left,msg,tid);
00399 r = flt_lf_evaluate(n->right,msg,tid);
00400
00401 if(l == NULL && r == NULL) {
00402 ret = (u_char *)1;
00403 }
00404 else {
00405 if(l == (u_char *)1 && r == (u_char *)1) {
00406 ret = (u_char *)1;
00407 }
00408 else {
00409 if(!l || !r || l == (u_char *)1 || r == (u_char *)1) {
00410 ret = NULL;
00411 }
00412 else {
00413 if(cf_strcasecmp(l,r) == 0) {
00414 ret = (u_char *)1;
00415 }
00416 else {
00417 ret = NULL;
00418 }
00419 }
00420 }
00421 }
00422
00423 if(l > (u_char *)1) free(l);
00424 if(r > (u_char *)1) free(r);
00425
00426 return ret;
00427
00428 case TOK_NE:
00429 l = flt_lf_evaluate(n->left,msg,tid);
00430 r = flt_lf_evaluate(n->right,msg,tid);
00431
00432 if(l == NULL && r == NULL) {
00433 ret = NULL;
00434 }
00435 else {
00436 if(l == (u_char *)1 && r == (u_char *)1) {
00437 ret = NULL;
00438 }
00439 else {
00440 if(!l || !r || l == (u_char *)1 || r == (u_char *)1) {
00441 ret = (u_char *)1;
00442 }
00443 else {
00444 if(cf_strcasecmp(l,r) == 0) {
00445 ret = NULL;
00446 }
00447 else {
00448 ret = (u_char *)1;
00449 }
00450 }
00451 }
00452 }
00453
00454 if(l > (u_char *)1) free(l);
00455 if(r > (u_char *)1) free(r);
00456
00457 return ret;
00458
00459 case TOK_OR:
00460 l = flt_lf_evaluate(n->left,msg,tid);
00461 if(l) ret = (u_char *)1;
00462
00463 if(!ret) {
00464 r = flt_lf_evaluate(n->right,msg,tid);
00465 if(r) ret = (u_char *)1;
00466 }
00467
00468 if(l > (u_char *)1) free(l);
00469 if(r > (u_char *)1) free(r);
00470
00471 return ret;
00472
00473 case TOK_AND:
00474 l = flt_lf_evaluate(n->left,msg,tid);
00475 r = flt_lf_evaluate(n->right,msg,tid);
00476
00477 if(!l && !r) {
00478 ret = (u_char *)1;
00479 }
00480 else {
00481 if(r == (u_char *)1 && l == (u_char *)1) {
00482 ret = (u_char *)1;
00483 }
00484 else {
00485 if(!l || !r || r == (u_char *)1 || l == (u_char *)1) {
00486 ret = NULL;
00487 }
00488 else {
00489 if(cf_strcasecmp(r,l) == 0) {
00490 ret = (char *)1;
00491 }
00492 else {
00493 ret = NULL;
00494 }
00495 }
00496 }
00497 }
00498
00499 if(l > (u_char *)1) free(l);
00500 if(r > (u_char *)1) free(r);
00501
00502 return ret;
00503
00504 case TOK_ID:
00505 switch(*n->content) {
00506 case 'm':
00507 snprintf(buff,50,"%lld",msg->mid);
00508 return strdup(buff);
00509 case 't':
00510 snprintf(buff,50,"%lld",tid);
00511 return strdup(buff);
00512 case 'a':
00513 return strdup(msg->author);
00514 case 's':
00515 return strdup(msg->subject);
00516 case 'c':
00517 return strdup(msg->category);
00518 case 'd':
00519 snprintf(buff,50,"%ld",msg->date);
00520 return strdup(buff);
00521 case 'l':
00522 snprintf(buff,50,"%d",msg->level);
00523 return strdup(buff);
00524 case 'v':
00525 return (u_char *)(msg->may_show == 0 ? 0 : 1);
00526 }
00527 case TOK_STR:
00528 return strdup(n->content);
00529 case TOK_LPAREN:
00530 if(n->argument) {
00531 ret = flt_lf_evaluate(n->argument,msg,tid);
00532 }
00533 else ret = NULL;
00534 return ret;
00535 }
00536
00537 return NULL;
00538 }
00539
00540 int flt_lf_filter(t_cf_hash *head,t_configuration *dc,t_configuration *vc,t_message *msg,unsigned long long tid,int mode) {
00541 if(flt_lf_active) {
00542 if(flt_lf_first) {
00543 if(flt_lf_evaluate(flt_lf_first,msg,tid) == 0) {
00544 msg->may_show = 0;
00545 }
00546 }
00547
00548 return FLT_OK;
00549 }
00550
00551 return FLT_DECLINE;
00552 }
00553
00554 int flt_lf_handle_command(t_configfile *cf,t_conf_opt *opt,u_char **args,int argnum) {
00555 flt_lf_active = cf_strcmp(args[0],"yes") == 0;
00556 return 0;
00557 }
00558
00559 void flt_lf_cleanup(void) {
00560 }
00561
00562 t_conf_opt config[] = {
00563 { "ActivateLiveFilter", flt_lf_handle_command, NULL },
00564 { NULL, NULL, NULL }
00565 };
00566
00567 t_handler_config handlers[] = {
00568 { VIEW_INIT_HANDLER, flt_lf_form },
00569 { VIEW_LIST_HANDLER, flt_lf_filter },
00570 { 0, NULL }
00571 };
00572
00573 t_module_config flt_livefilter = {
00574 config,
00575 handlers,
00576 NULL,
00577 NULL,
00578 NULL,
00579 flt_lf_cleanup
00580 };
00581
00582