1 /*
2 * Copyright (C) 2000,2001 Florian Sander
3 *
4 * $Id: userrec.c (1.3.2) for AversE-XP v1.0+ 2003/12/06 [Xp-AvR] Exp $
5 */
6
7
8 /* searches the channel list for a nick and returns a pointer
9 * to his/her user-struct, if found. */
nick2suser(char * nick,char * channel)10 static struct stats_memberlist *nick2suser(char *nick, char *channel)
11 {
12 struct stats_chanset *chan;
13 struct stats_memberlist *m, *lm;
14
15 Context;
16 chan = findschan(channel);
17 if (!chan)
18 chan = initchan(channel);
19 if (chan) {
20 lm = NULL;
21 m = chan->members;
22 while (m) {
23 if (!rfc_casecmp(m->nick, nick)) {
24 if (lm) {
25 lm->next = m->next;
26 m->next = chan->members;
27 chan->members = m;
28 }
29 if (!m->user)
30 return NULL;
31 else
32 return m;
33 }
34 lm = m;
35 m = m->next;
36 }
37
38
39 }
40 return NULL;
41 }
42
findschan(char * channel)43 static struct stats_chanset *findschan(char *channel)
44 {
45 struct stats_chanset *chan;
46
47 for (chan = schans; chan; chan = chan->next)
48 if (!strcasecmp(chan->chan, channel))
49 return chan;
50 return NULL;
51 }
52
initchan(char * channel)53 static struct stats_chanset *initchan(char *channel)
54 {
55 struct chanset_t *ch;
56 memberlist *m;
57 struct stats_chanset *chan, *nchan;
58 char *host;
59
60 Context;
61 debug1("Stats.mod: Initing chanset for %s", channel);
62 ch = findchan_by_dname(channel);
63 if (!ch) {
64 debug1("initchan: no such chan %s", channel);
65 return NULL;
66 }
67 if (ch->channel.members < 1) {
68 debug2("initchan: %s members == %d", channel, ch->channel.members);
69 return NULL;
70 }
71 chan = schans;
72 while (chan && chan->next)
73 chan = chan->next;
74 nchan = nmalloc(sizeof(struct stats_chanset));
75 nchan->chan = nmalloc(strlen(channel) + 1);
76 strcpy(nchan->chan, channel);
77 nchan->next = NULL;
78 nchan->members = NULL;
79 if (chan)
80 chan->next = nchan;
81 else
82 schans = nchan;
83 for (m = ch->channel.member; m; m = m->next) {
84 if (m->user == NULL) {
85 host = nmalloc(strlen(m->nick) + 1 + strlen(m->userhost) + 1);
86 sprintf(host, "%s!%s", m->nick, m->userhost);
87 m->user = get_user_by_host(host);
88 nfree(host);
89 }
90 saddmember(m->nick, m->userhost, m->user ? m->user->handle : "*", channel);
91 }
92 return nchan;
93 }
94
saddmember(char * nick,char * uhost,char * hand,char * channel)95 static void saddmember(char *nick, char *uhost, char *hand, char *channel)
96 {
97 struct stats_chanset *chan;
98 struct stats_memberlist *m, *nm;
99 char *host;
100
101 Context;
102 if (!nick) {
103 debug0("kein nick");
104 return;
105 }
106 Context;
107 if (!nick[0]) {
108 debug0("kein nick0");
109 return;
110 }
111 debug3("saddmember(%s, %s, %s)", channel, nick, uhost);
112 chan = findschan(channel);
113 if (!chan)
114 return;
115 m = chan->members;
116 while (m && m->next)
117 m = m->next;
118 nm = nmalloc(sizeof(struct stats_memberlist));
119 nm->nick = nmalloc(strlen(nick) + 1);
120 strcpy(nm->nick, nick);
121 nm->uhost = nmalloc(strlen(uhost) + 1);
122 strcpy(nm->uhost, uhost);
123 if (hand[0] != '*') {
124 nm->user = findsuser_by_name(hand);
125 if (!nm->user) {
126 nm->user = addsuser(hand, 1, 1);
127 debug1("Stats.Mod: Created suserrec for %s.", hand);
128 }
129 } else {
130 host = nmalloc(strlen(nick) + 1 + strlen(uhost) + 1);
131 sprintf(host, "%s!%s", nick, uhost);
132 nm->user = findsuser(host);
133 nfree(host);
134 }
135 if (nm->user)
136 nm->stats = findlocstats(channel, nm->user->user);
137 else
138 nm->stats = NULL;
139 nm->next = NULL;
140 nm->joined = now;
141 if (m)
142 m->next = nm;
143 else
144 chan->members = nm;
145 }
146
strackmember(char * channel,char * oldnick,char * newnick)147 static void strackmember(char *channel, char *oldnick, char *newnick)
148 {
149 struct stats_chanset *chan;
150 struct stats_memberlist *m;
151
152 Context;
153 chan = findschan(channel);
154 if (!chan)
155 return;
156 for (m = chan->members; m; m = m->next) {
157 if (!rfc_casecmp(m->nick, oldnick)) {
158 nfree(m->nick);
159 m->nick = nmalloc(strlen(newnick) + 1);
160 strcpy(m->nick, newnick);
161 return;
162 }
163 }
164 }
165
skillmember(char * channel,char * nick)166 static void skillmember(char *channel, char *nick)
167 {
168 struct stats_chanset *chan;
169 struct stats_memberlist *m, *mm;
170
171 Context;
172 chan = findschan(channel);
173 if (!chan)
174 return;
175 m = chan->members;
176 mm = NULL;
177 while (m) {
178 if (!rfc_casecmp(m->nick, nick)) {
179 nfree(m->nick);
180 nfree(m->uhost);
181 if (mm)
182 mm->next = m->next;
183 else
184 chan->members = m->next;
185 nfree(m);
186 return;
187 }
188 mm = m;
189 m = m->next;
190 }
191 putlog(LOG_MISC, "*", "Stats.mod: skillmember(%s, %s) failed!!!", channel, nick);
192 }
193
194
195 /* Find the stats-user that belongs to a hostmask */
findsuser(char * host)196 static struct stats_userlist *findsuser(char *host)
197 {
198 struct stats_userlist *user, *u;
199 struct stats_hostlist *h, *h2;
200 int len = 0;
201
202 Context;
203 u = NULL;
204 h2 = NULL;
205 for (user = suserlist; user; user = user->next) {
206 for (h = user->hosts; h; h = h->next) {
207 /* the longest hostmask gives the best match */
208 if (!len || (strlen(h->mask) > len)) {
209 if (wild_match(h->mask, host)) {
210 u = user;
211 h2 = h;
212 len = strlen(h->mask);
213 }
214 }
215 }
216 }
217 if (u) {
218 h2->lastused = now;
219 return u;
220 }
221 return NULL;
222 }
223
findsuser_by_name(char * user)224 static struct stats_userlist *findsuser_by_name(char *user)
225 {
226 struct stats_userlist *u;
227
228 Context;
229 for (u = suserlist; u; u = u->next)
230 if (!rfc_casecmp(u->user, user))
231 return u;
232 return NULL;
233 }
234
addsuser(char * user,int list,int addhosts)235 static struct stats_userlist *addsuser(char *user, int list, int addhosts)
236 {
237 struct stats_userlist *u, *nu;
238
239 Context;
240 for (u = suserlist; u; u = u->next)
241 if (!rfc_casecmp(u->user, user))
242 return u;
243 u = suserlist;
244 while (u && u->next)
245 u = u->next;
246 nu = nmalloc(sizeof(struct stats_userlist));
247 nu->user = nmalloc(strlen(user) + 1);
248 strcpy(nu->user, user);
249 nu->list = list;
250 nu->addhosts = addhosts;
251 nu->next = NULL;
252 nu->hosts = NULL;
253 nu->email = NULL;
254 nu->homepage = NULL;
255 if (u)
256 u->next = nu;
257 else
258 suserlist = nu;
259 return nu;
260 }
261
delsuser(char * user)262 static void delsuser(char *user)
263 {
264 struct stats_userlist *u, *lu;
265
266 Context;
267 debug1("Deleting %s...", user);
268 u = suserlist;
269 lu = NULL;
270 while (u) {
271 if (!rfc_casecmp(u->user, user)) {
272 if (lu)
273 lu->next = u->next;
274 else
275 suserlist = u->next;
276 free_hostlist(u->hosts);
277 if (u->email)
278 nfree(u->email);
279 if (u->homepage)
280 nfree(u->homepage);
281 nfree(u->user);
282 weed_userlink_from_chanset(u);
283 weed_userlink_from_locstats(u);
284 nfree(u);
285 if (lu)
286 u = lu->next;
287 else
288 u = suserlist;
289 } else {
290 lu = u;
291 u = u->next;
292 }
293 }
294 }
295
saddhost(struct stats_userlist * u,char * host,time_t lastused)296 static void saddhost(struct stats_userlist *u, char *host, time_t lastused)
297 {
298 struct stats_hostlist *h, *nh;
299
300 Context;
301 for (h = u->hosts; h; h = h->next)
302 if (!rfc_casecmp(h->mask, host))
303 return;
304 h = u->hosts;
305 while (h && h->next)
306 h = h->next;
307 nh = nmalloc(sizeof(struct stats_hostlist));
308 nh->mask = nmalloc(strlen(host) + 1);
309 strcpy(nh->mask, host);
310 nh->lastused = lastused;
311 nh->next = NULL;
312 if (h)
313 h->next = nh;
314 else
315 u->hosts = nh;
316 }
317
sdelhost(struct stats_userlist * u,char * host)318 static int sdelhost(struct stats_userlist *u, char *host)
319 {
320 struct stats_hostlist *h, *lh;
321
322 Context;
323 h = u->hosts;
324 lh = NULL;
325 while (h) {
326 if (!rfc_casecmp(h->mask, host)) {
327 nfree(h->mask);
328 if (lh)
329 lh->next = h->next;
330 else
331 u->hosts = h->next;
332 nfree(h);
333 return 1;
334 }
335 lh = h;
336 h = h->next;
337 }
338 return 0;
339 }
340
stats_autosadd(struct stats_memberlist * m,struct stats_chanset * chan)341 static void stats_autosadd(struct stats_memberlist *m, struct stats_chanset *chan)
342 {
343 struct stats_userlist *u;
344 struct userrec *uu;
345 char *mhost, *host;
346
347 Context;
348 if (autoadd < 0)
349 return;
350 if ((now - m->joined) < (autoadd * 60))
351 return;
352 if (m->user) {
353 debug3("Stats.Mod: stats_autosadd called for %s in %s, but m->user already belongs to %s",
354 m->nick, chan->chan, m->user->user);
355 return;
356 }
357 u = findsuser_by_name(m->nick);
358 host = nmalloc(strlen(m->uhost) + strlen(m->nick) + 2);
359 sprintf(host, "%s!%s", m->nick, m->uhost);
360 mhost = nmalloc(strlen(host) + 10);
361 maskstricthost(host, mhost);
362 if (u) {
363 if (u->addhosts) {
364 saddhost(u, mhost, now);
365 m->user = u;
366 putlog(LOG_MISC, "*", "Stats.Mod: Added stats-hostmask %s to %s.", mhost, u->user);
367 }
368 } else {
369 uu = get_user_by_host(host);
370 if (!uu && (autoadd == 0)) {
371 nfree(mhost);
372 nfree(host);
373 return;
374 }
375 if (uu)
376 u = addsuser(uu->handle, 1, 1);
377 else
378 u = addsuser(m->nick, 1, 1);
379 saddhost(u, mhost, now);
380 if (uu)
381 putlog(LOG_MISC, "*", "Stats.Mod: %s matched %s(in the \"common\" userfile), added %s to userbase.", host, uu->handle, u->user);
382 else
383 putlog(LOG_MISC, "*", "Stats.Mod: Added %s(%s) to userbase.", u->user, mhost);
384 m->user = u;
385 }
386 if (m->user)
387 m->stats = findlocstats(chan->chan, m->user->user);
388 else
389 m->stats = NULL;
390 nfree(mhost);
391 nfree(host);
392 }
393
listsuser(locstats * ls,char * chan)394 static int listsuser(locstats *ls, char *chan)
395 {
396 struct userrec *ou;
397
398 if (!use_userfile) {
399 if (!ls->u)
400 ls->u = findsuser_by_name(ls->user);
401 if (ls->u && !ls->u->list)
402 return 0;
403 } else {
404 ou = get_user_by_handle(userlist, ls->user);
405 if (matchattr(ou, nostatsflags, chan))
406 return 0;
407 }
408 return 1;
409 }
410
countsusers()411 static int countsusers()
412 {
413 static struct stats_userlist *u;
414 int users = 0;
415
416 Context;
417 for (u = suserlist; u; u = u->next)
418 users++;
419 return users;
420 }
421
counthosts()422 static int counthosts()
423 {
424 static struct stats_userlist *u;
425 static struct stats_hostlist *h;
426 int hosts = 0;
427
428 Context;
429 for (u = suserlist; u; u = u->next)
430 for (h = u->hosts; h; h = h->next)
431 hosts++;
432 return hosts;
433 }
434
weed_userlink_from_chanset(struct stats_userlist * u)435 static void weed_userlink_from_chanset(struct stats_userlist *u)
436 {
437 struct stats_chanset *chan;
438 struct stats_memberlist *m;
439
440 Context;
441 for (chan = schans; chan; chan = chan->next) {
442 for (m = chan->members; m; m = m->next) {
443 if (m->user == u) {
444 m->user = NULL;
445 m->stats = NULL;
446 }
447 }
448 }
449 }
450
weed_statlink_from_chanset(locstats * ls)451 static void weed_statlink_from_chanset(locstats *ls)
452 {
453 struct stats_chanset *chan;
454 struct stats_memberlist *m;
455
456 Context;
457 for (chan = schans; chan; chan = chan->next) {
458 for (m = chan->members; m; m = m->next) {
459 if (m->stats == ls) {
460 m->stats = NULL;
461 }
462 }
463 }
464 }
465
466 /* removes all references to a userstruct from the stat-structs
467 * (mostly used if the user got deleted) */
weed_userlink_from_locstats(struct stats_userlist * u)468 static void weed_userlink_from_locstats(struct stats_userlist *u)
469 {
470 globstats *gs;
471 locstats *ls;
472
473 Context;
474 for (gs = sdata; gs; gs = gs->next)
475 for (ls = gs->local; ls; ls = ls->next)
476 if (ls->u == u)
477 ls->u = NULL;
478 Context;
479 }
480
countmembers(struct stats_memberlist * m)481 static int countmembers(struct stats_memberlist *m)
482 {
483 int nr = 0;
484
485 Context;
486 while (m) {
487 nr++;
488 m = m->next;
489 }
490 return nr;
491 }
492
check_desynch()493 static void check_desynch()
494 {
495 struct stats_chanset *chan;
496 struct chanset_t *ch;
497
498 Context;
499 for (ch = chanset; ch; ch = ch->next) {
500 if (ch->status & CHAN_INACTIVE)
501 continue;
502 chan = findschan(ch->dname);
503 if (chan)
504 if (ch->channel.members == countmembers(chan->members))
505 continue;
506 putlog(LOG_DEBUG, "*", "Stats.Mod: Channel list for %s desynched!!! Resetting...", ch->dname);
507 if (chan)
508 free_one_chan(chan->chan);
509 initchan(ch->dname);
510 }
511 }
512
513 /* used when shosts/susers changed */
update_schannel_members()514 static void update_schannel_members()
515 {
516 struct stats_chanset *chan;
517 struct stats_memberlist *m;
518 struct userrec *u;
519 char *host;
520
521 Context;
522 for (chan = schans; chan; chan = chan->next) {
523 for (m = chan->members; m; m = m->next) {
524 m->user = NULL;
525 host = nmalloc(strlen(m->nick) + 1 + strlen(m->uhost) + 1);
526 sprintf(host, "%s!%s", m->nick, m->uhost);
527 u = get_user_by_host(host);
528 if (u) {
529 m->user = findsuser_by_name(u->handle);
530 if (!m->user) {
531 m->user = addsuser(u->handle, 1, 0);
532 debug1("Stats.Mod: Created suserrec for %s.", u->handle);
533 }
534 } else
535 m->user = findsuser(host);
536 nfree(host);
537 m->stats = NULL;
538 }
539 }
540 debug0("update_schannel_members()");
541 }
542
setemail(struct stats_userlist * u,char * email)543 static void setemail(struct stats_userlist *u, char *email)
544 {
545 if (!u) {
546 putlog(LOG_MISC, "*", "ERROR! Tried to set email for NULL!");
547 return;
548 }
549 if (u->email)
550 nfree(u->email);
551 u->email = nmalloc(strlen(email) + 1);
552 strcpy(u->email, email);
553 }
554
sethomepage(struct stats_userlist * u,char * homepage)555 static void sethomepage(struct stats_userlist *u, char *homepage)
556 {
557 if (!u) {
558 putlog(LOG_MISC, "*", "ERROR! Tried to set homepage for NULL!");
559 return;
560 }
561 if (u->homepage)
562 nfree(u->homepage);
563 u->homepage = nmalloc(strlen(homepage) + 1);
564 strcpy(u->homepage, homepage);
565 }
566