1 /*
2  * Copyright (C) 2000,2001  Florian Sander
3  *
4  * $Id: datahandling.c (1.3.2) for AversE-XP v1.0+ 2003/12/06 [Xp-AvR] Exp $
5  */
6 
incrstats(char * user,char * chan,int type,int value,int set)7 static void incrstats(char *user, char *chan, int type, int value, int set)
8 {
9   globstats *gs, *gs2;
10   locstats *ls, *ls2;
11   int i, ii;
12 
13   if (type >= TOTAL_TYPES)
14     return;
15   if (!user) {
16     debug0("Stats.mod: incrstats(..) Ups, user is NULL!");
17     return;
18   }
19   if (!chan) {
20     debug0("Stats.mod: incrstats(..) Ups, chan is NULL!");
21     return;
22   }
23   for (gs = sdata; gs; gs = gs->next) {
24     if (!strcasecmp(chan, gs->chan))
25       break;
26   }
27   if (!gs) {
28     gs2 = sdata;
29     while (gs2 && gs2->next)
30       gs2 = gs2->next;
31     gs = nmalloc(sizeof(globstats));
32     gs->started = now;
33     gs->peak[S_TOTAL] = gs->peak[S_DAILY] = gs->peak[S_WEEKLY] = gs->peak[S_MONTHLY] = 0;
34     for (i = 0; i < 24; i++) {
35       gs->users[S_USERSUM][i] = 0;
36       gs->users[S_USERCOUNTS][i] = -1;
37     }
38     for (i = 0; i < (TOTAL_TYPES + TOTAL_SPECIAL_TYPES); i++)
39       gs->slocal[S_TOTAL][i] = gs->slocal[S_DAILY][i] = gs->slocal[S_WEEKLY][i] = gs->slocal[S_MONTHLY][i] = NULL;
40     gs->next = NULL;
41     gs->local = NULL;
42     gs->topics = NULL;
43     gs->hosts = NULL;
44     gs->urls = NULL;
45     gs->log = gs->lastlog = NULL;
46     gs->log_length = 0;
47     gs->kicks = NULL;
48     gs->words = NULL;
49     gs->chan = nmalloc(strlen(chan) + 1);
50     strcpy(gs->chan, chan);
51     if (gs2)
52       gs2->next = gs;
53     else
54       sdata = gs;
55   }
56   for (ls = gs->local; ls; ls = ls->next) {
57     if (!strcasecmp(ls->user, user))
58       break;
59   }
60   if (type == T_GSTARTED) {
61     gs->started = value;
62     return;
63   }
64   if (type == T_PEAK) {
65     gs->peak[set] = value;
66     return;
67   }
68   if (!ls) {
69     ls2 = gs->local;
70     while (ls2 && ls2->next)
71       ls2 = ls2->next;
72     ls = nmalloc(sizeof(locstats));
73     ls->started = now;
74     ls->next = NULL;
75     ls->words = NULL;
76     ls->tree = NULL;
77     ls->quotes = NULL;
78     ls->quotefr = 0;
79     ls->flag = 0;
80     for (i = 0; i < TOTAL_TYPES; i++) {
81       ls->values[S_TOTAL][i] = 0;
82       ls->values[S_TODAY][i] = 0;
83       ls->values[S_WEEKLY][i] = 0;
84       ls->values[S_MONTHLY][i] = 0;
85     }
86     ls->user = nmalloc(strlen(user) + 1);
87     strcpy(ls->user, user);
88     ls->u = NULL;
89     if (ls2)
90       ls2->next = ls;
91     else
92       gs->local = ls;
93     for (i = 0; i < (TOTAL_TYPES + TOTAL_SPECIAL_TYPES); i++)
94       ls->snext[S_TOTAL][i] = ls->snext[S_DAILY][i] = ls->snext[S_WEEKLY][i] = ls->snext[S_MONTHLY][i] = NULL;
95     for (i = 0; i < 4; i++) {
96       for (ii = 0; ii < (TOTAL_TYPES + TOTAL_SPECIAL_TYPES); ii++) {
97         ls2 = gs->slocal[i][ii];
98         while (ls2 && ls2->snext[i][ii])
99           ls2 = ls2->snext[i][ii];
100         if (ls2)
101           ls2->snext[i][ii] = ls;
102         else
103           gs->slocal[i][ii] = ls;
104       }
105     }
106   }
107   if (type == T_LSTARTED)
108     ls->started = value;
109   else {
110     if (set > 0)
111       ls->values[set - 1][type] = value;
112     else if (set < 0)
113       ls->values[(set * (-1)) - 1][type] += value;
114     else {
115       ls->values[S_TOTAL][type] += value;
116       ls->values[S_TODAY][type] += value;
117       ls->values[S_WEEKLY][type] += value;
118       ls->values[S_MONTHLY][type] += value;
119     }
120   }
121 }
122 
nincrstats(locstats * ls,int type,int value)123 static void nincrstats(locstats *ls, int type, int value)
124 {
125   ls->values[S_TOTAL][type] += value;
126   ls->values[S_TODAY][type] += value;
127   ls->values[S_WEEKLY][type] += value;
128   ls->values[S_MONTHLY][type] += value;
129 }
130 
initstats(char * chan,char * user)131 static locstats *initstats(char *chan, char *user)
132 {
133   globstats *gs, *gs2;
134   locstats *ls, *ls2;
135   int i, ii;
136 
137   gs = sdata;
138   while (gs) {
139     if (!rfc_casecmp(gs->chan, chan))
140       break;
141     gs = gs->next;
142   }
143   if (!gs) {
144     gs2 = sdata;
145     while (gs2 && gs2->next)
146       gs2 = gs2->next;
147     gs = nmalloc(sizeof(globstats));
148     gs->started = now;
149     gs->peak[S_TOTAL] = gs->peak[S_DAILY] = gs->peak[S_WEEKLY] = gs->peak[S_MONTHLY] = 0;
150     for (i = 0; i < 24; i++) {
151       gs->users[S_USERSUM][i] = 0;
152       gs->users[S_USERCOUNTS][i] = -1;
153     }
154     gs->next = NULL;
155     gs->local = NULL;
156     gs->words = NULL;
157     gs->topics = NULL;
158     gs->hosts = NULL;
159     gs->urls = NULL;
160     gs->log = gs->lastlog = NULL;
161     gs->log_length = 0;
162     gs->kicks = NULL;
163     gs->chan = nmalloc(strlen(chan) + 1);
164     strcpy(gs->chan, chan);
165     for (i = 0; i < (TOTAL_TYPES + TOTAL_SPECIAL_TYPES); i++)
166       gs->slocal[S_TOTAL][i] = gs->slocal[S_DAILY][i] = gs->slocal[S_WEEKLY][i] = gs->slocal[S_MONTHLY][i] = NULL;
167     if (gs2)
168       gs2->next = gs;
169     else
170       sdata = gs;
171   }
172   for (ls = gs->local; ls; ls = ls->next) {
173     if (!rfc_casecmp(ls->user, user))
174       return ls;
175   }
176   if (!ls) {
177     ls2 = gs->local;
178     while (ls2 && ls2->next)
179       ls2 = ls2->next;
180     ls = nmalloc(sizeof(locstats));
181     ls->started = now;
182     ls->next = NULL;
183     ls->words = NULL;
184     ls->tree = NULL;
185     ls->quotes = NULL;
186     ls->quotefr = 0;
187     ls->flag = 0;
188     for (i = 0; i < TOTAL_TYPES; i++) {
189       ls->values[S_TOTAL][i] = 0;
190       ls->values[S_TODAY][i] = 0;
191       ls->values[S_WEEKLY][i] = 0;
192       ls->values[S_MONTHLY][i] = 0;
193     }
194     ls->user = nmalloc(strlen(user) + 1);
195     strcpy(ls->user, user);
196     ls->u = NULL;
197     if (ls2)
198       ls2->next = ls;
199     else
200       gs->local = ls;
201     for (i = 0; i < (TOTAL_TYPES + TOTAL_SPECIAL_TYPES); i++)
202       ls->snext[S_TOTAL][i] = ls->snext[S_DAILY][i] = ls->snext[S_WEEKLY][i] = ls->snext[S_MONTHLY][i] = NULL;
203     for (i = 0; i < 4; i++) {
204       for (ii = 0; ii < (TOTAL_TYPES + TOTAL_SPECIAL_TYPES); ii++) {
205         ls2 = gs->slocal[i][ii];
206         while (ls2 && ls2->snext[i][ii])
207           ls2 = ls2->snext[i][ii];
208         if (ls2)
209           ls2->snext[i][ii] = ls;
210         else
211           gs->slocal[i][ii] = ls;
212       }
213     }
214   }
215   return ls;
216 }
217 
getstats(char * user,char * chan,char * type,int today)218 static int getstats(char *user, char *chan, char *type, int today)
219 {
220   struct stats_global *gs = sdata;
221   struct stats_local *ls;
222   int itype;
223 
224   while (gs) {
225     ls = gs->local;
226     if (!strcasecmp(gs->chan, chan)) {
227       while (ls) {
228         if (!strcasecmp(ls->user, user)) {
229           itype = typetoi(type);
230           if (itype >= 0)
231             return ls->values[today][itype];
232         }
233         ls = ls->next;
234       }
235     }
236     gs = gs->next;
237   }
238   return 0;
239 }
240 
sortstats(struct stats_global * gs,int itype,int today)241 static void sortstats(struct stats_global *gs, int itype, int today)
242 {
243   int again = 1;
244   struct stats_local *last, *p, *c, *n;
245   int a, b, pitype;
246 
247   Context;
248   again = 1;
249   last = NULL;
250   if (itype < 0) {
251     switch (itype) {
252       case T_WPL:
253         sortstats_wpl(gs, today);
254         break;
255       case T_VOCABLES:
256         sortstats_vocables(gs, today);
257         break;
258       case T_WORD:
259         sortstats_word(gs, today);
260         break;
261       case T_IDLE:
262         sortstats_idle(gs, today);
263         break;
264       default:
265         debug1("Missing sorting algorithm for \"%d\"!!!", itype);
266     }
267     return;
268   }
269 
270   pitype = itype;
271   while ((gs->slocal[today][pitype] != last) && (again)) {
272     p = NULL;
273     c = gs->slocal[today][pitype];
274     n = c->snext[today][pitype];
275     again = 0;
276     while (n != last) {
277       if (!c || !n)
278         a = b = 0;
279       else {
280         a = c->values[today][itype];
281         b = n->values[today][itype];
282       }
283       if (a < b) {
284         again = 1;
285         c->snext[today][pitype] = n->snext[today][pitype];
286         n->snext[today][pitype] = c;
287         if (p == NULL)
288           gs->slocal[today][pitype] = n;
289         else
290           p->snext[today][pitype] = n;
291       }
292       p = c;
293       c = n;
294       n = n->snext[today][pitype];
295     }
296     last = c;
297   }
298   Context;
299   return;
300 }
301 
sortstats_wpl(struct stats_global * gs,int today)302 static void sortstats_wpl(struct stats_global *gs, int today)
303 {
304   int again = 1;
305   struct stats_local *last, *p, *c, *n;
306   int a, b, pitype;
307 
308   Context;
309   again = 1;
310   last = NULL;
311   pitype = (T_WPL * (-1)) + TOTAL_TYPES - 1;
312   while ((gs->slocal[today][pitype] != last) && (again)) {
313     p = NULL;
314     c = gs->slocal[today][pitype];
315     n = c->snext[today][pitype];
316     again = 0;
317     while (n != last) {
318       if (!c || !n)
319         a = b = 0;
320       else {
321         if (c->values[today][T_LINES])
322           a = (int) (((float) c->values[today][T_WORDS] / (float) c->values[today][T_LINES]) * 100.0);
323         else
324           a = 0;
325         if (n->values[today][T_LINES])
326           b = (int) (((float) n->values[today][T_WORDS] / (float) n->values[today][T_LINES]) * 100.0);
327         else
328           b = 0;
329       }
330       if (a < b) {
331         again = 1;
332         c->snext[today][pitype] = n->snext[today][pitype];
333         n->snext[today][pitype] = c;
334         if (p == NULL)
335           gs->slocal[today][pitype] = n;
336         else
337           p->snext[today][pitype] = n;
338       }
339       p = c;
340       c = n;
341       n = n->snext[today][pitype];
342     }
343     last = c;
344   }
345   Context;
346   return;
347 }
348 
sortstats_vocables(struct stats_global * gs,int today)349 static void sortstats_vocables(struct stats_global *gs, int today)
350 {
351   int again = 1;
352   struct stats_local *last, *p, *c, *n;
353   int a, b, pitype;
354 
355   Context;
356   again = 1;
357   last = NULL;
358   countvocables(gs);
359   pitype = (T_VOCABLES * (-1)) + TOTAL_TYPES - 1;
360   while ((gs->slocal[today][pitype] != last) && (again)) {
361     p = NULL;
362     c = gs->slocal[today][pitype];
363     n = c->snext[today][pitype];
364     again = 0;
365     while (n != last) {
366       if (!c || !n)
367         a = b = 0;
368       else {
369         a = c->vocables;
370         b = n->vocables;
371       }
372       if (a < b) {
373         again = 1;
374         c->snext[today][pitype] = n->snext[today][pitype];
375         n->snext[today][pitype] = c;
376         if (p == NULL)
377           gs->slocal[today][pitype] = n;
378         else
379           p->snext[today][pitype] = n;
380       }
381       p = c;
382       c = n;
383       n = n->snext[today][pitype];
384     }
385     last = c;
386   }
387   Context;
388   return;
389 }
390 
sortstats_word(struct stats_global * gs,int today)391 static void sortstats_word(struct stats_global *gs, int today)
392 {
393   int again = 1;
394   struct stats_local *last, *p, *c, *n;
395   int a, b, pitype;
396 
397   Context;
398   again = 1;
399   last = NULL;
400   pitype = (T_WORD * (-1)) + TOTAL_TYPES - 1;
401   while ((gs->slocal[today][pitype] != last) && (again)) {
402     p = NULL;
403     c = gs->slocal[today][pitype];
404     n = c->snext[today][pitype];
405     again = 0;
406     while (n != last) {
407       if (!c || !n)
408         a = b = 0;
409       else {
410         if (c->word)
411           a = c->word->nr;
412         else
413           a = 0;
414         if (n->word)
415           b = n->word->nr;
416         else
417           b = 0;
418       }
419       if (a < b) {
420         again = 1;
421         c->snext[today][pitype] = n->snext[today][pitype];
422         n->snext[today][pitype] = c;
423         if (p == NULL)
424           gs->slocal[today][pitype] = n;
425         else
426           p->snext[today][pitype] = n;
427       }
428       p = c;
429       c = n;
430       n = n->snext[today][pitype];
431     }
432     last = c;
433   }
434   Context;
435   return;
436 }
437 
438 /* sort stats by idle-factor (minutes/lines) */
sortstats_idle(struct stats_global * gs,int today)439 static void sortstats_idle(struct stats_global *gs, int today)
440 {
441   int again = 1;
442   struct stats_local *last, *p, *c, *n;
443   int a, b, pitype;
444 
445   Context;
446   again = 1;
447   last = NULL;
448   pitype = (T_IDLE * (-1)) + TOTAL_TYPES - 1;
449   while ((gs->slocal[today][pitype] != last) && (again)) {
450     p = NULL;
451     c = gs->slocal[today][pitype];
452     n = c->snext[today][pitype];
453     again = 0;
454     while (n != last) {
455       if (!c || !n)
456         a = b = 0;
457       else {
458         if (c->values[today][T_LINES])
459           a = (int) (((float) c->values[today][T_MINUTES] / (float) c->values[today][T_LINES]) * 100.0);
460         else
461           a = 0;
462         if (n->values[today][T_LINES])
463           b = (int) (((float) n->values[today][T_MINUTES] / (float) n->values[today][T_LINES]) * 100.0);
464         else
465           b = 0;
466       }
467       if (a < b) {
468         again = 1;
469         c->snext[today][pitype] = n->snext[today][pitype];
470         n->snext[today][pitype] = c;
471         if (p == NULL)
472           gs->slocal[today][pitype] = n;
473         else
474           p->snext[today][pitype] = n;
475       }
476       p = c;
477       c = n;
478       n = n->snext[today][pitype];
479     }
480     last = c;
481   }
482   Context;
483   return;
484 }
485 
countvocables(globstats * gs)486 static void countvocables(globstats *gs)
487 {
488   locstats *ls;
489   wordstats *ws;
490 
491   for (ls = gs->local; ls; ls = ls->next) {
492     ls->vocables = 0;
493     for (ws = ls->words; ws; ws = ws->next)
494       ls->vocables++;
495   }
496 }
497 
sortwordstats(locstats * ls,globstats * gs)498 static void sortwordstats(locstats *ls, globstats *gs)
499 {
500   int again = 1;
501   wordstats *last, *p, *c, *n, *tmp;
502   int a, b;
503 
504   Context;
505   again = 1;
506   last = NULL;
507   if (ls)
508     tmp = ls->words;
509   else
510     tmp = gs->words;
511   while ((tmp != last) && (again)) {
512     p = NULL;
513     if (ls)
514       c = ls->words;
515     else
516       c = gs->words;
517     n = c->next;
518     again = 0;
519     while (n != last) {
520       if (!c || !n)
521         a = b = 0;
522       else {
523         a = c->nr;
524         b = n->nr;
525       }
526       if (a < b) {
527   again = 1;
528   c->next = n->next;
529   n->next = c;
530   if (p == NULL) {
531     if (ls)
532       ls->words = n;
533     else
534       gs->words = n;
535     tmp = n;
536   } else
537     p->next = n;
538       }
539       p = c;
540       c = n;
541       n = n->next;
542     }
543     last = c;
544   }
545   Context;
546   return;
547 }
548 
sorthosts(struct stats_global * gs)549 static void sorthosts(struct stats_global *gs)
550 {
551   int again = 1;
552   hoststr *last, *p, *c, *n;
553   int a, b;
554 
555   Context;
556   again = 1;
557   last = NULL;
558   while ((gs->hosts != last) && (again)) {
559     p = NULL;
560     c = gs->hosts;
561     n = c->next;
562     again = 0;
563     while (n != last) {
564       if (!c || !n)
565         a = b = 0;
566       else {
567         a = c->nr;
568         b = n->nr;
569       }
570       if (a < b) {
571         again = 1;
572         c->next = n->next;
573         n->next = c;
574         if (p == NULL)
575           gs->hosts = n;
576         else
577           p->next = n;
578       }
579       p = c;
580       c = n;
581       n = n->next;
582     }
583     last = c;
584   }
585   Context;
586   return;
587 }
588 
589 /* typetoi(): returns the index of a stat-type */
typetoi(char * type)590 static int typetoi(char *type)
591 {
592   if (!strcasecmp(type, "lstarted"))
593     return T_LSTARTED;
594   else if (!strcasecmp(type, "gstarted"))
595     return T_GSTARTED;
596   else if (!strcasecmp(type, "words"))
597     return T_WORDS;
598   else if (!strcasecmp(type, "letters"))
599     return T_LETTERS;
600   else if (!strcasecmp(type, "minutes"))
601     return T_MINUTES;
602   else if (!strcasecmp(type, "topics"))
603     return T_TOPICS;
604   else if (!strcasecmp(type, "lines"))
605     return T_LINES;
606   else if (!strcasecmp(type, "actions"))
607     return T_ACTIONS;
608   else if (!strcasecmp(type, "kicks"))
609     return T_KICKS;
610   else if (!strcasecmp(type, "modes"))
611     return T_MODES;
612   else if (!strcasecmp(type, "bans"))
613     return T_BANS;
614   else if (!strcasecmp(type, "nicks"))
615     return T_NICKS;
616   else if (!strcasecmp(type, "joins"))
617     return T_JOINS;
618   else if (!strcasecmp(type, "smileys"))
619     return T_SMILEYS;
620   else if (!strcasecmp(type, "questions"))
621     return T_QUESTIONS;
622   else if (!strcasecmp(type, "wpl"))
623     return T_WPL;
624   else if (!strcasecmp(type, "w/l"))
625     return T_WPL;
626   else if (!strcasecmp(type, "word"))
627     return T_WORD;
628   else if (!strcasecmp(type, "vocables"))
629     return T_VOCABLES;
630   else if (!strcasecmp(type, "started"))
631     return T_LSTARTED;
632   else if (!strcasecmp(type, "quote"))
633     return T_QUOTE;
634   else if (!strcasecmp(type, "idle"))
635     return T_IDLE;
636   else {
637     debug1("Stats.mod: Unknown stat type: %s", type);
638     return T_ERROR;
639   }
640 }
641 
findlocstats(char * chan,char * user)642 static locstats *findlocstats(char *chan, char *user)
643 {
644   globstats *gl;
645   locstats *ll;
646 
647   for (gl = sdata; gl; gl = gl->next) {
648     if (!rfc_casecmp(gl->chan, chan))
649       break;
650   }
651   if (!gl)
652     return NULL;
653   for (ll = gl->local; ll; ll = ll->next) {
654     if (!rfc_casecmp(ll->user, user))
655       return ll;
656   }
657   return NULL;
658 }
659 
findglobstats(char * chan)660 static globstats *findglobstats(char *chan)
661 {
662   globstats *gl;
663 
664   for (gl = sdata; gl; gl = gl->next) {
665     if (!rfc_casecmp(gl->chan, chan))
666       break;
667   }
668   return gl;
669 }
670 
write_stats()671 static void write_stats()
672 {
673   char s[125];
674   FILE *f;
675   struct stats_global *gs;
676   struct stats_local *ls;
677   struct stats_userlist *u;
678   struct stats_hostlist *h;
679   int i;
680 
681   Context;
682   if (!statsfile[0])
683     return;
684   sprintf(s, "%s~new", statsfile);
685   f = fopen(s, "w");
686   chmod(s, statsfilemode);
687   if (f == NULL) {
688     putlog(LOG_MISC, "*", "ERROR writing stats file.");
689     return;
690   }
691   fprintf(f, "@ # Statistics from %s.\n", botnetnick);
692   fprintf(f, "@ filever 1\n");
693   fprintf(f, "@ month %d\n", getmonth());
694   for (gs = sdata; gs; gs = gs->next) {
695     fprintf(f, "%s ! %d\n", gs->chan, (int) gs->started);
696     fprintf(f, "%s @ %d\n", gs->chan, gs->peak[S_TOTAL]);
697     fprintf(f, "@ peaks %s %d %d %d %d\n", gs->chan, gs->peak[S_TOTAL],
698             gs->peak[S_DAILY], gs->peak[S_WEEKLY], gs->peak[S_MONTHLY]);
699     for (ls = gs->local; ls; ls = ls->next) {
700       fprintf(f, "%s %s %d", gs->chan, ls->user, (int) ls->started);
701       for (i = 0; i < TOTAL_TYPES; i++)
702         fprintf(f, " %ld", ls->values[S_TOTAL][i]);
703       fprintf(f, "\n");
704       fprintf(f, "@ daily %s %s", gs->chan, ls->user);
705       for (i = 0; i < TOTAL_TYPES; i++)
706         fprintf(f, " %ld", ls->values[S_DAILY][i]);
707       fprintf(f, "\n");
708       fprintf(f, "@ weekly %s %s", gs->chan, ls->user);
709       for (i = 0; i < TOTAL_TYPES; i++)
710         fprintf(f, " %ld", ls->values[S_WEEKLY][i]);
711       fprintf(f, "\n");
712       fprintf(f, "@ monthly %s %s", gs->chan, ls->user);
713       for (i = 0; i < TOTAL_TYPES; i++)
714         fprintf(f, " %ld", ls->values[S_MONTHLY][i]);
715       fprintf(f, "\n");
716       i = 0;
717     }
718   }
719   for (u = suserlist; u; u = u->next) {
720     fprintf(f, "@ user %s %d %d", u->user, u->list, u->addhosts);
721     for (h = u->hosts; h; h = h->next) {
722       fprintf(f, " %s %lu", h->mask, h->lastused);
723     }
724     fprintf(f, "\n");
725     if (u->email || u->homepage) {
726       fprintf(f, "@ uxtra %s", u->user);
727       if (u->email)
728         fprintf(f, " e %s", u->email);
729       if (u->homepage)
730         fprintf(f, " h %s", u->homepage);
731       fprintf(f, "\n");
732     }
733   }
734   fclose(f);
735   unlink(statsfile);
736   movefile(s, statsfile);
737   Context;
738   return;
739 }
740 
read_stats()741 static void read_stats()
742 {
743   FILE *f;
744   char buf[SAVESTATSLENGTH + 1];
745   char *s, *chan, *user, *cmd, *host, *tmp;
746   int i, version, range, month, list, addhosts;
747   struct stats_userlist *u;
748   time_t lastused;
749   locstats *ls;
750   globstats *gs;
751 
752   Context;
753   ls = NULL;
754   gs = NULL;
755   version = 0;
756   month = 0;
757   f = fopen(statsfile, "r");
758   if (f == NULL) {
759     putlog(LOG_MISC, "*", "ERROR reading stats file");
760     return;
761   }
762   free_stats();
763   while (!feof(f)) {
764     buf[0] = 0;
765     s = buf;
766     fgets(s, SAVESTATSLENGTH - 1, f);
767     s[SAVESTATSLENGTH - 1] = 0;
768     if (buf[0] == 0)
769       continue;
770     if (s[strlen(s) - 1] == '\n')
771       s[strlen(s) - 1] = 0;
772     chan = newsplit(&s);
773     if (!strcmp(chan, "@")) {
774       cmd = newsplit(&s);
775       if (!strcmp(cmd, "filever"))
776 	version = atoi(newsplit(&s));
777       else if (!strcmp(cmd, "month"))
778         month = atoi(newsplit(&s));
779       else if (!strcmp(cmd, "peaks")) {
780         chan = newsplit(&s);
781         incrstats("*", chan, T_PEAK, atoi(newsplit(&s)), S_TOTAL);
782         incrstats("*", chan, T_PEAK, atoi(newsplit(&s)), S_DAILY);
783         incrstats("*", chan, T_PEAK, atoi(newsplit(&s)), S_WEEKLY);
784         incrstats("*", chan, T_PEAK, atoi(newsplit(&s)), S_MONTHLY);
785       } else if (!strcmp(cmd, "daily") || !strcmp(cmd, "weekly")
786                  || !strcmp(cmd, "monthly")) {
787         if (!strcmp(cmd, "daily"))
788 	  range = S_DAILY;
789         else if (!strcmp(cmd, "weekly"))
790 	  range = S_WEEKLY;
791         else if (!strcmp(cmd, "monthly"))
792           range = S_MONTHLY;
793         else {
794           debug2("Error while reading statsfile: range uninitialized! (%s %s)", cmd, s);
795           continue;
796         }
797         if ((range == S_MONTHLY) && (month != lastmonth))
798           continue;
799         chan = newsplit(&s);
800         user = newsplit(&s);
801         if ((gs && strcmp(gs->chan, chan)) || !gs) {
802           gs = findglobstats(chan);
803           ls = findlocstats(chan, user);
804         } else {
805           if ((ls && strcmp(ls->user, user)) || !ls)
806             ls = findlocstats(chan, user);
807         }
808         if (!ls)
809           ls = initstats(chan, user);
810         for (i = 0; i < TOTAL_TYPES; i++)
811           ls->values[range][i] = atoi(newsplit(&s));
812       } else if (!strcmp(cmd, "user")) {
813 	user = newsplit(&s);
814 	list = atoi(newsplit(&s));
815 	addhosts = atoi(newsplit(&s));
816 	u = addsuser(user, list, addhosts);
817 	while (s[0]) {
818 	  host = newsplit(&s);
819 	  lastused = (time_t) atoi(newsplit(&s));
820 	  saddhost(u, host, lastused);
821 	}
822       } else if (!strcmp(cmd, "uxtra")) {
823         user = newsplit(&s);
824         u = findsuser_by_name(user);
825         while (u && s[0]) {
826           tmp = newsplit(&s);
827           if (!strcmp(tmp, "e"))
828             setemail(u, newsplit(&s));
829           else
830             sethomepage(u, newsplit(&s));
831         }
832       }
833     } else {
834       user = newsplit(&s);
835       if (!strcmp(user, "!"))
836         incrstats(user, chan, T_GSTARTED, atoi(newsplit(&s)), 1);
837       else if (!strcmp(user, "@"))
838         incrstats(user, chan, T_PEAK, atoi(newsplit(&s)), S_TOTAL);
839       else {
840         incrstats(user, chan, T_LSTARTED, atoi(newsplit(&s)), 1);
841         ls = initstats(chan, user);
842         for (i = 0; i < TOTAL_TYPES; i++)
843           ls->values[S_TOTAL][i] = atoi(newsplit(&s));
844       }
845     }
846   }
847   fclose(f);
848   Context;
849   return;
850 }
851 
reset_tstats()852 static void reset_tstats()
853 {
854   globstats *gs;
855   locstats *ls;
856   int i;
857 
858   Context;
859   putlog(LOG_MISC, "*", "Stats.mod: Resetting today's statistics...");
860   for (gs = sdata; gs; gs = gs->next) {
861     gs->peak[S_TODAY] = 0;
862     free_wordstats(gs->words);
863     gs->words = NULL;
864     free_topics(gs->topics);
865     gs->topics = NULL;
866     free_urls(gs->urls);
867     gs->urls = NULL;
868     free_hosts(gs->hosts);
869     gs->hosts = NULL;
870     free_kicks(gs->kicks);
871     gs->kicks = NULL;
872     for (ls = gs->local; ls; ls = ls->next) {
873       free_wordstats(ls->words);
874       ls->words = NULL;
875       ls->tree = NULL;
876       free_quotes(ls->quotes);
877       ls->quotes = NULL;
878       for (i = 0; i < TOTAL_TYPES; i++)
879         ls->values[S_TODAY][i] = 0;
880     }
881   }
882   Context;
883 }
884 
reset_mwstats(int range)885 static void reset_mwstats(int range)
886 {
887   globstats *gs;
888   locstats *ls;
889   int i;
890 
891   Context;
892   putlog(LOG_MISC, "*", "Stats.mod: Resetting %s statistics...", (range == S_WEEKLY) ? "weekly" : "monthly");
893   for (gs = sdata; gs; gs = gs->next) {
894     gs->peak[range] = 0;
895     for (ls = gs->local; ls; ls = ls->next) {
896       for (i = 0; i < TOTAL_TYPES; i++)
897         ls->values[range][i] = 0;
898     }
899   }
900   Context;
901 }
902 
sort_stats_alphabetically(globstats * gs)903 static void sort_stats_alphabetically(globstats *gs)
904 {
905   locstats *as, *bs, *l, *last;
906   int a, b, again = 1;
907   char *astr, *bstr, n[2];
908 
909   Context;
910   n[0] = n[1] = 0;
911   last = NULL;
912   while ((gs->local != last) && again) {
913     again = 0;
914     l = NULL;
915     as = gs->local;
916     bs = gs->local->next;
917     while(bs) {
918       if (!as)
919         astr = n;
920       else
921         astr = as->user;
922       if (!bs)
923         bstr = n;
924       else
925         bstr = bs->user;
926       a = (int) tolower(astr[0]);
927       b = (int) tolower(bstr[0]);
928       while ((a == b) && a && b) {
929 	astr++;
930 	bstr++;
931         a = (int) tolower(astr[0]);
932         b = (int) tolower(bstr[0]);
933       }
934       if (a > b) {
935         if (!l)
936           gs->local = bs;
937         else
938           l->next = bs;
939         as->next = bs->next;
940         bs->next = as;
941         again = 1;
942         if (l == NULL)
943           gs->local = bs;
944         else
945           l = bs;
946       }
947       l = as;
948       as = bs;
949       bs = bs->next;
950     }
951     last = as;
952   }
953   Context;
954 }
955 
resetlocstats(locstats * ls)956 static void resetlocstats(locstats *ls)
957 {
958   int i;
959 
960   if (!ls) {
961     debug0("ERROR! resetlocstats called with NULL pointer!");
962     return;
963   }
964   for (i = 0; i < TOTAL_TYPES; i++) {
965     ls->values[S_TOTAL][i] = 0;
966     ls->values[S_TODAY][i] = 0;
967     ls->values[S_WEEKLY][i] = 0;
968     ls->values[S_MONTHLY][i] = 0;
969   }
970   return;
971 }
972 
calcwordstats(char * hand,globstats * gs,char * rest,locstats * stats)973 static void calcwordstats(char *hand, globstats *gs, char *rest, locstats *stats)
974 {
975   locstats *ls;
976   char *word;
977   int i;
978 
979   Context;
980   if (!log_wordstats)
981     return;
982   if (!gs) {
983     debug1("Can't calculate wordstats for %s, no globstats.", hand);
984     return;
985   }
986   if (stats)
987     ls = stats;
988   else {
989     for (ls = gs->local; ls; ls = ls->next)
990       if (!rfc_casecmp(hand, ls->user))
991         break;
992   }
993   if (!ls) {
994     debug2("Can't calculate wordstats for %s in %s, no locstats.", hand, gs->chan);
995     return;
996   }
997   for (i = 0; i < strlen(rest); i++)
998     if (strchr("!?.,\"<>&\\", rest[i]))
999       rest[i] = ' ';
1000   while (rest[0]) {
1001     word = newsplit(&rest);
1002     strlower(word);
1003     incrwordstats(ls, word, 1, 0);
1004   }
1005 }
1006 
1007 /* add another entry to the tree */
incrwordstats(locstats * ls,char * word,int value,int set)1008 static void incrwordstats(locstats *ls, char *word, int value, int set)
1009 {
1010   wordstats *ne, *te, *le;
1011   wordstats *ll;
1012   int cmp;
1013 
1014   Context;
1015   if ((word[0] == ' ') || !word[0])
1016     return;
1017   if (min_word_length && (strlen(word) < min_word_length))
1018     return;
1019   if (!ls) {
1020     return;
1021   }
1022   te = ls->tree;
1023   le = NULL;
1024   while (te) {
1025     if (!(cmp = strcasecmp(te->word, word)))
1026       break;
1027     le = te;
1028     if (cmp < 0)
1029       te = te->left;
1030     else
1031       te = te->right;
1032   }
1033   if (!te) {
1034     ne = nmalloc(sizeof(struct stats_words));
1035     ne->word = nmalloc(strlen(word) + 1);
1036     strcpy(ne->word, word);
1037     ne->nr = 0;
1038     ne->left = ne->right = ne->next = NULL;
1039     if (!le)
1040       ls->tree = ne;
1041     else {
1042       if (strcasecmp(le->word, word) < 0)
1043         le->left = ne;
1044       else
1045         le->right = ne;
1046     }
1047     ll = ls->words;
1048     while (ll && ll->next)
1049       ll = ll->next;
1050     if (ll)
1051       ll->next = ne;
1052     else
1053       ls->words = ne;
1054     te = ne;
1055   }
1056   if (set)
1057     te->nr = value;
1058   else
1059     te->nr += value;
1060 }
1061 
nincrwordstats(globstats * gs,char * word,int value)1062 static void nincrwordstats(globstats *gs, char *word, int value)
1063 {
1064   wordstats *l, *ll;
1065 
1066   for (l = gs->words; l; l = l->next)
1067     if (!strcmp(word, l->word))
1068       break;
1069   if (!l) {
1070     l = gs->words;
1071     while (l && l->next)
1072       l = l->next;
1073     ll = nmalloc(sizeof(wordstats));
1074     ll->word = nmalloc(strlen(word) + 1);
1075     strcpy(ll->word, word);
1076     ll->nr = 0;
1077     ll->next = NULL;
1078     if (l)
1079       l->next = ll;
1080     else
1081       gs->words = ll;
1082     l = ll;
1083   }
1084   l->nr += value;
1085 }
1086 
do_globwordstats(globstats * gs)1087 static void do_globwordstats(globstats *gs)
1088 {
1089   wordstats *l;
1090   locstats *ls;
1091 
1092   for (l = gs->words; l; l = l->next)
1093     l->nr = 0;
1094   for (ls = gs->local; ls; ls = ls->next)
1095     for (l = ls->words; l; l = l->next)
1096       nincrwordstats(gs, l->word, l->nr);
1097   sortwordstats(NULL, gs);
1098 }
1099 
addquote(char * user,globstats * gs,char * quote,locstats * stats)1100 static void addquote(char *user, globstats *gs, char *quote, locstats *stats)
1101 {
1102   quotestr *l, *nl;
1103   locstats *ls;
1104 
1105   if (!quote_freq)
1106     return;
1107   if (!gs) {
1108     debug1("Can't add quote to %s, no globstats.", user);
1109     return;
1110   }
1111   if (stats)
1112     ls = stats;
1113   else {
1114     for (ls = gs->local; ls; ls = ls->next)
1115       if (!rfc_casecmp(user, ls->user))
1116         break;
1117   }
1118   if (!ls) {
1119     debug2("Can't add quote to %s in %s, no locstats.", user, gs->chan);
1120     return;
1121   }
1122   ls->quotefr--;
1123   if (ls->quotefr > 0)
1124     return;
1125   ls->quotefr = quote_freq;
1126   l = ls->quotes;
1127   while (l && l->next)
1128     l = l->next;
1129   nl = nmalloc(sizeof(quotestr));
1130   nl->next = NULL;
1131   nl->quote = nmalloc(strlen(quote) + 1);
1132   strcpy(nl->quote, quote);
1133   if (l)
1134     l->next = nl;
1135   else
1136     ls->quotes = nl;
1137 }
1138 
addtopic(char * channel,char * topic,char * by)1139 static void addtopic(char *channel, char *topic, char *by)
1140 {
1141   topicstr *e, *ne;
1142   globstats *gs;
1143 
1144   Context;
1145   gs = findglobstats(channel);
1146   if (!gs)
1147     return;
1148   for (e = gs->topics; e; e = e->next)
1149     if (!strcasecmp(topic, e->topic))
1150       return;
1151   e = gs->topics;
1152   while (e && e->next)
1153     e = e->next;
1154   ne = nmalloc(sizeof(topicstr));
1155   ne->topic = nmalloc(strlen(topic) + 1);
1156   strcpy(ne->topic, topic);
1157   ne->by = nmalloc(strlen(by) + 1);
1158   strcpy(ne->by, by);
1159   ne->when = now;
1160   ne->next = NULL;
1161   if (e)
1162     e->next = ne;
1163   else
1164     gs->topics = ne;
1165 }
1166 
addhost(char * host,globstats * gs)1167 static void addhost(char *host, globstats *gs)
1168 {
1169   hoststr *e, *ne;
1170   char *s;
1171 
1172   if (!gs || !host)
1173     return;
1174   s = strchr(host, '@');
1175   if (s)
1176     host = s + 1;
1177   if (strcmp(host, "[IP]"))
1178     strlower(host);
1179   for (e = gs->hosts; e; e = e->next) {
1180     if (!strcmp(host, e->host)) {
1181       e->nr++;
1182       return;
1183     }
1184   }
1185   e = gs->hosts;
1186   while (e && e->next)
1187     e = e->next;
1188   ne = nmalloc(sizeof(hoststr));
1189   ne->host = nmalloc(strlen(host) + 1);
1190   strcpy(ne->host, host);
1191   ne->nr = 1;
1192   ne->next = NULL;
1193   if (e)
1194     e->next = ne;
1195   else
1196     gs->hosts = ne;
1197   return;
1198 }
1199 
setword(globstats * gs,char * word)1200 static void setword(globstats *gs, char *word)
1201 {
1202   locstats *l;
1203   wordstats *w;
1204 
1205   for (l = gs->local; l; l = l->next) {
1206     l->word = NULL;
1207     for (w = l->words; w; w = w->next) {
1208       if (!strcmp(w->word, word)) {
1209         l->word = w;
1210         break;
1211       }
1212     }
1213   }
1214 }
1215 
track_stat_user(char * oldnick,char * newnick)1216 static int track_stat_user(char *oldnick, char *newnick)
1217 {
1218   globstats *gs;
1219   locstats *ls;
1220   struct stats_userlist *u;
1221   int found = 0;
1222 
1223   Context;
1224   for (gs = sdata; gs; gs = gs->next) {
1225     for (ls = gs->local; ls; ls = ls->next) {
1226       if (!rfc_casecmp(oldnick, ls->user) && strcmp(newnick, ls->user)) {
1227         nfree(ls->user);
1228         ls->user = nmalloc(strlen(newnick) + 1);
1229         strcpy(ls->user, newnick);
1230         found = 1;
1231         debug3("Transferred stats from %s to %s in %s", oldnick, newnick, gs->chan);
1232       }
1233     }
1234   }
1235   for (u = suserlist; u; u = u->next) {
1236     if (!rfc_casecmp(oldnick, u->user) && strcmp(newnick, u->user)) {
1237       nfree(u->user);
1238       u->user = nmalloc(strlen(newnick) + 1);
1239       strcpy(u->user, newnick);
1240       found = 1;
1241       debug2("Changed user name from %s to %s in my local database.", oldnick, newnick);
1242     }
1243   }
1244   if (found)
1245     return 1;
1246   return 0;
1247 }
1248 
check_for_url(char * user,char * chan,char * text)1249 static void check_for_url(char *user, char *chan, char *text)
1250 {
1251   char *p, *url;
1252   char *tmp, *tmp2, *t;
1253   struct stats_url *e, *ne;
1254   globstats *gs;
1255   int weiter;
1256 
1257   if (log_urls < 1)
1258     return;
1259   gs = findglobstats(chan);
1260   if (!gs)
1261     return;
1262   url = p = tmp = tmp2 = t = NULL;
1263   if ((p = strstr(text, "http://")))
1264     url = newsplit(&p);
1265   else if ((p = strstr(text, "ftp://")))
1266     url = newsplit(&p);
1267   else if (strstr(text, "www.") || strstr(text, ".com") || strstr(text, "ftp.")) {
1268     tmp = nmalloc(strlen(text) + 1);
1269     strcpy(tmp, text);
1270     t = tmp;
1271     while (t[0]) {
1272       p = newsplit(&t);
1273       if (strstr(p, "www.") || strstr(p, ".com") || strstr(text, "ftp.")) {
1274         url = p;
1275         break;
1276       }
1277     }
1278   }
1279   if (!url)
1280     return;
1281   if (strchr(url, '@')) {
1282     if (tmp)
1283       nfree(tmp);
1284     return;
1285   }
1286   if (strncasecmp(url, "http://", 7) && strncasecmp(url, "ftp://", 6)) {
1287     if (!strncasecmp(url, "ftp.", 4)) {
1288       tmp2 = nmalloc(strlen(url) + 6 + 1);
1289       strcpy(tmp2, "ftp://");
1290       strcpy(tmp2 + 6, url);
1291     } else {
1292       tmp2 = nmalloc(strlen(url) + 7 + 1);
1293       strcpy(tmp2, "http://");
1294       strcpy(tmp2 + 7, url);
1295     }
1296     url = tmp2;
1297   }
1298   for (e = gs->urls; e; e = e->next) {
1299     if (!strcmp(e->url, url)) {
1300       nfree(e->by);
1301       e->by = nmalloc(strlen(user) + 1);
1302       strcpy(e->by, user);
1303       e->when = now;
1304       if (tmp)
1305         nfree(tmp);
1306       if (tmp2)
1307         nfree(tmp2);
1308       return;
1309     }
1310   }
1311   weiter = 1;
1312   for (p = url; (p != url) && weiter; p--) {
1313     if (strchr(".!?,#", p[0]))
1314       p[0] = 0;
1315     else
1316       weiter = 0;
1317   }
1318   for (e = gs->urls; e && e->next; e = e->next);
1319   ne = nmalloc(sizeof(struct stats_url));
1320   ne->url = nmalloc(strlen(url) + 1);
1321   strcpy(ne->url, url);
1322   ne->by = nmalloc(strlen(user) + 1);
1323   strcpy(ne->by, user);
1324   ne->when = now;
1325   ne->next = NULL;
1326   if (e)
1327     e->next = ne;
1328   else
1329     gs->urls = ne;
1330   if (tmp)
1331     nfree(tmp);
1332   if (tmp2)
1333     nfree(tmp2);
1334   debug2("Logged URL: \"%s\" mentioned by %s.", ne->url, ne->by);
1335 }
1336 
add_chanlog(globstats * gs,char * nick,char * text,int type)1337 static void add_chanlog(globstats *gs, char *nick, char *text, int type)
1338 {
1339   char ts[20];
1340   time_t tt, ttbuf;
1341   quotestr *newlog, *l;
1342 
1343   if (!gs || (kick_context < 1))
1344     return;
1345   ttbuf = tt = now;
1346   strftime(ts, 19, "[%H:%M:%S]", localtime(&tt));
1347   newlog = nmalloc(sizeof(quotestr));
1348   newlog->next = NULL;
1349   if (type == SL_PRIVMSG) {
1350     newlog->quote = nmalloc(strlen(nick) + strlen(ts) + strlen(text) + 11);
1351     sprintf(newlog->quote, "%s &lt;%s&gt; %s", ts, nick, text);
1352   } else if (type == SL_KICK) {
1353     newlog->quote = nmalloc(strlen(text) + strlen(ts) + 2);
1354     sprintf(newlog->quote, "%s %s", ts, text);
1355   } else if (type == SL_MODE) {
1356     newlog->quote = nmalloc(strlen(ts) + strlen(text) + 2);
1357     sprintf(newlog->quote, "%s %s", ts, text);
1358   } else if (type == SL_NICK) {
1359     newlog->quote = nmalloc(strlen(ts) + strlen(nick) + strlen(text) + 19);
1360     sprintf(newlog->quote, "%s %s changed nick to %s", ts, nick, text);
1361   } else if (type == SL_PART) {
1362     newlog->quote = nmalloc(strlen(ts) + strlen(nick) + strlen(gs->chan) + 12);
1363     sprintf(newlog->quote, "%s %s has left %s", ts, nick, gs->chan);
1364   } else if (type == SL_JOIN) {
1365     newlog->quote = nmalloc(strlen(ts) + strlen(nick) + strlen(gs->chan) + 14);
1366     sprintf(newlog->quote, "%s %s has joined %s", ts, nick, gs->chan);
1367   } else if (type == SL_QUIT) {
1368     newlog->quote = nmalloc(strlen(ts) + strlen(nick) + strlen(text) + 18);
1369     sprintf(newlog->quote, "%s %s has quit IRC (%s)", ts, nick, text);
1370   } else {
1371     debug1("Unknown log-type: %d !!!", type);
1372     newlog->quote = NULL;
1373   }
1374   if (gs->lastlog)
1375     gs->lastlog->next = newlog;
1376   else
1377     gs->log = newlog;
1378   gs->lastlog = newlog;
1379   gs->log_length++;
1380   while ((gs->log_length > kick_context) && (gs->log_length > 0)) {
1381     l = gs->log->next;
1382     nfree(gs->log->quote);
1383     if (gs->lastlog == gs->log)
1384       gs->lastlog = NULL;
1385     nfree(gs->log);
1386     gs->log = l;
1387     gs->log_length--;
1388   }
1389   ctime(&ttbuf);
1390 }
1391 
save_kick(globstats * gs,char * kick)1392 static void save_kick(globstats *gs, char *kick)
1393 {
1394   struct stats_kick *k, *nk;
1395   quotestr *log, *l, *nl;
1396 
1397   Context;
1398   if (!gs)
1399     return;
1400   for (k = gs->kicks; k && k->next; k = k->next);
1401   nk = nmalloc(sizeof(struct stats_kick));
1402   nk->next = NULL;
1403   nk->log = NULL;
1404   if (!gs->log || (kick_context < 1)) {
1405     nl = nmalloc(sizeof(quotestr));
1406     nl->quote = nmalloc(strlen(kick) + 1);
1407     strcpy(nl->quote, kick);
1408     nl->next = NULL;
1409     nk->log = nl;
1410   } else {
1411     for (log = gs->log; log; log = log->next) {
1412       nl = nmalloc(sizeof(quotestr));
1413       nl->quote = nmalloc(strlen(log->quote) + 1);
1414       strcpy(nl->quote, log->quote);
1415       nl->next = NULL;
1416       for (l = nk->log; l && l->next; l = l->next);
1417       if (l)
1418         l->next = nl;
1419       else
1420         nk->log = nl;
1421     }
1422   }
1423   if (k)
1424     k->next = nk;
1425   else
1426     gs->kicks = nk;
1427   debug1("Logged kick in %s.", gs->chan);
1428 }
1429