4
0

stats.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. /*
  2. * Statistics module for eggdrop 1.4+
  3. * by G`Quann
  4. */
  5. /*
  6. * stats.c - this is never gonna work... (Oct 99)
  7. */
  8. /*
  9. * oops... seems that it works :) (Dec 99)
  10. */
  11. /*
  12. * Copyright (C) 2000,2001 Florian Sander
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License
  16. * as published by the Free Software Foundation; either version 2
  17. * of the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  27. */
  28. #define MAKING_STATS
  29. #define MODULE_NAME "stats"
  30. #define MODULE_VERSION "1.3.4-dev"
  31. #include "../module.h"
  32. #include "../irc.mod/irc.h"
  33. #include "../server.mod/server.h"
  34. #include "../channels.mod/channels.h"
  35. #include <stdlib.h>
  36. #include <sys/stat.h>
  37. #include <time.h> /* for time_t */
  38. #include <ctype.h>
  39. #include <sys/types.h>
  40. #include <fcntl.h>
  41. #include <errno.h>
  42. #undef global
  43. static Function *global = NULL, *irc_funcs = NULL, *server_funcs = NULL, *channels_funcs = NULL;
  44. #ifndef EGG_IS_MIN_VER
  45. #define EGG_IS_MIN_VER(ver) ((ver) <= 10400)
  46. #endif
  47. #if !EGG_IS_MIN_VER(10500)
  48. #define OLDBOT 1
  49. #endif
  50. #ifndef Context
  51. #define Context context
  52. #endif
  53. #ifndef findchan_by_dname
  54. #define findchan_by_dname findchan
  55. #endif
  56. #ifndef my_htonl
  57. #define my_htonl htonl
  58. #endif
  59. #include "stats.h"
  60. #include "slang.h"
  61. static struct stats_global *sdata = NULL;
  62. static struct stats_chanset *schans = NULL;
  63. static struct stats_userlist *suserlist = NULL;
  64. static struct slang_lang *slangs = NULL;
  65. static struct slang_chan *slangchans = NULL;
  66. static char statsfile[121] = "statsmod.dat";
  67. static char webstats[510] = "words letters lines actions smileys joins kicks modes topics minutes";
  68. static char graphstats[510] = "words letters lines actions smileys joins kicks modes topics minutes";
  69. static char stat_reply[128] = "words letters smileys minutes";
  70. static char graphgif[128] = "";
  71. static char graphcolor[20] = "blue";
  72. static char webdir[256] = "../public_html";
  73. static char webfiles[256] = "";
  74. static char webfile_suffix[20] = ".html";
  75. static char bodytag[512] = "<BODY BGCOLOR=#000000 TEXT=#1A9DFF LINK=#00D993 VLINK=#71C2FF ALINK=#2FFFBB>";
  76. static char smileys[128] = ":-) :) ;) ;-) ^_^ :-D :-P :P =) ;D";
  77. static char badflags[20] = "ofvb|ofv";
  78. static char nostatsflags[20] = "b|-";
  79. static char nopeak[20] = "b|-";
  80. static char network[41] = "unknown-net";
  81. static char stats_loglevel[20] = "1";
  82. static char livestats_log[121];
  83. static char livestats_ignore_msg[256] = "<H1>You are on ignore.</H1>";
  84. static char livestats_ip[21] = "";
  85. static int statsfilemode = 0600;
  86. static int webupdate = 0;
  87. static int webnr = 15;
  88. static int graphnr = 15;
  89. static int stats_save_time = 10;
  90. static int autoadd = 5;
  91. static int stat_expire_user = 0;
  92. static int write_today = 1;
  93. static int maxstat_thr = 0;
  94. static int maxstat_time = 0;
  95. static int maxlivestats_thr = 0;
  96. static int maxlivestats_time = 0;
  97. static int mstat_thr = 0;
  98. static time_t mstat_time = 0;
  99. static int livestats_timeout;
  100. static int offset = 0;
  101. static int max_words = 20;
  102. static int topwords_limit = 5;
  103. static int quote_freq = 10;
  104. static int log_wordstats = 0;
  105. static int lasthour = 0;
  106. static int lastmonth = 0;
  107. static int min_word_length = 0;
  108. static int use_userfile = 0;
  109. static int table_color = 0x3850B8;
  110. static int fade_table_to = 0x000000;
  111. static int table_border = 0;
  112. static int log_urls = 1;
  113. static int kick_context = 0;
  114. static int display_kicks = 0;
  115. static int display_average_users = 1;
  116. static int show_userlist = 1;
  117. static int show_usersonchan = 1;
  118. static int list_secret_chans = 1;
  119. #include "datahandling.c"
  120. #include "slang.c"
  121. #include "sensors.c"
  122. #include "userrec.c"
  123. #include "misc.c"
  124. #include "pubcmds.c"
  125. #include "msgcmds.c"
  126. #include "dcccmds.c"
  127. #include "tclstats.c"
  128. #if EGG_IS_MIN_VER(10500)
  129. #include "webfiles.c"
  130. #endif
  131. #include "user.c"
  132. #include "livestats.c"
  133. static int stats_save_temp = 1;
  134. static int webupdate_temp = 1;
  135. static int stats_expmem()
  136. {
  137. int size = 0;
  138. struct stats_global *sl = sdata;
  139. Context;
  140. while (sl) {
  141. size += sizeof(struct stats_global);
  142. size += strlen(sl->chan) + 1;
  143. size += localstats_expmem(sl->local);
  144. size += wordstats_expmem(sl->words);
  145. size += topics_expmem(sl->topics);
  146. size += urls_expmem(sl->urls);
  147. size += hosts_expmem(sl->hosts);
  148. size += quotes_expmem(sl->log);
  149. size += kicks_expmem(sl->kicks);
  150. sl = sl->next;
  151. }
  152. Context;
  153. size += suserlist_expmem(suserlist);
  154. size += chanlist_expmem(schans);
  155. size += slang_expmem();
  156. return size;
  157. }
  158. static int suserlist_expmem(struct stats_userlist *e)
  159. {
  160. int size = 0;
  161. Context;
  162. while (e) {
  163. size += sizeof(struct stats_userlist);
  164. size += strlen(e->user) + 1;
  165. if (e->email)
  166. size += strlen(e->email) + 1;
  167. if (e->homepage)
  168. size += strlen(e->homepage) + 1;
  169. size += hostlist_expmem(e->hosts);
  170. e = e->next;
  171. }
  172. return size;
  173. }
  174. static int hostlist_expmem(struct stats_hostlist *e)
  175. {
  176. int size = 0;
  177. Context;
  178. while (e) {
  179. size += sizeof(struct stats_hostlist);
  180. size += strlen(e->mask) + 1;
  181. e = e->next;
  182. }
  183. return size;
  184. }
  185. static int chanlist_expmem(struct stats_chanset *e)
  186. {
  187. int size = 0;
  188. Context;
  189. while (e) {
  190. size += sizeof(struct stats_chanset);
  191. size += strlen(e->chan) + 1;
  192. size += memberlist_expmem(e->members);
  193. e = e->next;
  194. }
  195. return size;
  196. }
  197. static int memberlist_expmem(struct stats_memberlist *e)
  198. {
  199. int size = 0;
  200. Context;
  201. while (e) {
  202. size += sizeof(struct stats_memberlist);
  203. size += strlen(e->nick) + 1;
  204. size += strlen(e->uhost) + 1;
  205. e = e->next;
  206. }
  207. return size;
  208. }
  209. static int localstats_expmem(struct stats_local *sl)
  210. {
  211. int size = 0;
  212. Context;
  213. while (sl) {
  214. size += sizeof(struct stats_local);
  215. size += strlen(sl->user) + 1;
  216. size += wordstats_expmem(sl->words);
  217. size += quotes_expmem(sl->quotes);
  218. sl = sl->next;
  219. }
  220. Context;
  221. return size;
  222. }
  223. static int wordstats_expmem(wordstats *l)
  224. {
  225. int size = 0;
  226. Context;
  227. while (l) {
  228. size += strlen(l->word) + 1;
  229. size += sizeof(wordstats);
  230. l = l->next;
  231. }
  232. return size;
  233. }
  234. static int quotes_expmem(quotestr *l)
  235. {
  236. int size = 0;
  237. Context;
  238. while (l) {
  239. size += strlen(l->quote) + 1;
  240. size += sizeof(quotestr);
  241. l = l->next;
  242. }
  243. return size;
  244. }
  245. static int topics_expmem(topicstr *e)
  246. {
  247. int size = 0;
  248. Context;
  249. while (e) {
  250. size += strlen(e->topic) + 1;
  251. size += strlen(e->by) + 1;
  252. size += sizeof(topicstr);
  253. e = e->next;
  254. }
  255. return size;
  256. }
  257. static int urls_expmem(struct stats_url *e)
  258. {
  259. int size = 0;
  260. Context;
  261. while (e) {
  262. size += strlen(e->url) + 1;
  263. size += strlen(e->by) + 1;
  264. size += sizeof(struct stats_url);
  265. e = e->next;
  266. }
  267. return size;
  268. }
  269. static int kicks_expmem(struct stats_kick *e)
  270. {
  271. int size = 0;
  272. Context;
  273. while (e) {
  274. size += sizeof(struct stats_kick);
  275. size += quotes_expmem(e->log);
  276. e = e->next;
  277. }
  278. return size;
  279. }
  280. static int hosts_expmem(hoststr *e)
  281. {
  282. int size = 0;
  283. Context;
  284. while (e) {
  285. size += strlen(e->host) + 1;
  286. size += sizeof(hoststr);
  287. e = e->next;
  288. }
  289. return size;
  290. }
  291. static void free_stats()
  292. {
  293. struct stats_global *sl;
  294. Context;
  295. while (sdata) {
  296. sl = sdata->next;
  297. free_localstats(sdata->local);
  298. free_wordstats(sdata->words);
  299. free_topics(sdata->topics);
  300. free_urls(sdata->urls);
  301. free_quotes(sdata->log);
  302. free_hosts(sdata->hosts);
  303. free_kicks(sdata->kicks);
  304. nfree(sdata->chan);
  305. nfree(sdata);
  306. sdata = sl;
  307. }
  308. free_chanlist(schans);
  309. free_suserlist(suserlist);
  310. free_slang();
  311. Context;
  312. return;
  313. }
  314. static void free_suserlist(struct stats_userlist *e)
  315. {
  316. struct stats_userlist *ee;
  317. Context;
  318. while (e) {
  319. ee = e->next;
  320. nfree(e->user);
  321. if (e->email)
  322. nfree(e->email);
  323. if (e->homepage)
  324. nfree(e->homepage);
  325. free_hostlist(e->hosts);
  326. nfree(e);
  327. e = ee;
  328. }
  329. }
  330. static void free_hostlist(struct stats_hostlist *e)
  331. {
  332. struct stats_hostlist *ee;
  333. Context;
  334. while (e) {
  335. ee = e->next;
  336. nfree(e->mask);
  337. nfree(e);
  338. e = ee;
  339. }
  340. }
  341. static void free_chanlist(struct stats_chanset *e)
  342. {
  343. struct stats_chanset *ee;
  344. Context;
  345. while (e) {
  346. ee = e->next;
  347. nfree(e->chan);
  348. free_memberlist(e->members);
  349. nfree(e);
  350. e = ee;
  351. }
  352. }
  353. static void free_one_chan(char *channel)
  354. {
  355. struct stats_chanset *e, *ee;
  356. Context;
  357. e = schans;
  358. ee = NULL;
  359. while (e) {
  360. if (!rfc_casecmp(e->chan, channel)) {
  361. nfree(e->chan);
  362. free_memberlist(e->members);
  363. if (ee)
  364. ee->next = e->next;
  365. else
  366. schans = e->next;
  367. nfree(e);
  368. return;
  369. }
  370. ee = e;
  371. e = e->next;
  372. }
  373. }
  374. static void free_memberlist(struct stats_memberlist *e)
  375. {
  376. struct stats_memberlist *ee;
  377. Context;
  378. while (e) {
  379. ee = e->next;
  380. nfree(e->nick);
  381. nfree(e->uhost);
  382. nfree(e);
  383. e = ee;
  384. }
  385. }
  386. static void free_localstats(struct stats_local *sl)
  387. {
  388. struct stats_local *sll;
  389. Context;
  390. while (sl) {
  391. Context;
  392. sll = sl->next;
  393. free_wordstats(sl->words);
  394. free_quotes(sl->quotes);
  395. nfree(sl->user);
  396. nfree(sl);
  397. sl = sll;
  398. Context;
  399. }
  400. Context;
  401. return;
  402. }
  403. static void free_wordstats(wordstats *l)
  404. {
  405. wordstats *ll;
  406. Context;
  407. while (l) {
  408. ll = l->next;
  409. nfree(l->word);
  410. nfree(l);
  411. l = ll;
  412. }
  413. return;
  414. }
  415. static void free_quotes(quotestr *l)
  416. {
  417. quotestr *ll;
  418. Context;
  419. while (l) {
  420. ll = l->next;
  421. nfree(l->quote);
  422. nfree(l);
  423. l = ll;
  424. }
  425. return;
  426. }
  427. static void free_topics(topicstr *e)
  428. {
  429. topicstr *ee;
  430. Context;
  431. while (e) {
  432. ee = e->next;
  433. nfree(e->topic);
  434. nfree(e->by);
  435. nfree(e);
  436. e = ee;
  437. }
  438. return;
  439. }
  440. static void free_urls(struct stats_url *e)
  441. {
  442. struct stats_url *ee;
  443. Context;
  444. while (e) {
  445. ee = e->next;
  446. nfree(e->url);
  447. nfree(e->by);
  448. nfree(e);
  449. e = ee;
  450. }
  451. return;
  452. }
  453. static void free_kicks(struct stats_kick *e)
  454. {
  455. struct stats_kick *ee;
  456. Context;
  457. while (e) {
  458. ee = e->next;
  459. free_quotes(e->log);
  460. nfree(e);
  461. e = ee;
  462. }
  463. }
  464. static void free_hosts(hoststr *e)
  465. {
  466. hoststr *ee;
  467. Context;
  468. while (e) {
  469. ee = e->next;
  470. nfree(e->host);
  471. nfree(e);
  472. e = ee;
  473. }
  474. return;
  475. }
  476. /* a report on the module status */
  477. static void stats_report(int idx, int details)
  478. {
  479. int size, users, hosts;
  480. Context;
  481. size = stats_expmem();
  482. users = countsusers();
  483. hosts = counthosts();
  484. dprintf(idx, " Stats-userbase contains %d users and %d hosts\n", users, hosts);
  485. if (details)
  486. dprintf(idx, " using %d bytes\n", size);
  487. }
  488. static void stats_minutely ()
  489. {
  490. sensor_minutely();
  491. if (stats_save_temp >= stats_save_time) {
  492. write_stats();
  493. stats_save_temp = 1;
  494. } else
  495. stats_save_temp++;
  496. if ((webupdate_temp >= webupdate) && (webupdate > 0)) {
  497. webupdate_temp = 1;
  498. #if EGG_IS_MIN_VER(10500)
  499. write_new_webstats();
  500. #else
  501. putlog(LOG_MISC, "*", "Couldn't write static webstats! Feature unsupported on eggdrop1.4!");
  502. #endif
  503. } else
  504. webupdate_temp++;
  505. check_desynch();
  506. }
  507. static void stats_5minutely ()
  508. {
  509. Context;
  510. sensor_countusers();
  511. }
  512. static void stats_daily ()
  513. {
  514. Context;
  515. deloldstatusers();
  516. purgestats();
  517. reset_tstats();
  518. if (lastmonth != getmonth()) {
  519. reset_mwstats(S_MONTHLY);
  520. lastmonth = getmonth();
  521. }
  522. if (ismonday())
  523. reset_mwstats(S_WEEKLY);
  524. update_schannel_members();
  525. Context;
  526. }
  527. static tcl_ints my_tcl_ints[] =
  528. {
  529. {"save-stats", &stats_save_time, 0},
  530. {"webupdate", &webupdate, 0},
  531. {"webnr", &webnr, 0},
  532. {"topnr", &webnr, 0},
  533. {"graphnr", &graphnr, 0},
  534. {"autoadd", &autoadd, 0},
  535. {"expire-users", &stat_expire_user, 0},
  536. {"write-today", &write_today, 0},
  537. {"stats-file-mode", &statsfilemode, 0},
  538. {"livestats-timeout", &livestats_timeout, 0},
  539. {"offset", &offset, 0},
  540. {"max-words", &max_words, 0},
  541. {"topwords-limit", &topwords_limit, 0},
  542. {"quote-frequency", &quote_freq, 0},
  543. {"log-wordstats", &log_wordstats, 0},
  544. {"min-word-length", &min_word_length, 0},
  545. {"use-eggdrop-userfile", &use_userfile, 0},
  546. {"table-color", &table_color, 0},
  547. {"fade-table-to", &fade_table_to, 0},
  548. {"table-border", &table_border, 0},
  549. {"display-urls", &log_urls, 0},
  550. {"kick-context", &kick_context, 0},
  551. {"display-kicks", &display_kicks, 0},
  552. {"display-average-users", &display_average_users, 0},
  553. {"show-userlist", &show_userlist, 0},
  554. {"show-usersonchan", &show_usersonchan, 0},
  555. {"list-secret-chans", &list_secret_chans, 0},
  556. {0, 0, 0}
  557. };
  558. static tcl_strings my_tcl_strings[] =
  559. {
  560. {"statsfile", statsfile, 121, 0},
  561. {"webstats", webstats, 510, 0},
  562. {"topstats", webstats, 510, 0},
  563. {"webdir", webdir, 256, 0},
  564. {"webfiles", webfiles, 256, 0},
  565. {"webfile-suffix", webfile_suffix, 20, 0},
  566. {"bodytag", bodytag, 512, 0},
  567. {"smileys", smileys, 128, 0},
  568. {"smilies", smileys, 128, 0},
  569. {"graphstats", graphstats, 510, 0},
  570. {"graphgif", graphgif, 128, 0},
  571. {"graphcolor", graphcolor, 20, 0},
  572. {"anti-autoadd-flags", badflags, 20, 0},
  573. {"anti-stats-flag", nostatsflags, 20, 0},
  574. {"anti-peak-flag", nopeak, 20, 0},
  575. {"network", network, 40, 0},
  576. {"livestats-loglevel", stats_loglevel, 20, 0},
  577. {"livestats-log", livestats_log, 121, 0},
  578. {"stat-reply", stat_reply, 128, 0},
  579. {"livestats-ignore-msg", livestats_ignore_msg, 128, 0},
  580. {"livestats-ip", livestats_ip, 20, 0},
  581. {0, 0, 0, 0}
  582. };
  583. static tcl_coups my_tcl_coups[] =
  584. {
  585. {"max-stat-cmds", &maxstat_thr, &maxstat_time},
  586. {"max-livestats-access", &maxlivestats_thr, &maxlivestats_time},
  587. {0, 0, 0},
  588. };
  589. static char *stats_close()
  590. {
  591. Context;
  592. stop_listen_livestats();
  593. write_stats();
  594. free_stats();
  595. rem_builtins(H_dcc, mydcc);
  596. rem_builtins(H_pubm, stats_pubm);
  597. rem_builtins(H_pub, stats_pub);
  598. rem_builtins(H_msg, stats_msg);
  599. rem_builtins(H_topc, stats_topc);
  600. rem_builtins(H_ctcp, stats_ctcp);
  601. rem_builtins(H_kick, stats_kick);
  602. rem_builtins(H_mode, stats_mode);
  603. rem_builtins(H_nick, stats_nick);
  604. rem_builtins(H_join, stats_join);
  605. rem_builtins(H_nkch, stats_nkch);
  606. rem_builtins(H_sign, stats_sign);
  607. rem_builtins(H_part, stats_part);
  608. rem_tcl_ints(my_tcl_ints);
  609. rem_tcl_coups(my_tcl_coups);
  610. rem_tcl_strings(my_tcl_strings);
  611. rem_tcl_commands(mytcls);
  612. rem_help_reference("stats.help");
  613. del_hook(HOOK_MINUTELY, (Function) stats_minutely);
  614. del_hook(HOOK_DAILY, (Function) stats_daily);
  615. del_hook(HOOK_5MINUTELY, (Function) stats_5minutely);
  616. module_undepend(MODULE_NAME);
  617. return NULL;
  618. }
  619. char *stats_start();
  620. static Function stats_table[] =
  621. {
  622. (Function) stats_start,
  623. (Function) stats_close,
  624. (Function) stats_expmem,
  625. (Function) stats_report,
  626. };
  627. char *stats_start(Function * global_funcs)
  628. {
  629. global = global_funcs;
  630. Context;
  631. sdata = NULL;
  632. schans = NULL;
  633. suserlist = NULL;
  634. slangs = NULL;
  635. slangchans = NULL;
  636. Context;
  637. module_register(MODULE_NAME, stats_table, 1, 3);
  638. if (!(irc_funcs = module_depend(MODULE_NAME, "irc", 1, 0)))
  639. return "You need the irc module to use the stats module.";
  640. if (!(server_funcs = module_depend(MODULE_NAME, "server", 1, 0)))
  641. return "You need the server module to use the stats module.";
  642. if (!(channels_funcs = module_depend(MODULE_NAME, "channels", 1, 0)))
  643. return "You need the channels module to use the stats module.";
  644. if (!module_depend(MODULE_NAME, "eggdrop", 108, 0)) {
  645. if (!module_depend(MODULE_NAME, "eggdrop", 107, 0)) {
  646. if (!module_depend(MODULE_NAME, "eggdrop", 106, 0)) {
  647. if (!module_depend(MODULE_NAME, "eggdrop", 105, 0)) {
  648. if (!module_depend(MODULE_NAME, "eggdrop", 104, 0)) {
  649. module_undepend(MODULE_NAME);
  650. return "Sorry, stats.mod doesn't work with this eggdrop version.";
  651. }
  652. }
  653. }
  654. }
  655. }
  656. #ifndef OLDBOT
  657. livestats_timeout = 10;
  658. #else
  659. livestats_timeout = 1;
  660. #endif
  661. livestats_log[0] = 0;
  662. add_builtins(H_dcc, mydcc);
  663. add_builtins(H_pubm, stats_pubm);
  664. add_builtins(H_pub, stats_pub);
  665. add_builtins(H_msg, stats_msg);
  666. add_builtins(H_topc, stats_topc);
  667. add_builtins(H_ctcp, stats_ctcp);
  668. add_builtins(H_kick, stats_kick);
  669. add_builtins(H_mode, stats_mode);
  670. add_builtins(H_nick, stats_nick);
  671. add_builtins(H_join, stats_join);
  672. add_builtins(H_nkch, stats_nkch);
  673. add_builtins(H_sign, stats_sign);
  674. add_builtins(H_part, stats_part);
  675. add_tcl_ints(my_tcl_ints);
  676. add_tcl_coups(my_tcl_coups);
  677. add_tcl_strings(my_tcl_strings);
  678. add_tcl_commands(mytcls);
  679. add_hook(HOOK_MINUTELY, (Function) stats_minutely);
  680. add_hook(HOOK_DAILY, (Function) stats_daily);
  681. add_hook(HOOK_5MINUTELY, (Function) stats_5minutely);
  682. add_help_reference("stats.help");
  683. lastmonth = getmonth();
  684. read_stats();
  685. #if EGG_IS_MIN_VER(10503)
  686. initudef(1, "nopubstats", 1);
  687. initudef(1, "quietstats", 1);
  688. initudef(1, "nostats", 1);
  689. #endif
  690. putlog(LOG_MISC, "*", "Stats.mod v%s loaded.", MODULE_VERSION);
  691. return NULL;
  692. }