| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627 |
- /*
- * Copyright (C) 2000,2001 Florian Sander
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- /* nick2suser():
- * searches the channel list for a nick and returns a pointer
- * to his/her user-struct, if found.
- */
- static struct stats_memberlist *nick2suser(char *nick, char *channel)
- {
- struct stats_chanset *chan;
- struct stats_memberlist *m, *lm;
- Context;
- chan = findschan(channel);
- if (!chan)
- chan = initchan(channel);
- if (chan) {
- lm = NULL;
- m = chan->members;
- while (m) {
- if (!rfc_casecmp(m->nick, nick)) {
- if (lm) {
- // move this entry to the top of the list
- // since chatting means writing several sentences,
- // we'll probably need this item again pretty soon.
- // => should be faster
- lm->next = m->next;
- m->next = chan->members;
- chan->members = m;
- }
- if (!m->user)
- return NULL;
- else
- return m;
- }
- lm = m;
- m = m->next;
- }
- }
- return NULL;
- }
- static struct stats_chanset *findschan(char *channel)
- {
- struct stats_chanset *chan;
- for (chan = schans; chan; chan = chan->next)
- if (!strcasecmp(chan->chan, channel))
- return chan;
- return NULL;
- }
- static struct stats_chanset *initchan(char *channel)
- {
- struct chanset_t *ch;
- memberlist *m;
- struct stats_chanset *chan, *nchan;
- char *host;
- Context;
- debug1("Stats.mod: Initing chanset for %s", channel);
- ch = findchan_by_dname(channel);
- if (!ch) {
- debug1("initchan: no such chan %s", channel);
- return NULL;
- }
- if (ch->channel.members < 1) {
- debug2("initchan: %s members == %d", channel, ch->channel.members);
- return NULL;
- }
- chan = schans;
- while (chan && chan->next)
- chan = chan->next;
- nchan = nmalloc(sizeof(struct stats_chanset));
- nchan->chan = nmalloc(strlen(channel) + 1);
- strcpy(nchan->chan, channel);
- nchan->next = NULL;
- nchan->members = NULL;
- if (chan)
- chan->next = nchan;
- else
- schans = nchan;
- for (m = ch->channel.member; m; m = m->next) {
- if (!m->userhost) {
- debug2("Stats.Mod: No host for %s in %s available, yet.",
- m->nick, channel);
- continue;
- }
- if (m->user == NULL) {
- host = nmalloc(strlen(m->nick) + 1 + strlen(m->userhost) + 1);
- sprintf(host, "%s!%s", m->nick, m->userhost);
- m->user = get_user_by_host(host);
- nfree(host);
- }
- saddmember(m->nick, m->userhost, m->user ? m->user->handle : "*", channel);
- }
- return nchan;
- }
- static void saddmember(char *nick, char *uhost, char *hand, char *channel)
- {
- struct stats_chanset *chan;
- struct stats_memberlist *m, *nm;
- char *host;
- Context;
- if (!nick) {
- debug0("kein nick");
- return;
- }
- Context;
- if (!nick[0]) {
- debug0("kein nick0");
- return;
- }
- debug3("saddmember(%s, %s, %s)", channel, nick, uhost);
- chan = findschan(channel);
- if (!chan)
- return;
- m = chan->members;
- while (m && m->next)
- m = m->next;
- nm = nmalloc(sizeof(struct stats_memberlist));
- nm->nick = nmalloc(strlen(nick) + 1);
- strcpy(nm->nick, nick);
- nm->uhost = nmalloc(strlen(uhost) + 1);
- strcpy(nm->uhost, uhost);
- if (hand[0] != '*') {
- nm->user = findsuser_by_name(hand);
- if (!nm->user) {
- nm->user = addsuser(hand, 1, 1);
- debug1("Stats.Mod: Created suserrec for %s.", hand);
- }
- } else {
- host = nmalloc(strlen(nick) + 1 + strlen(uhost) + 1);
- sprintf(host, "%s!%s", nick, uhost);
- nm->user = findsuser(host);
- nfree(host);
- }
- if (nm->user)
- nm->stats = findlocstats(channel, nm->user->user);
- else
- nm->stats = NULL;
- nm->next = NULL;
- nm->joined = now;
- if (m)
- m->next = nm;
- else
- chan->members = nm;
- }
- static void strackmember(char *channel, char *oldnick, char *newnick)
- {
- struct stats_chanset *chan;
- struct stats_memberlist *m;
- Context;
- chan = findschan(channel);
- if (!chan)
- return;
- for (m = chan->members; m; m = m->next) {
- if (!rfc_casecmp(m->nick, oldnick)) {
- nfree(m->nick);
- m->nick = nmalloc(strlen(newnick) + 1);
- strcpy(m->nick, newnick);
- return;
- }
- }
- }
- static void skillmember(char *channel, char *nick)
- {
- struct stats_chanset *chan;
- struct stats_memberlist *m, *mm;
- Context;
- chan = findschan(channel);
- if (!chan)
- return;
- m = chan->members;
- mm = NULL;
- while (m) {
- if (!rfc_casecmp(m->nick, nick)) {
- nfree(m->nick);
- nfree(m->uhost);
- if (mm)
- mm->next = m->next;
- else
- chan->members = m->next;
- nfree(m);
- return;
- }
- mm = m;
- m = m->next;
- }
- putlog(LOG_MISC, "*", "Stats.mod: skillmember(%s, %s) failed!!!", channel, nick);
- }
- /* Find the stats-user that belongs to a hostmask
- */
- static struct stats_userlist *findsuser(char *host)
- {
- struct stats_userlist *user, *u;
- struct stats_hostlist *h, *h2;
- int len = 0;
- Context;
- u = NULL;
- h2 = NULL;
- for (user = suserlist; user; user = user->next) {
- for (h = user->hosts; h; h = h->next) {
- /* the longest hostmask gives the best match */
- if (!len || (strlen(h->mask) > len)) {
- if (wild_match(h->mask, host)) {
- u = user;
- h2 = h;
- len = strlen(h->mask);
- }
- }
- }
- }
- if (u) {
- h2->lastused = now;
- return u;
- }
- return NULL;
- }
- static struct stats_userlist *findsuser_by_name(char *user)
- {
- struct stats_userlist *u;
- Context;
- for (u = suserlist; u; u = u->next)
- if (!rfc_casecmp(u->user, user))
- return u;
- return NULL;
- }
- static struct stats_userlist *addsuser(char *user, int list, int addhosts)
- {
- struct stats_userlist *u, *nu;
- Context;
- for (u = suserlist; u; u = u->next)
- if (!rfc_casecmp(u->user, user))
- return u;
- u = suserlist;
- while (u && u->next)
- u = u->next;
- nu = nmalloc(sizeof(struct stats_userlist));
- nu->user = nmalloc(strlen(user) + 1);
- strcpy(nu->user, user);
- nu->list = list;
- nu->addhosts = addhosts;
- nu->next = NULL;
- nu->hosts = NULL;
- nu->email = NULL;
- nu->homepage = NULL;
- if (u)
- u->next = nu;
- else
- suserlist = nu;
- return nu;
- }
- static void delsuser(char *user)
- {
- struct stats_userlist *u, *lu;
- Context;
- debug1("Deleting %s...", user);
- u = suserlist;
- lu = NULL;
- while (u) {
- if (!rfc_casecmp(u->user, user)) {
- if (lu)
- lu->next = u->next;
- else
- suserlist = u->next;
- free_hostlist(u->hosts);
- if (u->email)
- nfree(u->email);
- if (u->homepage)
- nfree(u->homepage);
- nfree(u->user);
- weed_userlink_from_chanset(u);
- weed_userlink_from_locstats(u);
- nfree(u);
- if (lu)
- u = lu->next;
- else
- u = suserlist;
- } else {
- lu = u;
- u = u->next;
- }
- }
- }
- static void saddhost(struct stats_userlist *u, char *host, time_t lastused)
- {
- struct stats_hostlist *h, *nh;
- Context;
- for (h = u->hosts; h; h = h->next)
- if (!rfc_casecmp(h->mask, host))
- return;
- h = u->hosts;
- while (h && h->next)
- h = h->next;
- nh = nmalloc(sizeof(struct stats_hostlist));
- nh->mask = nmalloc(strlen(host) + 1);
- strcpy(nh->mask, host);
- nh->lastused = lastused;
- nh->next = NULL;
- if (h)
- h->next = nh;
- else
- u->hosts = nh;
- }
- static int sdelhost(struct stats_userlist *u, char *host)
- {
- struct stats_hostlist *h, *lh;
- Context;
- h = u->hosts;
- lh = NULL;
- while (h) {
- if (!rfc_casecmp(h->mask, host)) {
- nfree(h->mask);
- if (lh)
- lh->next = h->next;
- else
- u->hosts = h->next;
- nfree(h);
- return 1;
- }
- lh = h;
- h = h->next;
- }
- return 0;
- }
- static void stats_autosadd(struct stats_memberlist *m, struct stats_chanset *chan)
- {
- struct stats_userlist *u;
- struct userrec *uu;
- char *mhost, *host, *egghost;
- struct chanset_t *eggchan;
- memberlist *eggmember;
- Context;
- if (autoadd < 0)
- return;
- if ((now - m->joined) < (autoadd * 60))
- return;
- if (m->user) {
- debug3("Stats.Mod: stats_autosadd called for %s in %s, but m->user already belongs to %s",
- m->nick, chan->chan, m->user->user);
- return;
- }
- #ifndef OLDBOT
- eggchan = findchan_by_dname(chan->chan);
- #else
- eggchan = findchan(chan->chan);
- #endif
- if (!eggchan) {
- putlog(LOG_MISC, "*", "Stats.Mod: Couldn't find eggdrop channel data while autoadding in %s.", chan->chan);
- return;
- }
- eggmember = ismember(eggchan, m->nick);
- if (!eggmember) {
- putlog(LOG_MISC, "*", "Stats.Mod: Couldn't find eggdrop member data while autoadding %s in %s.", m->nick, chan->chan);
- return;
- }
- egghost = eggmember->userhost;
- if (!egghost) {
- debug2("Stats.Mod: Couldn't autoadd %s in %s because there isn't an validated host, yet.", m->nick, chan->chan);
- return;
- }
- u = findsuser_by_name(m->nick);
- host = nmalloc(strlen(egghost) + strlen(m->nick) + 2);
- sprintf(host, "%s!%s", m->nick, egghost);
- mhost = nmalloc(strlen(host) + 10); /* better a few bytes too much than too little */
- // I use maskstricthost() here, because stats.mod shouldn't strip
- // a host anywhere at all. (strict-hosts 0 sucks...)
- maskstricthost(host, mhost);
- // mhost = nrealloc(mhost, strlen(mhost) + strlen(nick) + 1);sprintf(mhost, "%s%s", m->nick, mhost + 1);
- if (u) {
- if (u->addhosts) {
- saddhost(u, mhost, now);
- m->user = u;
- putlog(LOG_MISC, "*", "Stats.Mod: Added stats-hostmask %s to %s.", mhost, u->user);
- }
- } else {
- uu = get_user_by_host(host);
- if (!uu && (autoadd == 0)) {
- nfree(mhost);
- nfree(host);
- return;
- }
- if (uu)
- u = addsuser(uu->handle, 1, 1);
- else
- u = addsuser(m->nick, 1, 1);
- saddhost(u, mhost, now);
- if (uu)
- putlog(LOG_MISC, "*", "Stats.Mod: %s matched %s(in the \"common\" userfile), added %s to userbase.", host, uu->handle, u->user);
- else
- putlog(LOG_MISC, "*", "Stats.Mod: Added %s(%s) to userbase.", u->user, mhost);
- m->user = u;
- }
- if (m->user)
- m->stats = findlocstats(chan->chan, m->user->user);
- else
- m->stats = NULL;
- nfree(mhost);
- nfree(host);
- }
- static int listsuser(locstats *ls, char *chan)
- {
- struct userrec *ou;
- if (!use_userfile) {
- if (!ls->u)
- ls->u = findsuser_by_name(ls->user);
- if (ls->u && !ls->u->list)
- return 0;
- } else {
- ou = get_user_by_handle(userlist, ls->user);
- if (matchattr(ou, nostatsflags, chan))
- return 0;
- }
- return 1;
- }
- static int countsusers()
- {
- static struct stats_userlist *u;
- int users = 0;
- Context;
- for (u = suserlist; u; u = u->next)
- users++;
- return users;
- }
- static int counthosts()
- {
- static struct stats_userlist *u;
- static struct stats_hostlist *h;
- int hosts = 0;
- Context;
- for (u = suserlist; u; u = u->next)
- for (h = u->hosts; h; h = h->next)
- hosts++;
- return hosts;
- }
- static void weed_userlink_from_chanset(struct stats_userlist *u)
- {
- struct stats_chanset *chan;
- struct stats_memberlist *m;
- Context;
- for (chan = schans; chan; chan = chan->next) {
- for (m = chan->members; m; m = m->next) {
- if (m->user == u) {
- m->user = NULL;
- m->stats = NULL;
- }
- }
- }
- }
- static void weed_statlink_from_chanset(locstats *ls)
- {
- struct stats_chanset *chan;
- struct stats_memberlist *m;
- Context;
- for (chan = schans; chan; chan = chan->next) {
- for (m = chan->members; m; m = m->next) {
- if (m->stats == ls) {
- m->stats = NULL;
- }
- }
- }
- }
- /* weed_userlink_from_locstats():
- * removes all references to a userstruct from the stat-structs
- * (mostly used if the user got deleted)
- */
- static void weed_userlink_from_locstats(struct stats_userlist *u)
- {
- globstats *gs;
- locstats *ls;
- Context;
- for (gs = sdata; gs; gs = gs->next)
- for (ls = gs->local; ls; ls = ls->next)
- if (ls->u == u)
- ls->u = NULL;
- Context;
- }
- static int countmembers(struct stats_memberlist *m)
- {
- int nr = 0;
- Context;
- while (m) {
- nr++;
- m = m->next;
- }
- return nr;
- }
- static void check_desynch()
- {
- struct stats_chanset *chan;
- struct chanset_t *ch;
- Context;
- for (ch = chanset; ch; ch = ch->next) {
- if (ch->status & CHAN_INACTIVE)
- continue;
- #if EGG_IS_MIN_VER(10500)
- chan = findschan(ch->dname);
- #else
- chan = findschan(ch->name);
- #endif
- if (chan)
- if (ch->channel.members == countmembers(chan->members))
- continue;
- #if EGG_IS_MIN_VER(10500)
- putlog(LOG_DEBUG, "*", "Stats.Mod: Channel list for %s desynched!!! Resetting...", ch->dname);
- #else
- putlog(LOG_DEBUG, "*", "Stats.Mod: Channel list for %s desynched!!! Resetting...", ch->name);
- #endif
- if (chan)
- free_one_chan(chan->chan);
- #if EGG_IS_MIN_VER(10500)
- initchan(ch->dname);
- #else
- initchan(ch->name);
- #endif
- }
- }
- /* used when shosts/susers changed */
- static void update_schannel_members()
- {
- struct stats_chanset *chan;
- struct stats_memberlist *m;
- struct userrec *u;
- char *host;
- Context;
- for (chan = schans; chan; chan = chan->next) {
- for (m = chan->members; m; m = m->next) {
- m->user = NULL;
- host = nmalloc(strlen(m->nick) + 1 + strlen(m->uhost) + 1);
- sprintf(host, "%s!%s", m->nick, m->uhost);
- u = get_user_by_host(host);
- if (u) {
- m->user = findsuser_by_name(u->handle);
- if (!m->user) {
- m->user = addsuser(u->handle, 1, 0);
- debug1("Stats.Mod: Created suserrec for %s.", u->handle);
- }
- } else
- m->user = findsuser(host);
- nfree(host);
- m->stats = NULL;
- }
- }
- debug0("update_schannel_members()");
- }
- static void setemail(struct stats_userlist *u, char *email)
- {
- if (!u) {
- putlog(LOG_MISC, "*", "ERROR! Tried to set email for NULL!");
- return;
- }
- if (u->email)
- nfree(u->email);
- u->email = nmalloc(strlen(email) + 1);
- strcpy(u->email, email);
- }
- static void sethomepage(struct stats_userlist *u, char *homepage)
- {
- if (!u) {
- putlog(LOG_MISC, "*", "ERROR! Tried to set homepage for NULL!");
- return;
- }
- if (u->homepage)
- nfree(u->homepage);
- u->homepage = nmalloc(strlen(homepage) + 1);
- strcpy(u->homepage, homepage);
- }
|