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 <%s> %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