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
00027 #include <sys/stat.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 struct {
00040 u_char **BlackList;
00041 long BLlen;
00042 int FollowUps;
00043 time_t ShowFrom;
00044 time_t ShowUntil;
00045 u_char *DeletedFile;
00046 t_cf_tree tree;
00047 } Cfg = { NULL, 0, 0, 0, 0, NULL, { NULL, NULL, NULL } };
00048
00049 int flt_deleted_compare(t_cf_tree_dataset *a,t_cf_tree_dataset *b) {
00050 if(*((unsigned long long *)a->key) < *((unsigned long long *)b->key)) return -1;
00051 if(*((unsigned long long *)a->key) > *((unsigned long long *)b->key)) return 1;
00052
00053 return 0;
00054 }
00055
00056 void flt_deleted_create_tree() {
00057 FILE *fd;
00058 struct stat st;
00059 u_int64_t *field;
00060 u_int32_t i,nmem = 0;
00061
00062 t_cf_tree_dataset data;
00063 data.data = NULL;
00064
00065 if(!Cfg.tree.root) {
00066 if(stat(Cfg.DeletedFile,&st) == 0) {
00067 nmem = st.st_size / sizeof(*field);
00068 field = fo_alloc(NULL,nmem,sizeof(*field),FO_ALLOC_MALLOC);
00069
00070 if((fd = fopen(Cfg.DeletedFile,"r")) == NULL) {
00071 free(field);
00072 return;
00073 }
00074
00075 fread(field,sizeof(*field),st.st_size / sizeof(*field),fd);
00076 fclose(fd);
00077
00078 cf_tree_init(&Cfg.tree,flt_deleted_compare,NULL);
00079 for(i=0;i<nmem;i++) {
00080 data.key = memdup(&field[i],sizeof(*field));
00081 cf_tree_insert(&Cfg.tree,NULL,&data);
00082 }
00083
00084 free(field);
00085 }
00086 else {
00087 if((fd = fopen(Cfg.DeletedFile,"w")) !=NULL) {
00088 fclose(fd);
00089 }
00090 }
00091 }
00092 }
00093
00094
00095 int execute_filter(t_cf_hash *head,t_configuration *dc,t_configuration *vc,t_cl_thread *thread,int mode) {
00096 t_name_value *url;
00097 u_char *UserName = cf_hash_get(GlobalValues,"UserName",8);
00098 t_cf_tree_dataset dt;
00099 size_t len;
00100 u_char buff[150];
00101
00102 dt.data = NULL;
00103
00104 if(mode == 0) {
00105 if(UserName) {
00106 url = cfg_get_value(dc,"UBaseURL");
00107
00108 if(Cfg.DeletedFile) {
00109 flt_deleted_create_tree();
00110
00111 dt.key = &thread->tid;
00112
00113 if(cf_tree_find(&Cfg.tree,Cfg.tree.root,&dt)) {
00114 thread->messages->may_show = 0;
00115 delete_subtree(thread->messages);
00116 }
00117 else {
00118 len = snprintf(buff,150,"%s?a=d&t=%lld",url->values[0],thread->tid);
00119 tpl_cf_setvar(&thread->messages->tpl,"dellink",buff,len,1);
00120 }
00121 }
00122 }
00123
00124 return FLT_OK;
00125 }
00126
00127 return FLT_DECLINE;
00128 }
00129
00130 int posting_list_filter(t_cf_hash *head,t_configuration *dc,t_configuration *vc,t_message *msg,unsigned long long tid,int mode) {
00131 long i;
00132
00133 if(Cfg.BLlen) {
00134 for(i=0;i<Cfg.BLlen;i++) {
00135 if(cf_strcasecmp(msg->author,Cfg.BlackList[i]) == 0) {
00136 msg->may_show = 0;
00137
00138 if(Cfg.FollowUps == 0) {
00139 if(!delete_subtree(msg)) {
00140 return FLT_OK;
00141 }
00142 }
00143 }
00144 }
00145 }
00146
00147 if(mode == 0) {
00148 if(Cfg.ShowFrom) {
00149 if(msg->may_show) {
00150 if(msg->date < Cfg.ShowFrom) {
00151 msg->may_show = 0;
00152 }
00153 }
00154 }
00155
00156 if(Cfg.ShowUntil) {
00157 if(msg->may_show) {
00158 if(msg->date > Cfg.ShowUntil) {
00159 msg->may_show = 0;
00160 }
00161 }
00162 }
00163 }
00164
00165 return FLT_OK;
00166 }
00167
00168 int delete_thread(t_cf_hash *head,t_configuration *dc,t_configuration *vc) {
00169 u_char *c_tid,*qs,*a;
00170 FILE *fd;
00171 u_int64_t tid;
00172
00173 if(head && Cfg.DeletedFile) {
00174 qs = getenv("QUERY_STRING");
00175
00176 if(qs) {
00177 a = cf_cgi_get(head,"a");
00178
00179 if(a && cf_strcmp(a,"d") == 0) {
00180 c_tid = cf_cgi_get(head,"t");
00181
00182 if(c_tid) {
00183 tid = strtoull(c_tid,NULL,10);
00184
00185 if(tid) {
00186 flt_deleted_create_tree();
00187
00188 fd = fopen(Cfg.DeletedFile,"a");
00189 if(fd) {
00190 fwrite(&tid,sizeof(tid),1,fd);
00191 fclose(fd);
00192 }
00193 else {
00194 perror("delete_thread: fopen");
00195 }
00196
00197 cf_hash_entry_delete(head,"t",1);
00198 cf_hash_entry_delete(head,"a",1);
00199 }
00200 }
00201 }
00202
00203 return FLT_OK;
00204 }
00205 }
00206
00207 return FLT_DECLINE;
00208 }
00209
00210 int flt_del_handle_command(t_configfile *cf,t_conf_opt *opt,u_char **args,int argnum) {
00211 long i;
00212
00213 if(cf_strcmp(opt->name,"BlackList") == 0) {
00214 if(Cfg.BLlen) {
00215 for(i=0;i<Cfg.BLlen;i++) {
00216 free(Cfg.BlackList[i]);
00217 }
00218 free(Cfg.BlackList);
00219 }
00220
00221 Cfg.BLlen = split(args[0],",",&Cfg.BlackList);
00222 }
00223 else if(cf_strcmp(opt->name,"ShowBlacklistFollowups") == 0) {
00224 Cfg.FollowUps = cf_strcasecmp(args[0],"yes") == 0;
00225 }
00226 else if(cf_strcmp(opt->name,"ShowFrom") == 0) {
00227 Cfg.ShowFrom = strtol(args[0],NULL,10);
00228 }
00229 else if(cf_strcmp(opt->name,"ShowUntil") == 0) {
00230 Cfg.ShowUntil = strtol(args[0],NULL,10);
00231 }
00232 else if(cf_strcmp(opt->name,"DeletedFile") == 0) {
00233 if(Cfg.DeletedFile) free(Cfg.DeletedFile);
00234 Cfg.DeletedFile = strdup(args[0]);
00235 }
00236
00237 return 0;
00238 }
00239
00240 void flt_del_cleanup(void) {
00241 long i;
00242 if(Cfg.BLlen) {
00243 for(i=0;i<Cfg.BLlen;i++) {
00244 free(Cfg.BlackList[i]);
00245 }
00246 free(Cfg.BlackList);
00247 }
00248
00249 if(Cfg.DeletedFile) free(Cfg.DeletedFile);
00250 }
00251
00252 int flt_deleted_validate(t_cf_hash *head,t_configuration *dc,t_configuration *vc,time_t last_modified,int sock) {
00253 struct stat st;
00254
00255 if(Cfg.DeletedFile) {
00256 if(stat(Cfg.DeletedFile,&st) == -1) return FLT_DECLINE;
00257 if(st.st_mtime > last_modified) return FLT_EXIT;
00258 }
00259
00260 return FLT_OK;
00261 }
00262
00263 time_t flt_deleted_lm(t_cf_hash *head,t_configuration *dc,t_configuration *vc,int sock) {
00264 struct stat st;
00265
00266 if(Cfg.DeletedFile) {
00267 if(stat(Cfg.DeletedFile,&st) == -1) return -1;
00268 return st.st_mtime;
00269 }
00270
00271
00272 return -1;
00273 }
00274
00275 t_conf_opt config[] = {
00276 { "BlackList", flt_del_handle_command, NULL },
00277 { "ShowBlacklistFollowups", flt_del_handle_command, NULL },
00278 { "ShowFrom", flt_del_handle_command, NULL },
00279 { "ShowUntil", flt_del_handle_command, NULL },
00280 { "DeletedFile", flt_del_handle_command, NULL },
00281 { NULL, NULL, NULL }
00282 };
00283
00284 t_handler_config handlers[] = {
00285 { INIT_HANDLER, delete_thread },
00286 { VIEW_HANDLER, execute_filter },
00287 { VIEW_LIST_HANDLER, posting_list_filter },
00288 { 0, NULL }
00289 };
00290
00291 t_module_config flt_deleted = {
00292 config,
00293 handlers,
00294 flt_deleted_validate,
00295 flt_deleted_lm,
00296 NULL,
00297 flt_del_cleanup
00298 };
00299
00300