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

flt_urlrewrite.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 <time.h>
00024 
00025 #include <string.h>
00026 #include <ctype.h>
00027 #include <pcre.h>
00028 #include <sys/types.h>
00029 
00030 #include "readline.h"
00031 #include "hashlib.h"
00032 #include "utils.h"
00033 #include "configparser.h"
00034 #include "cfcgi.h"
00035 #include "template.h"
00036 #include "clientlib.h"
00037 /* }}} */
00038 
00039 #define DEFAULT_URLREWRITE_SIZE  5
00040 
00041 #define MACRO_NODE_OPERATOR      0
00042 #define MACRO_NODE_VALUE         1
00043 
00044 #define MACRO_OP_NOT             0
00045 #define MACRO_OP_AND             1
00046 #define MACRO_OP_OR              2
00047 
00048 typedef struct s_macro_node {
00049    int type;
00050    union {
00051      void *ptr_data;
00052      int int_data;
00053    } data;
00054 
00055    struct s_macro_node *left,
00056                        *right,
00057                        *parent;
00058 
00059 } t_macro_node;
00060 
00061 typedef struct s_urlrewrite {
00062   pcre *regexp;
00063   pcre_extra *regexp_extra;
00064   t_macro_node *macro_tree;
00065   const u_char *replacement;
00066   unsigned long int match_count;
00067   int *match_arr;
00068 } t_urlrewrite;
00069 
00070 t_urlrewrite **UrlRewrites = NULL;
00071 int UrlRewriteCount = 0;
00072 int UrlRewriteSize = 0;
00073 
00074 int is_macro_true(t_macro_node *tree) {
00075   t_string *data;
00076   int op_type;
00077 
00078   if(!tree)
00079     return 0;
00080 
00081   switch(tree->type) {
00082     case MACRO_NODE_VALUE:
00083       data = (t_string *)tree->data.ptr_data;
00084       if(!data->len)
00085         return 0;
00086       if(!cf_strcmp(data->content, "true")) {
00087         return 1;
00088       } else if(!cf_strcmp(data->content, "logged_in")) {
00089         return cf_hash_get(GlobalValues,"UserName",8) ? 1 : 0;
00090       }
00091       return 0;
00092       break;
00093     case MACRO_NODE_OPERATOR: {
00094       op_type = tree->data.int_data;
00095       switch(op_type) {
00096         case MACRO_OP_NOT:
00097           return !is_macro_true(tree->right);
00098         case MACRO_OP_AND:
00099           return is_macro_true(tree->left) && is_macro_true(tree->right);
00100         case MACRO_OP_OR:
00101           return is_macro_true(tree->left) || is_macro_true(tree->right);
00102         default:
00103           return 0;
00104       }
00105       break;
00106     default:
00107       return 0;
00108     }
00109   }
00110 }
00111 
00112 void free_macro_tree(t_macro_node *tree) {
00113   if(!tree)
00114     return;
00115   if(tree->left)
00116     free_macro_tree(tree->left);
00117   if(tree->right)
00118     free_macro_tree(tree->right);
00119   switch(tree->type) {
00120     case MACRO_NODE_VALUE:
00121       str_cleanup((t_string *)tree->data.ptr_data);
00122       free(tree->data.ptr_data);
00123       break;
00124     default:
00125       break;
00126   }
00127   free(tree);
00128 }
00129 
00130 t_macro_node *parse_macro(const u_char *str) {
00131   t_macro_node *cur_node;
00132   t_string left_side;
00133   int n_braces;
00134   int had_zero_brace;
00135   u_char op;
00136   u_char *buf;
00137   u_char *nstr;
00138   u_char *ptr;
00139 
00140   n_braces = 0;
00141   had_zero_brace = 0;
00142 
00143   // see if we can strip of uneeded braces at beggining / end of string
00144   for(ptr = (u_char *)str; *ptr; ptr++) {
00145     if(*ptr == ')') {
00146       if(n_braces == 1 && *(ptr+1))
00147         had_zero_brace = 1;
00148       n_braces--;
00149       if(n_braces < 0) { // too many ")"
00150         return NULL;
00151       }
00152     } else if(*ptr == '(') {
00153       n_braces++;
00154     }
00155   }
00156 
00157   if(n_braces != 0) { // too many "("
00158     return NULL;
00159   }
00160 
00161   // duplicate so that we can modify it
00162   nstr = strdup(str);
00163 
00164   // if these braces are just outside, like(a & b) => strip them
00165   if(!had_zero_brace && nstr[0] == '(' && nstr[strlen(nstr)-1] == ')') {
00166     nstr[strlen(nstr)-1] = 0;
00167   }
00168 
00169   cur_node = (t_macro_node *)fo_alloc(NULL,1,sizeof(t_macro_node),FO_ALLOC_MALLOC);
00170   if(!cur_node) {
00171     free(nstr);
00172     return NULL;
00173   }
00174 
00175   str_init(&left_side);
00176 
00177   n_braces = 0;
00178 
00179   if(!had_zero_brace && nstr[0] == '(' && nstr[strlen(nstr)-1] == ')') {
00180     ptr = nstr + 1;
00181   } else {
00182     ptr = nstr;
00183   }
00184 
00185   for(; *ptr; ptr++) {
00186     if(n_braces > 0) {
00187       if(*ptr == ')') { // close brace
00188         str_char_append(&left_side, *ptr);
00189         n_braces--;
00190         continue;
00191       } else if(!isspace(*ptr)) { // ignore spaces
00192         str_char_append(&left_side, *ptr);
00193       }
00194       continue;
00195     }
00196     if(*ptr == '!') { // negation operator
00197       if(left_side.len) { // something already on the left side?
00198         free(nstr);
00199         free(cur_node);
00200         str_cleanup(&left_side);
00201         return NULL;
00202       }
00203       break;
00204     } else if(*ptr == '(') { // open brace
00205       str_char_append(&left_side, *ptr);
00206       n_braces++;
00207       continue;
00208     } else if(*ptr == '&' || *ptr == '|') {
00209       break;
00210     } else if(!isalpha(*ptr) && !isspace(*ptr) && *ptr != '_') { // only letters and underscore allowed
00211       free(nstr);
00212       free(cur_node);
00213       str_cleanup(&left_side);
00214       return NULL;
00215     } else if(isspace(*ptr)) { // ignore spaces
00216       continue;
00217     }
00218     str_char_append(&left_side, *ptr);
00219   }
00220 
00221   cur_node->parent = NULL;
00222 
00223   // end of string => no operator found
00224   if(!*ptr) {
00225     // this is a value
00226     if(!left_side.len) { // parse error
00227       free(nstr);
00228       free(cur_node);
00229       str_cleanup(&left_side);
00230       return NULL;
00231     }
00232 
00233     //(value) => remove braces
00234     if(left_side.content[0] == '(' && left_side.content[left_side.len-1] == ')') {
00235       if(left_side.len == 2) { // "()" => parse error
00236         free(nstr);
00237         free(cur_node);
00238         str_cleanup(&left_side);
00239         return NULL;
00240       }
00241       buf = strdup(left_side.content);
00242       str_char_set(&left_side, buf + 1, left_side.len - 2);
00243       free(buf);
00244     }
00245 
00246     cur_node->type = MACRO_NODE_VALUE;
00247     cur_node->left = NULL;
00248     cur_node->right = NULL;
00249     cur_node->data.ptr_data = fo_alloc(NULL,1,sizeof(t_string),FO_ALLOC_MALLOC);
00250     str_init((t_string *)cur_node->data.ptr_data);
00251     str_str_set((t_string *)cur_node->data.ptr_data, &left_side);
00252     str_cleanup(&left_side);
00253     free(nstr);
00254 
00255     return cur_node;
00256   }
00257 
00258   op = *ptr++;
00259 
00260   cur_node->type = MACRO_NODE_OPERATOR;
00261 
00262   switch(op) {
00263     case '!':
00264       str_cleanup(&left_side);
00265       cur_node->data.int_data = MACRO_OP_NOT;
00266       cur_node->left = NULL;
00267       cur_node->right = parse_macro((const u_char *)ptr);
00268       if(!cur_node->right) {
00269         free(nstr);
00270         free(cur_node);
00271         return NULL;
00272       }
00273       cur_node->right->parent = cur_node;
00274       break;
00275     case '&':
00276       cur_node->data.int_data = MACRO_OP_AND;
00277       cur_node->left = parse_macro((const u_char *)left_side.content);
00278       str_cleanup(&left_side);
00279       if(!cur_node->left) {
00280         free(nstr);
00281         free(cur_node);
00282         return NULL;
00283       }
00284       cur_node->left->parent = cur_node;
00285       cur_node->right = parse_macro((const u_char *)ptr);
00286       if(!cur_node->right) {
00287       free(cur_node->left);
00288         free(nstr);
00289         free(cur_node);
00290         return NULL;
00291       }
00292       cur_node->right->parent = cur_node;
00293       break;
00294     case '|':
00295       cur_node->data.int_data = MACRO_OP_OR;
00296       cur_node->left = parse_macro((const u_char *)left_side.content);
00297       str_cleanup(&left_side);
00298       if(!cur_node->left) {
00299         free(nstr);
00300         free(cur_node);
00301         return NULL;
00302       }
00303       cur_node->left->parent = cur_node;
00304       cur_node->right = parse_macro((const u_char *)ptr);
00305       if(!cur_node->right) {
00306         free(cur_node->left);
00307         free(nstr);
00308         free(cur_node);
00309         return NULL;
00310       }
00311       cur_node->right->parent = cur_node;
00312       break;
00313     default:
00314       str_cleanup(&left_side);
00315       break;
00316   }
00317 
00318   free(nstr);
00319   return cur_node;
00320 }
00321 
00322 int treat_link(t_string *dest, u_char *src) {
00323   int i, j;
00324   int res;
00325   int nbr;
00326   u_char buf[3];
00327   u_char *ptr;
00328 
00329   for(i = 0; i < UrlRewriteCount; i++) {
00330     if(!is_macro_true(UrlRewrites[i]->macro_tree)) {
00331       continue;
00332     }
00333     res = pcre_exec(UrlRewrites[i]->regexp, UrlRewrites[i]->regexp_extra, src, strlen(src), 0, 0, UrlRewrites[i]->match_arr,(UrlRewrites[i]->match_count + 1) * 3);
00334     if(res >= 0) { // didn't match
00335       break; // matched
00336     }
00337   }
00338 
00339   if(i == UrlRewriteCount) { // nothing matched
00340     str_char_set(dest, src, strlen(src));
00341     return 0;
00342   }
00343 
00344   for(j = 0; j < strlen(UrlRewrites[i]->replacement); j++) {
00345     if(UrlRewrites[i]->replacement[j] == '$') { // replacement varialbe
00346       if(isdigit(UrlRewrites[i]->replacement[j+1])) {
00347         if(isdigit(UrlRewrites[i]->replacement[j+2])) {
00348           strncpy(buf, &UrlRewrites[i]->replacement[j+1], 2);
00349           buf[2] = 0;
00350         } else {
00351           strncpy(buf, &UrlRewrites[i]->replacement[j+1], 1);
00352           buf[1] = 0;
00353         }
00354         nbr = atoi(buf);
00355         res = pcre_get_substring(src, UrlRewrites[i]->match_arr,(UrlRewrites[i]->match_count + 1) * 3, nbr,(const char **)&ptr);
00356         // error => ignore
00357         if(res < 0) {
00358           str_char_append(dest, UrlRewrites[i]->replacement[j]);
00359           continue;
00360         }
00361         str_chars_append(dest, ptr, res);
00362         pcre_free_substring(ptr);
00363         if(isdigit(UrlRewrites[i]->replacement[j+2])) {
00364           j += 2;
00365         } else {
00366           j++;
00367         }
00368         continue;
00369       }
00370     }
00371     str_char_append(dest, UrlRewrites[i]->replacement[j]);
00372   }
00373 
00374   return 0;
00375 }
00376 
00377 int execute_filter(t_cf_hash *head,t_configuration *dc,t_configuration *vc,t_cl_thread *thread,t_cf_template *tpl) {
00378   const t_cf_tpl_variable *msg_content;
00379   t_string content, link;
00380   u_char *ptr, *ptr_end_attr, *ptr_end_tag, *ptr_end_elem, *ptr_link;
00381   int res;
00382 
00383   str_init(&content);
00384 
00385   // get old message(this plugin has to be called *after* flt_posting!
00386   msg_content = tpl_cf_getvar(tpl, "message");
00387 
00388   if(!msg_content) // is not set? do nothing.
00389     return FLT_OK;
00390 
00391   ptr = msg_content->data->content;
00392 
00393   for(; *ptr; ptr++) {
00394     if(!cf_strncmp(ptr, "<a href=\"", 9)) {
00395       str_init(&link);
00396 
00397       ptr += 9;
00398       ptr_end_attr = strchr(ptr, '"');
00399       ptr_end_tag = strchr(ptr_end_attr, '>');
00400       ptr_end_elem = strchr(ptr_end_tag, '<');
00401 
00402       // not found?
00403       if(!ptr_end_attr || !ptr_end_tag || !ptr_end_elem) {
00404         // ignore
00405         str_cleanup(&link);
00406         str_chars_append(&content, "<a href=\"", 9);
00407         continue;
00408       }
00409 
00410       ptr_link = strndup(ptr,(int)(ptr_end_attr - ptr));
00411       if(!ptr_link) {
00412         str_cleanup(&link);
00413         str_chars_append(&content, "<a href=\"", 9);
00414         continue;
00415       }
00416 
00417       res = treat_link(&link, ptr_link);
00418       free(ptr_link);
00419 
00420       if(res < 0) {
00421         str_cleanup(&link);
00422         str_chars_append(&content, "<a href=\"", 9);
00423         continue;
00424       }
00425 
00426       str_chars_append(&content, "<a href=\"", 9);
00427       str_str_append(&content, &link);
00428       str_chars_append(&content, ptr_end_attr,(int)(ptr_end_tag - ptr_end_attr + 1));
00429       str_str_append(&content, &link);
00430 
00431       ptr = ptr_end_elem - 1;
00432 
00433       str_cleanup(&link);
00434     } else {
00435       str_char_append(&content, *ptr);
00436     }
00437   }
00438 
00439   tpl_cf_setvar(tpl,"message", content.content, content.len, 0);
00440   str_cleanup(&content);
00441 
00442   return FLT_OK;
00443 }
00444 
00445 
00446 int add_rewriterule(t_configfile *cfile,t_conf_opt *opt,u_char **args,int argnum) {
00447   t_urlrewrite **n_rewrites;
00448   t_urlrewrite *n_rewrite;
00449   int alloc_type;
00450   const u_char *error;
00451   int err_offset;
00452 
00453   if(UrlRewriteCount + 1 > UrlRewriteSize) {
00454     if(!UrlRewriteSize) {
00455       alloc_type = FO_ALLOC_MALLOC;
00456     } else {
00457       alloc_type = FO_ALLOC_REALLOC;
00458     }
00459     UrlRewriteSize += DEFAULT_URLREWRITE_SIZE;
00460     n_rewrites = fo_alloc(UrlRewrites, sizeof(t_urlrewrite *), UrlRewriteSize, alloc_type);
00461     if(!n_rewrites) {
00462       return 1;
00463     }
00464     UrlRewrites = n_rewrites;
00465   }
00466   n_rewrite = fo_alloc(NULL, sizeof(t_urlrewrite), 1, FO_ALLOC_MALLOC);
00467   if(!n_rewrite)
00468     return 1;
00469 
00470   n_rewrite->macro_tree = parse_macro(args[2]);
00471   if(!n_rewrite->macro_tree) {
00472     free(n_rewrite);
00473     return 1;
00474   }
00475 
00476   n_rewrite->replacement = strdup(args[1]);
00477   if(!n_rewrite->replacement) {
00478     free_macro_tree(n_rewrite->macro_tree);
00479     free(n_rewrite);
00480   }
00481 
00482   n_rewrite->regexp = pcre_compile(args[0], 0, (const char **)&error, &err_offset, NULL);
00483   if(!n_rewrite->regexp) {
00484     fprintf(stderr,"flt_urlrewrite: Regexp error with \"%s\": %s\n", args[0], error);
00485     free_macro_tree(n_rewrite->macro_tree);
00486     free((void *)n_rewrite->replacement);
00487     free(n_rewrite);
00488     return 1;
00489   }
00490   n_rewrite->regexp_extra = pcre_study(n_rewrite->regexp, 0, (const char **)&error);
00491   if(error) {
00492     printf("Regexp study error with \"%s\": %s\n", args[0], error);
00493     pcre_free(n_rewrite->regexp);
00494     free_macro_tree(n_rewrite->macro_tree);
00495     free((void *)n_rewrite->replacement);
00496     free(n_rewrite);
00497     return 1;
00498   }
00499   n_rewrite->match_count = 0;
00500   pcre_fullinfo(n_rewrite->regexp, n_rewrite->regexp_extra, PCRE_INFO_CAPTURECOUNT, &(n_rewrite->match_count));
00501   n_rewrite->match_arr = (int *)fo_alloc(NULL, sizeof(int),(n_rewrite->match_count + 1) * 3, FO_ALLOC_MALLOC);
00502   if(!n_rewrite->match_arr) {
00503     pcre_free(n_rewrite->regexp_extra);
00504     pcre_free(n_rewrite->regexp);
00505     free_macro_tree(n_rewrite->macro_tree);
00506     free((void *)n_rewrite->replacement);
00507     free(n_rewrite);
00508   }
00509 
00510   UrlRewrites[UrlRewriteCount++] = n_rewrite;
00511 
00512   return 0;
00513 }
00514 
00515 void flt_urlrewrite_cleanup(void) {
00516   // cleanup stuff
00517   int i;
00518 
00519   for(i = 0; i < UrlRewriteCount; i++) {
00520     pcre_free(UrlRewrites[i]->regexp_extra);
00521     pcre_free(UrlRewrites[i]->regexp);
00522     free_macro_tree(UrlRewrites[i]->macro_tree);
00523     free((void *)UrlRewrites[i]->replacement);
00524     free(UrlRewrites[i]->match_arr);
00525     free(UrlRewrites[i]);
00526   }
00527 
00528   if(UrlRewrites)
00529     free(UrlRewrites);
00530 }
00531 
00532 t_conf_opt flt_urlrewrite_config[] = {
00533   { "URLRewrite",  add_rewriterule, NULL },
00534   { NULL, NULL, NULL }
00535 };
00536 
00537 t_handler_config flt_urlrewrite_handlers[] = {
00538   { POSTING_HANDLER, execute_filter },
00539   { 0, NULL }
00540 };
00541 
00542 t_module_config flt_urlrewrite = {
00543   flt_urlrewrite_config,
00544   flt_urlrewrite_handlers,
00545   NULL,
00546   NULL,
00547   NULL,
00548   flt_urlrewrite_cleanup
00549 };
00550 
00551 /* eof */

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