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