stats.c 17 KB

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