Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

flt_livefilter.c

Go to the documentation of this file.
00001 
00008 /* {{{ Initial comments */
00009 /*
00010  * $LastChangedDate: 2004-04-01 18:34:17 +0200 (Thu, 01 Apr 2004) $
00011  * $LastChangedRevision: 50 $
00012  * $LastChangedBy: ckruse $
00013  *
00014  */
00015 /* }}} */
00016 
00017 /* {{{ Includes */
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     /* go to the next token */
00129     for(;*ptr && isspace(*ptr);ptr++);
00130 
00131     *pos = ptr;
00132 
00133     /* decide, what it is */
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         /* read string */
00174         if((ret = read_string(ptr+1)) != 0) return ret;
00175 
00176         /* safe new position */
00177         *pos = ptr + flt_lf_str.len + 2;
00178 
00179         /* return token */
00180         return TOK_STR;
00181       default:
00182         if(*ptr) {
00183           /* find end */
00184           for(;*ptr && isalnum(*ptr);ptr++);
00185 
00186           /* safe identifier */
00187           str_char_set(&flt_lf_str,*pos,ptr - *pos);
00188 
00189           /* set position */
00190           *pos = ptr;
00191 
00192           /* return token */
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     /* we have to search the right position due to the precedence */
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; /* true: both undefined */
00403       }
00404       else {
00405         if(l == (u_char *)1 && r == (u_char *)1) {
00406           ret = (u_char *)1; /* true: both true */
00407         }
00408         else {
00409           if(!l || !r || l == (u_char *)1 || r == (u_char *)1) {
00410             ret = NULL;      /* false: only one of them has this value */
00411           }
00412           else {
00413             if(cf_strcasecmp(l,r) == 0) {
00414               ret = (u_char *)1; /* true: strings are equal */
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;      /* false: both are undefined */
00434       }
00435       else {
00436         if(l == (u_char *)1 && r == (u_char *)1) {
00437           ret = NULL;      /* false: both are true */
00438         }
00439         else {
00440           if(!l || !r || l == (u_char *)1 || r == (u_char *)1) {
00441             ret = (u_char *)1; /* true: only one of them has this value */
00442           }
00443           else {
00444             if(cf_strcasecmp(l,r) == 0) {
00445               ret = NULL;      /* false: strings are equal */
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; /* true: both are undefined */
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;      /* false: only one undefined */
00487           }
00488           else {
00489             if(cf_strcasecmp(r,l) == 0) {
00490               ret = (char *)1; /* true: strings are equal */
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 /* eof */

Generated on Sun Apr 25 16:37:38 2004 for Classic Forum by doxygen 1.3.5