userrec.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. /*
  2. * Copyright (C) 2000,2001 Florian Sander
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. /* nick2suser():
  19. * searches the channel list for a nick and returns a pointer
  20. * to his/her user-struct, if found.
  21. */
  22. static struct stats_memberlist *nick2suser(char *nick, char *channel)
  23. {
  24. struct stats_chanset *chan;
  25. struct stats_memberlist *m, *lm;
  26. Context;
  27. chan = findschan(channel);
  28. if (!chan)
  29. chan = initchan(channel);
  30. if (chan) {
  31. lm = NULL;
  32. m = chan->members;
  33. while (m) {
  34. if (!rfc_casecmp(m->nick, nick)) {
  35. if (lm) {
  36. // move this entry to the top of the list
  37. // since chatting means writing several sentences,
  38. // we'll probably need this item again pretty soon.
  39. // => should be faster
  40. lm->next = m->next;
  41. m->next = chan->members;
  42. chan->members = m;
  43. }
  44. if (!m->user)
  45. return NULL;
  46. else
  47. return m;
  48. }
  49. lm = m;
  50. m = m->next;
  51. }
  52. }
  53. return NULL;
  54. }
  55. static struct stats_chanset *findschan(char *channel)
  56. {
  57. struct stats_chanset *chan;
  58. for (chan = schans; chan; chan = chan->next)
  59. if (!strcasecmp(chan->chan, channel))
  60. return chan;
  61. return NULL;
  62. }
  63. static struct stats_chanset *initchan(char *channel)
  64. {
  65. struct chanset_t *ch;
  66. memberlist *m;
  67. struct stats_chanset *chan, *nchan;
  68. char *host;
  69. Context;
  70. debug1("Stats.mod: Initing chanset for %s", channel);
  71. ch = findchan_by_dname(channel);
  72. if (!ch) {
  73. debug1("initchan: no such chan %s", channel);
  74. return NULL;
  75. }
  76. if (ch->channel.members < 1) {
  77. debug2("initchan: %s members == %d", channel, ch->channel.members);
  78. return NULL;
  79. }
  80. chan = schans;
  81. while (chan && chan->next)
  82. chan = chan->next;
  83. nchan = nmalloc(sizeof(struct stats_chanset));
  84. nchan->chan = nmalloc(strlen(channel) + 1);
  85. strcpy(nchan->chan, channel);
  86. nchan->next = NULL;
  87. nchan->members = NULL;
  88. if (chan)
  89. chan->next = nchan;
  90. else
  91. schans = nchan;
  92. for (m = ch->channel.member; m; m = m->next) {
  93. if (!m->userhost) {
  94. debug2("Stats.Mod: No host for %s in %s available, yet.",
  95. m->nick, channel);
  96. continue;
  97. }
  98. if (m->user == NULL) {
  99. host = nmalloc(strlen(m->nick) + 1 + strlen(m->userhost) + 1);
  100. sprintf(host, "%s!%s", m->nick, m->userhost);
  101. m->user = get_user_by_host(host);
  102. nfree(host);
  103. }
  104. saddmember(m->nick, m->userhost, m->user ? m->user->handle : "*", channel);
  105. }
  106. return nchan;
  107. }
  108. static void saddmember(char *nick, char *uhost, char *hand, char *channel)
  109. {
  110. struct stats_chanset *chan;
  111. struct stats_memberlist *m, *nm;
  112. char *host;
  113. Context;
  114. if (!nick) {
  115. debug0("kein nick");
  116. return;
  117. }
  118. Context;
  119. if (!nick[0]) {
  120. debug0("kein nick0");
  121. return;
  122. }
  123. debug3("saddmember(%s, %s, %s)", channel, nick, uhost);
  124. chan = findschan(channel);
  125. if (!chan)
  126. return;
  127. m = chan->members;
  128. while (m && m->next)
  129. m = m->next;
  130. nm = nmalloc(sizeof(struct stats_memberlist));
  131. nm->nick = nmalloc(strlen(nick) + 1);
  132. strcpy(nm->nick, nick);
  133. nm->uhost = nmalloc(strlen(uhost) + 1);
  134. strcpy(nm->uhost, uhost);
  135. if (hand[0] != '*') {
  136. nm->user = findsuser_by_name(hand);
  137. if (!nm->user) {
  138. nm->user = addsuser(hand, 1, 1);
  139. debug1("Stats.Mod: Created suserrec for %s.", hand);
  140. }
  141. } else {
  142. host = nmalloc(strlen(nick) + 1 + strlen(uhost) + 1);
  143. sprintf(host, "%s!%s", nick, uhost);
  144. nm->user = findsuser(host);
  145. nfree(host);
  146. }
  147. if (nm->user)
  148. nm->stats = findlocstats(channel, nm->user->user);
  149. else
  150. nm->stats = NULL;
  151. nm->next = NULL;
  152. nm->joined = now;
  153. if (m)
  154. m->next = nm;
  155. else
  156. chan->members = nm;
  157. }
  158. static void strackmember(char *channel, char *oldnick, char *newnick)
  159. {
  160. struct stats_chanset *chan;
  161. struct stats_memberlist *m;
  162. Context;
  163. chan = findschan(channel);
  164. if (!chan)
  165. return;
  166. for (m = chan->members; m; m = m->next) {
  167. if (!rfc_casecmp(m->nick, oldnick)) {
  168. nfree(m->nick);
  169. m->nick = nmalloc(strlen(newnick) + 1);
  170. strcpy(m->nick, newnick);
  171. return;
  172. }
  173. }
  174. }
  175. static void skillmember(char *channel, char *nick)
  176. {
  177. struct stats_chanset *chan;
  178. struct stats_memberlist *m, *mm;
  179. Context;
  180. chan = findschan(channel);
  181. if (!chan)
  182. return;
  183. m = chan->members;
  184. mm = NULL;
  185. while (m) {
  186. if (!rfc_casecmp(m->nick, nick)) {
  187. nfree(m->nick);
  188. nfree(m->uhost);
  189. if (mm)
  190. mm->next = m->next;
  191. else
  192. chan->members = m->next;
  193. nfree(m);
  194. return;
  195. }
  196. mm = m;
  197. m = m->next;
  198. }
  199. putlog(LOG_MISC, "*", "Stats.mod: skillmember(%s, %s) failed!!!", channel, nick);
  200. }
  201. /* Find the stats-user that belongs to a hostmask
  202. */
  203. static struct stats_userlist *findsuser(char *host)
  204. {
  205. struct stats_userlist *user, *u;
  206. struct stats_hostlist *h, *h2;
  207. int len = 0;
  208. Context;
  209. u = NULL;
  210. h2 = NULL;
  211. for (user = suserlist; user; user = user->next) {
  212. for (h = user->hosts; h; h = h->next) {
  213. /* the longest hostmask gives the best match */
  214. if (!len || (strlen(h->mask) > len)) {
  215. if (wild_match(h->mask, host)) {
  216. u = user;
  217. h2 = h;
  218. len = strlen(h->mask);
  219. }
  220. }
  221. }
  222. }
  223. if (u) {
  224. h2->lastused = now;
  225. return u;
  226. }
  227. return NULL;
  228. }
  229. static struct stats_userlist *findsuser_by_name(char *user)
  230. {
  231. struct stats_userlist *u;
  232. Context;
  233. for (u = suserlist; u; u = u->next)
  234. if (!rfc_casecmp(u->user, user))
  235. return u;
  236. return NULL;
  237. }
  238. static struct stats_userlist *addsuser(char *user, int list, int addhosts)
  239. {
  240. struct stats_userlist *u, *nu;
  241. Context;
  242. for (u = suserlist; u; u = u->next)
  243. if (!rfc_casecmp(u->user, user))
  244. return u;
  245. u = suserlist;
  246. while (u && u->next)
  247. u = u->next;
  248. nu = nmalloc(sizeof(struct stats_userlist));
  249. nu->user = nmalloc(strlen(user) + 1);
  250. strcpy(nu->user, user);
  251. nu->list = list;
  252. nu->addhosts = addhosts;
  253. nu->next = NULL;
  254. nu->hosts = NULL;
  255. nu->email = NULL;
  256. nu->homepage = NULL;
  257. if (u)
  258. u->next = nu;
  259. else
  260. suserlist = nu;
  261. return nu;
  262. }
  263. static void delsuser(char *user)
  264. {
  265. struct stats_userlist *u, *lu;
  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. static void saddhost(struct stats_userlist *u, char *host, time_t lastused)
  296. {
  297. struct stats_hostlist *h, *nh;
  298. Context;
  299. for (h = u->hosts; h; h = h->next)
  300. if (!rfc_casecmp(h->mask, host))
  301. return;
  302. h = u->hosts;
  303. while (h && h->next)
  304. h = h->next;
  305. nh = nmalloc(sizeof(struct stats_hostlist));
  306. nh->mask = nmalloc(strlen(host) + 1);
  307. strcpy(nh->mask, host);
  308. nh->lastused = lastused;
  309. nh->next = NULL;
  310. if (h)
  311. h->next = nh;
  312. else
  313. u->hosts = nh;
  314. }
  315. static int sdelhost(struct stats_userlist *u, char *host)
  316. {
  317. struct stats_hostlist *h, *lh;
  318. Context;
  319. h = u->hosts;
  320. lh = NULL;
  321. while (h) {
  322. if (!rfc_casecmp(h->mask, host)) {
  323. nfree(h->mask);
  324. if (lh)
  325. lh->next = h->next;
  326. else
  327. u->hosts = h->next;
  328. nfree(h);
  329. return 1;
  330. }
  331. lh = h;
  332. h = h->next;
  333. }
  334. return 0;
  335. }
  336. static void stats_autosadd(struct stats_memberlist *m, struct stats_chanset *chan)
  337. {
  338. struct stats_userlist *u;
  339. struct userrec *uu;
  340. char *mhost, *host, *egghost;
  341. struct chanset_t *eggchan;
  342. memberlist *eggmember;
  343. Context;
  344. if (autoadd < 0)
  345. return;
  346. if ((now - m->joined) < (autoadd * 60))
  347. return;
  348. if (m->user) {
  349. debug3("Stats.Mod: stats_autosadd called for %s in %s, but m->user already belongs to %s",
  350. m->nick, chan->chan, m->user->user);
  351. return;
  352. }
  353. #ifndef OLDBOT
  354. eggchan = findchan_by_dname(chan->chan);
  355. #else
  356. eggchan = findchan(chan->chan);
  357. #endif
  358. if (!eggchan) {
  359. putlog(LOG_MISC, "*", "Stats.Mod: Couldn't find eggdrop channel data while autoadding in %s.", chan->chan);
  360. return;
  361. }
  362. eggmember = ismember(eggchan, m->nick);
  363. if (!eggmember) {
  364. putlog(LOG_MISC, "*", "Stats.Mod: Couldn't find eggdrop member data while autoadding %s in %s.", m->nick, chan->chan);
  365. return;
  366. }
  367. egghost = eggmember->userhost;
  368. if (!egghost) {
  369. debug2("Stats.Mod: Couldn't autoadd %s in %s because there isn't an validated host, yet.", m->nick, chan->chan);
  370. return;
  371. }
  372. u = findsuser_by_name(m->nick);
  373. host = nmalloc(strlen(egghost) + strlen(m->nick) + 2);
  374. sprintf(host, "%s!%s", m->nick, egghost);
  375. mhost = nmalloc(strlen(host) + 10); /* better a few bytes too much than too little */
  376. // I use maskstricthost() here, because stats.mod shouldn't strip
  377. // a host anywhere at all. (strict-hosts 0 sucks...)
  378. maskstricthost(host, mhost);
  379. // mhost = nrealloc(mhost, strlen(mhost) + strlen(nick) + 1);sprintf(mhost, "%s%s", m->nick, mhost + 1);
  380. if (u) {
  381. if (u->addhosts) {
  382. saddhost(u, mhost, now);
  383. m->user = u;
  384. putlog(LOG_MISC, "*", "Stats.Mod: Added stats-hostmask %s to %s.", mhost, u->user);
  385. }
  386. } else {
  387. uu = get_user_by_host(host);
  388. if (!uu && (autoadd == 0)) {
  389. nfree(mhost);
  390. nfree(host);
  391. return;
  392. }
  393. if (uu)
  394. u = addsuser(uu->handle, 1, 1);
  395. else
  396. u = addsuser(m->nick, 1, 1);
  397. saddhost(u, mhost, now);
  398. if (uu)
  399. putlog(LOG_MISC, "*", "Stats.Mod: %s matched %s(in the \"common\" userfile), added %s to userbase.", host, uu->handle, u->user);
  400. else
  401. putlog(LOG_MISC, "*", "Stats.Mod: Added %s(%s) to userbase.", u->user, mhost);
  402. m->user = u;
  403. }
  404. if (m->user)
  405. m->stats = findlocstats(chan->chan, m->user->user);
  406. else
  407. m->stats = NULL;
  408. nfree(mhost);
  409. nfree(host);
  410. }
  411. static int listsuser(locstats *ls, char *chan)
  412. {
  413. struct userrec *ou;
  414. if (!use_userfile) {
  415. if (!ls->u)
  416. ls->u = findsuser_by_name(ls->user);
  417. if (ls->u && !ls->u->list)
  418. return 0;
  419. } else {
  420. ou = get_user_by_handle(userlist, ls->user);
  421. if (matchattr(ou, nostatsflags, chan))
  422. return 0;
  423. }
  424. return 1;
  425. }
  426. static int countsusers()
  427. {
  428. static struct stats_userlist *u;
  429. int users = 0;
  430. Context;
  431. for (u = suserlist; u; u = u->next)
  432. users++;
  433. return users;
  434. }
  435. static int counthosts()
  436. {
  437. static struct stats_userlist *u;
  438. static struct stats_hostlist *h;
  439. int hosts = 0;
  440. Context;
  441. for (u = suserlist; u; u = u->next)
  442. for (h = u->hosts; h; h = h->next)
  443. hosts++;
  444. return hosts;
  445. }
  446. static void weed_userlink_from_chanset(struct stats_userlist *u)
  447. {
  448. struct stats_chanset *chan;
  449. struct stats_memberlist *m;
  450. Context;
  451. for (chan = schans; chan; chan = chan->next) {
  452. for (m = chan->members; m; m = m->next) {
  453. if (m->user == u) {
  454. m->user = NULL;
  455. m->stats = NULL;
  456. }
  457. }
  458. }
  459. }
  460. static void weed_statlink_from_chanset(locstats *ls)
  461. {
  462. struct stats_chanset *chan;
  463. struct stats_memberlist *m;
  464. Context;
  465. for (chan = schans; chan; chan = chan->next) {
  466. for (m = chan->members; m; m = m->next) {
  467. if (m->stats == ls) {
  468. m->stats = NULL;
  469. }
  470. }
  471. }
  472. }
  473. /* weed_userlink_from_locstats():
  474. * removes all references to a userstruct from the stat-structs
  475. * (mostly used if the user got deleted)
  476. */
  477. static void weed_userlink_from_locstats(struct stats_userlist *u)
  478. {
  479. globstats *gs;
  480. locstats *ls;
  481. Context;
  482. for (gs = sdata; gs; gs = gs->next)
  483. for (ls = gs->local; ls; ls = ls->next)
  484. if (ls->u == u)
  485. ls->u = NULL;
  486. Context;
  487. }
  488. static int countmembers(struct stats_memberlist *m)
  489. {
  490. int nr = 0;
  491. Context;
  492. while (m) {
  493. nr++;
  494. m = m->next;
  495. }
  496. return nr;
  497. }
  498. static void check_desynch()
  499. {
  500. struct stats_chanset *chan;
  501. struct chanset_t *ch;
  502. Context;
  503. for (ch = chanset; ch; ch = ch->next) {
  504. if (ch->status & CHAN_INACTIVE)
  505. continue;
  506. #if EGG_IS_MIN_VER(10500)
  507. chan = findschan(ch->dname);
  508. #else
  509. chan = findschan(ch->name);
  510. #endif
  511. if (chan)
  512. if (ch->channel.members == countmembers(chan->members))
  513. continue;
  514. #if EGG_IS_MIN_VER(10500)
  515. putlog(LOG_DEBUG, "*", "Stats.Mod: Channel list for %s desynched!!! Resetting...", ch->dname);
  516. #else
  517. putlog(LOG_DEBUG, "*", "Stats.Mod: Channel list for %s desynched!!! Resetting...", ch->name);
  518. #endif
  519. if (chan)
  520. free_one_chan(chan->chan);
  521. #if EGG_IS_MIN_VER(10500)
  522. initchan(ch->dname);
  523. #else
  524. initchan(ch->name);
  525. #endif
  526. }
  527. }
  528. /* used when shosts/susers changed */
  529. static void update_schannel_members()
  530. {
  531. struct stats_chanset *chan;
  532. struct stats_memberlist *m;
  533. struct userrec *u;
  534. char *host;
  535. Context;
  536. for (chan = schans; chan; chan = chan->next) {
  537. for (m = chan->members; m; m = m->next) {
  538. m->user = NULL;
  539. host = nmalloc(strlen(m->nick) + 1 + strlen(m->uhost) + 1);
  540. sprintf(host, "%s!%s", m->nick, m->uhost);
  541. u = get_user_by_host(host);
  542. if (u) {
  543. m->user = findsuser_by_name(u->handle);
  544. if (!m->user) {
  545. m->user = addsuser(u->handle, 1, 0);
  546. debug1("Stats.Mod: Created suserrec for %s.", u->handle);
  547. }
  548. } else
  549. m->user = findsuser(host);
  550. nfree(host);
  551. m->stats = NULL;
  552. }
  553. }
  554. debug0("update_schannel_members()");
  555. }
  556. static void setemail(struct stats_userlist *u, char *email)
  557. {
  558. if (!u) {
  559. putlog(LOG_MISC, "*", "ERROR! Tried to set email for NULL!");
  560. return;
  561. }
  562. if (u->email)
  563. nfree(u->email);
  564. u->email = nmalloc(strlen(email) + 1);
  565. strcpy(u->email, email);
  566. }
  567. static void sethomepage(struct stats_userlist *u, char *homepage)
  568. {
  569. if (!u) {
  570. putlog(LOG_MISC, "*", "ERROR! Tried to set homepage for NULL!");
  571. return;
  572. }
  573. if (u->homepage)
  574. nfree(u->homepage);
  575. u->homepage = nmalloc(strlen(homepage) + 1);
  576. strcpy(u->homepage, homepage);
  577. }