00001
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "config.h"
00020 #include "defines.h"
00021
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <time.h>
00026 #include <sys/types.h>
00027 #include <sys/stat.h>
00028
00029 #include "readline.h"
00030 #include "hashlib.h"
00031 #include "utils.h"
00032 #include "configparser.h"
00033 #include "cfcgi.h"
00034 #include "template.h"
00035 #include "clientlib.h"
00036
00037
00038 struct {
00039 int HighlightVisitedPostings;
00040 u_char *VisitedPostingsColorF;
00041 u_char *VisitedPostingsColorB;
00042 u_char *VisitedFile;
00043 t_cf_tree tree;
00044 } Cfg = { 0, NULL, NULL, NULL, { NULL, NULL, NULL } };
00045
00046 int flt_visited_compare(t_cf_tree_dataset *a,t_cf_tree_dataset *b) {
00047 if(*((u_int64_t *)a->key) < *((u_int64_t *)b->key)) return -1;
00048 if(*((u_int64_t *)a->key) > *((u_int64_t *)b->key)) return 1;
00049
00050 return 0;
00051 }
00052
00053 void flt_visited_create_tree() {
00054 if(Cfg.tree.root == NULL) {
00055 FILE *fd;
00056 struct stat st;
00057 u_int64_t *field;
00058 u_int32_t i,nmem = 0;
00059
00060 t_cf_tree_dataset data;
00061 data.data = NULL;
00062
00063 if(stat(Cfg.VisitedFile,&st) == 0) {
00064 nmem = st.st_size / sizeof(*field);
00065 field = fo_alloc(NULL,nmem,sizeof(*field),FO_ALLOC_MALLOC);
00066
00067 if((fd = fopen(Cfg.VisitedFile,"r")) == NULL) {
00068 free(field);
00069 return;
00070 }
00071
00072 fread(field,sizeof(*field),st.st_size / sizeof(*field),fd);
00073 fclose(fd);
00074
00075 cf_tree_init(&Cfg.tree,flt_visited_compare,NULL);
00076 for(i=0;i<nmem;i++) {
00077 data.key = memdup(&field[i],sizeof(*field));
00078 cf_tree_insert(&Cfg.tree,NULL,&data);
00079 }
00080
00081 free(field);
00082 }
00083 else {
00084 if((fd = fopen(Cfg.VisitedFile,"w")) != NULL) {
00085 fclose(fd);
00086 }
00087 }
00088 }
00089 }
00090
00091
00092 void *flt_visited_is_visited(void *vmid) {
00093 u_int64_t *mid = (u_int64_t *)vmid;
00094 t_cf_tree_dataset data;
00095
00096 data.data = NULL;
00097
00098 if(Cfg.VisitedFile) {
00099 flt_visited_create_tree();
00100
00101 data.key = mid;
00102 if(cf_tree_find(&Cfg.tree,Cfg.tree.root,&data)) {
00103 return (void *)mid;
00104 }
00105 }
00106
00107 return NULL;
00108 }
00109
00110
00111 void *flt_visited_mark_visited(void *vmid) {
00112 u_int64_t *mid = (u_int64_t *)vmid;
00113 t_cf_tree_dataset data;
00114 FILE *fd;
00115
00116 data.data = NULL;
00117
00118 if(Cfg.VisitedFile) {
00119 flt_visited_create_tree();
00120
00121 data.key = memdup(mid,sizeof(*mid));
00122 if(cf_tree_find(&Cfg.tree,Cfg.tree.root,&data) == NULL) {
00123 if((fd = fopen(Cfg.VisitedFile,"a")) != NULL) {
00124 cf_tree_insert(&Cfg.tree,NULL,&data);
00125 fwrite(mid,sizeof(*mid),1,fd);
00126 fclose(fd);
00127
00128 return vmid;
00129 }
00130 }
00131
00132 free(data.key);
00133 }
00134
00135 return NULL;
00136 }
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 int execute_filter(t_cf_hash *head,t_configuration *dc,t_configuration *vc,int sock) {
00151 u_char *uname = cf_hash_get(GlobalValues,"UserName",8);
00152 t_cf_tree_dataset data = { NULL, NULL };
00153 u_char *cmid;
00154 u_char *ctid;
00155 u_int64_t mid,tid;
00156 FILE *fd;
00157 int ret;
00158 rline_t tsd;
00159 t_message *msg;
00160 t_cl_thread thread;
00161
00162 if(uname && Cfg.VisitedFile) {
00163
00164 cf_register_mod_api_ent("flt_visited","is_visited",flt_visited_is_visited);
00165 cf_register_mod_api_ent("flt_visited","mark_visited",flt_visited_mark_visited);
00166
00167 if(head && Cfg.HighlightVisitedPostings) {
00168 cmid = cf_cgi_get(head,"m");
00169 ctid = cf_cgi_get(head,"mv");
00170
00171
00172 if(ctid) {
00173 tid = strtoull(ctid,NULL,10);
00174 memset(&tsd,0,sizeof(tsd));
00175 memset(&thread,0,sizeof(thread));
00176
00177 if(tid) {
00178 #ifdef CF_SHARED_MEM
00179 ret = cf_get_message_through_shm((void *)sock,&thread,NULL,tid,0,CF_KILL_DELETED);
00180 #else
00181 ret = cf_get_message_through_sock(sock,&tsd,&thread,NULL,tid,0,CF_KILL_DELETED);
00182 #endif
00183
00184 if(ret == -1) {
00185 return FLT_DECLINE;
00186 }
00187
00188 if((fd = fopen(Cfg.VisitedFile,"a")) == NULL) {
00189 return FLT_DECLINE;
00190 }
00191
00192 for(msg=thread.messages;msg;msg=msg->next) {
00193 data.key = memdup(&msg->mid,sizeof(msg->mid));
00194
00195 if(!cf_tree_find(&Cfg.tree,Cfg.tree.root,&data)) {
00196 fwrite(&msg->mid,sizeof(msg->mid),1,fd);
00197 cf_tree_insert(&Cfg.tree,NULL,&data);
00198 }
00199 }
00200
00201 cleanup_struct(&thread);
00202 fclose(fd);
00203 }
00204 }
00205
00206
00207 else if(cmid) {
00208 mid = strtoull(cmid,NULL,10);
00209
00210 if(mid) {
00211 flt_visited_create_tree();
00212
00213 data.key = memdup(&mid,sizeof(mid));
00214
00215 if(!cf_tree_find(&Cfg.tree,Cfg.tree.root,&data)) {
00216 cf_tree_insert(&Cfg.tree,NULL,&data);
00217 fd = fopen(Cfg.VisitedFile,"a");
00218 if(fd) {
00219 fwrite(&mid,sizeof(mid),1,fd);
00220 fclose(fd);
00221 }
00222 }
00223 else {
00224 free(data.key);
00225 }
00226 }
00227 }
00228
00229 return FLT_OK;
00230 }
00231 }
00232
00233 return FLT_DECLINE;
00234 }
00235
00236 int set_col(t_cf_hash *head,t_configuration *dc,t_configuration *vc,t_cf_template *begin,t_cf_template *end) {
00237 if(Cfg.VisitedPostingsColorF || Cfg.VisitedPostingsColorB) {
00238 tpl_cf_setvar(begin,"visitedcol","1",1,0);
00239
00240 if(Cfg.VisitedPostingsColorF && *Cfg.VisitedPostingsColorF) {
00241 tpl_cf_setvar(begin,"visitedcolfg",Cfg.VisitedPostingsColorF,strlen(Cfg.VisitedPostingsColorF),0);
00242 }
00243 if(Cfg.VisitedPostingsColorB && *Cfg.VisitedPostingsColorB) {
00244 tpl_cf_setvar(begin,"visitedcolbg",Cfg.VisitedPostingsColorB,strlen(Cfg.VisitedPostingsColorB),0);
00245 }
00246 }
00247
00248 return FLT_OK;
00249 }
00250
00251 int posting_handler(t_cf_hash *head,t_configuration *dc,t_configuration *vc,t_cl_thread *thread,t_cf_template *tpl) {
00252 return set_col(head,dc,vc,tpl,NULL);
00253 }
00254
00255 int mark_visited(t_cf_hash *head,t_configuration *dc,t_configuration *vc,t_message *msg,unsigned long long tid,int mode) {
00256 u_char *uname = cf_hash_get(GlobalValues,"UserName",8);
00257 t_cf_tree_dataset data;
00258
00259 data.data = NULL;
00260
00261 if(uname && Cfg.VisitedFile && Cfg.HighlightVisitedPostings) {
00262 flt_visited_create_tree();
00263
00264 data.key = memdup(&msg->mid,sizeof(msg->mid));
00265 if(cf_tree_find(&Cfg.tree,Cfg.tree.root,&data)) {
00266 tpl_cf_setvar(&msg->tpl,"visited","1",1,0);
00267 }
00268
00269 return FLT_OK;
00270 }
00271
00272 return FLT_DECLINE;
00273 }
00274
00275 int flt_visit_handle_command(t_configfile *cf,t_conf_opt *opt,u_char **args,int argnum) {
00276 if(cf_strcmp(opt->name,"HighlightVisitedPostings") == 0) {
00277 Cfg.HighlightVisitedPostings = !cf_strcmp(args[0],"yes");
00278 }
00279 else if(cf_strcmp(opt->name,"VisitedPostingsColors") == 0) {
00280 if(Cfg.VisitedPostingsColorF) free(Cfg.VisitedPostingsColorF);
00281 if(Cfg.VisitedPostingsColorB) free(Cfg.VisitedPostingsColorB);
00282 Cfg.VisitedPostingsColorF = strdup(args[0]);
00283 Cfg.VisitedPostingsColorB = strdup(args[1]);
00284 }
00285 else if(cf_strcmp(opt->name,"VisitedFile") == 0) {
00286 if(Cfg.VisitedFile) free(Cfg.VisitedFile);
00287 Cfg.VisitedFile = strdup(args[0]);
00288 }
00289
00290 return 0;
00291 }
00292
00293 int flt_visited_validate(t_cf_hash *head,t_configuration *dc,t_configuration *vc,time_t last_modified,int sock) {
00294 struct stat st;
00295
00296 if(Cfg.VisitedFile) {
00297 if(stat(Cfg.VisitedFile,&st) == -1) return FLT_DECLINE;
00298 if(st.st_mtime > last_modified) return FLT_EXIT;
00299 }
00300
00301 return FLT_OK;
00302 }
00303
00304 time_t flt_visited_lm(t_cf_hash *head,t_configuration *dc,t_configuration *vc,int sock) {
00305 struct stat st;
00306
00307 if(Cfg.VisitedFile) {
00308 if(stat(Cfg.VisitedFile,&st) == -1) return -1;
00309 return st.st_mtime;
00310 }
00311
00312
00313 return -1;
00314 }
00315
00316 void flt_visited_cleanup(void) {
00317 if(Cfg.VisitedPostingsColorF) free(Cfg.VisitedPostingsColorF);
00318 if(Cfg.VisitedPostingsColorB) free(Cfg.VisitedPostingsColorB);
00319 if(Cfg.VisitedFile) free(Cfg.VisitedFile);
00320
00321 cf_tree_destroy(&Cfg.tree);
00322 }
00323
00324 t_conf_opt flt_visited_config[] = {
00325 { "HighlightVisitedPostings", flt_visit_handle_command, NULL },
00326 { "VisitedPostingsColors", flt_visit_handle_command, NULL },
00327 { "VisitedFile", flt_visit_handle_command, NULL },
00328 { NULL, NULL, NULL }
00329 };
00330
00331 t_handler_config flt_visited_handlers[] = {
00332 { CONNECT_INIT_HANDLER, execute_filter },
00333 { VIEW_INIT_HANDLER, set_col },
00334 { POSTING_HANDLER, posting_handler },
00335 { VIEW_LIST_HANDLER, mark_visited },
00336 { 0, NULL }
00337 };
00338
00339 t_module_config flt_visited = {
00340 flt_visited_config,
00341 flt_visited_handlers,
00342 flt_visited_validate,
00343 flt_visited_lm,
00344 NULL,
00345 flt_visited_cleanup
00346 };
00347
00348
00349