Advertisement
Guest User

Untitled

a guest
Dec 28th, 2018
125
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 19.59 KB | None | 0 0
  1. /*
  2.  * Module skeleton, by Carsten V. Munk 2001 <stskeeps@tspre.org>
  3.  * May be used, modified, or changed by anyone, no license applies.
  4.  * You may relicense this, to any license
  5.  */
  6.  
  7.  /* for compile, use:
  8.  EXLIBS="-lmysqlclient" make
  9.  */
  10.  
  11. #define USE_MYSQL
  12. #ifdef USE_MYSQL
  13.  
  14. #define MYCONF "wwwstats"
  15. #define DEFAULT_MYSQL_INTERVAL 900
  16. #define list_add list_add_MYSQL
  17. #include <mysql/mysql.h>
  18. #undef list_add
  19. #endif
  20. #include "unrealircd.h"
  21. #include "threads.h"
  22. #include <sys/socket.h>
  23. #include <sys/un.h>
  24.  
  25. struct chanStats_s {
  26.     aChannel *chan;
  27.     char chname[2*CHANNELLEN+1];
  28.     int msg;
  29.     int exists;
  30.     struct chanStats_s *next;
  31. };
  32.  
  33. struct channelInfo_s {
  34.     int hashnum;
  35.     aChannel *chan;
  36.     int messages;
  37. };
  38.  
  39. struct asendInfo_s {
  40.     int sock;
  41.     char *buf;
  42.     int bufsize;
  43.     char *tmpbuf;
  44. };
  45.  
  46. typedef struct chanStats_s chanStats;
  47. typedef struct channelInfo_s channelInfo;
  48. typedef struct asendInfo_s asendInfo;
  49.  
  50. int counter;
  51. time_t init_time;
  52.  
  53. int stats_socket;
  54. THREAD thr;
  55. MUTEX chans_mutex;
  56. int chans_mutex_ai;
  57. char send_buf[4096];
  58. struct sockaddr_un stats_addr;
  59. #ifdef USE_MYSQL
  60. THREAD mysql_thr;
  61. MYSQL *stats_db;
  62. #endif
  63.  
  64. char* wwwstats_msg(aClient *sptr, aChannel *chptr, char *msg, int notice);
  65. void wwwstats_thr(void*);
  66. void asend_sprintf(asendInfo *info, char *fmt, ...);
  67. void append_int_param(asendInfo *info, char *param, int value);
  68. int getChannelInfo(channelInfo *prev);
  69. aChannel *getChanByName(char *name);
  70. void removeExpiredChannels();
  71. char *tmp_escape(char *d, const char *a);
  72. void appendChannel(aChannel *ch, int messages);
  73. #ifdef USE_MYSQL
  74. void saveChannels(time_t act_time);
  75. void saveStats(time_t act_time);
  76. int mysql_query_sprintf(char *buf, char *fmt, ...);
  77. void wwwstats_mysql_thr(void *d);
  78. void loadChannels(void);
  79. void send_mysql_error(void);
  80. #endif
  81. int wwwstats_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
  82. int wwwstats_configposttest(int *errs);
  83. int wwwstats_configrun(ConfigFile *cf, ConfigEntry *ce, int type);
  84.  
  85. chanStats *chans, *chans_last;
  86.  
  87. // config file stuff, based on Gottem's module
  88.  
  89. #ifdef USE_MYSQL
  90. static char *mysql_user;
  91. static char *mysql_pass;
  92. static char *mysql_db;
  93. static char *mysql_host;
  94. static int use_mysql;
  95. static int mysql_interval;
  96. #endif
  97. static char *socket_path;
  98. int socket_hpath=0;
  99.  
  100. int wwwstats_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) {
  101.     ConfigEntry *cep; // For looping through our bl0cc
  102.     int errors = 0; // Error count
  103.     int i; // iter8or m8
  104.    
  105. #ifdef USE_MYSQL
  106.     int mysql_huser=0, mysql_hpass=0, mysql_hdb=0, mysql_en=0, mysql_hhost=0;
  107. #endif
  108.  
  109.     // Since we'll add a new top-level block to unrealircd.conf, need to filter on CONFIG_MAIN lmao
  110.     if(type != CONFIG_MAIN)
  111.         return 0; // Returning 0 means idgaf bout dis
  112.  
  113.     // Check for valid config entries first
  114.     if(!ce || !ce->ce_varname)
  115.         return 0;
  116.  
  117.     // If it isn't our bl0ck, idc
  118.     if(strcmp(ce->ce_varname, MYCONF))
  119.         return 0;
  120.  
  121.     // Loop dat shyte fam
  122.     for(cep = ce->ce_entries; cep; cep = cep->ce_next) {
  123.         // Do we even have a valid name l0l?
  124.         if(!cep->ce_varname) {
  125.             config_error("%s:%i: blank %s item", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF); // Rep0t error
  126.             errors++; // Increment err0r count fam
  127.             continue; // Next iteration imo tbh
  128.         }
  129.  
  130. #ifdef USE_MYSQL
  131.         if(!strcmp(cep->ce_varname, "mysql-user")) {
  132.             if(!cep->ce_vardata) {
  133.                 config_error("%s:%i: %s::%s must be a string", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
  134.                 errors++; // Increment err0r count fam
  135.                 continue;
  136.             }
  137.             mysql_huser=1;
  138.             continue;
  139.         }
  140.  
  141.         if(!strcmp(cep->ce_varname, "mysql-pass")) {
  142.             if(!cep->ce_vardata) {
  143.                 config_error("%s:%i: %s::%s must be a string", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
  144.                 errors++; // Increment err0r count fam
  145.                 continue;
  146.             }
  147.             mysql_hpass=1;
  148.             continue;
  149.         }
  150.        
  151.         if(!strcmp(cep->ce_varname, "mysql-db")) {
  152.             if(!cep->ce_vardata) {
  153.                 config_error("%s:%i: %s::%s must be a string", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
  154.                 errors++; // Increment err0r count fam
  155.                 continue;
  156.             }
  157.             mysql_hdb=1;
  158.             continue;
  159.         }
  160.        
  161.         if(!strcmp(cep->ce_varname, "mysql-host")) {
  162.             if(!cep->ce_vardata) {
  163.                 config_error("%s:%i: %s::%s must be a string", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
  164.                 errors++; // Increment err0r count fam
  165.                 continue;
  166.             }
  167.             mysql_hhost=1;
  168.             continue;
  169.         }
  170.        
  171.         if(!strcmp(cep->ce_varname, "mysql-interval")) {
  172.             if(!cep->ce_vardata) {
  173.                 config_error("%s:%i: %s::%s must be an integer between 1 and 1000 (minutes)", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
  174.                 errors++; // Increment err0r count fam
  175.                 continue; // Next iteration imo tbh
  176.             }
  177.             // Should be an integer yo
  178.             for(i = 0; cep->ce_vardata[i]; i++) {
  179.                 if(!isdigit(cep->ce_vardata[i])) {
  180.                     config_error("%s:%i: %s::%s must be an integer between 1 and 1000 (minutes)", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
  181.                     errors++; // Increment err0r count fam
  182.                     break;
  183.                 }
  184.             }
  185.             if(!errors && (atoi(cep->ce_vardata) < 1 || atoi(cep->ce_vardata) > 1000)) {
  186.                 config_error("%s:%i: %s::%s must be an integer between 1 and 1000 (minutes)", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
  187.                 errors++; // Increment err0r count fam
  188.             }
  189.             continue;
  190.         }
  191.  
  192.         if(!strcmp(cep->ce_varname, "use-mysql")) { // no value expected
  193.             mysql_en = 1;
  194.             continue;
  195.         }
  196. #endif
  197.  
  198.         if(!strcmp(cep->ce_varname, "socket-path")) {
  199.             if(!cep->ce_vardata) {
  200.                 config_error("%s:%i: %s::%s must be a path", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
  201.                 errors++; // Increment err0r count fam
  202.                 continue;
  203.             }
  204.             socket_hpath = 1;
  205.             continue;
  206.         }
  207.  
  208.         // Anything else is unknown to us =]
  209.         config_warn("%s:%i: unknown item %s::%s", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname); // So display just a warning
  210.     }
  211.    
  212.     if(mysql_en && (!mysql_huser || !mysql_hpass || !mysql_hdb || !mysql_hhost)){
  213.         config_warn("m_wwwstats: error: your mysql configuration is incomplete! Please either correct or disable it!");
  214.         errors++;
  215.     }
  216.    
  217.     *errs = errors;
  218.     return errors ? -1 : 1; // Returning 1 means "all good", -1 means we shat our panties
  219. }
  220.  
  221. int wwwstats_configposttest(int *errs) {
  222.     if(!socket_hpath){
  223.         config_warn("m_wwwstats: warning: socket path not specified! Socket won't be created.");
  224.     }
  225.     return 1;
  226. }
  227.  
  228. // "Run" the config (everything should be valid at this point)
  229. int wwwstats_configrun(ConfigFile *cf, ConfigEntry *ce, int type) {
  230.     ConfigEntry *cep; // For looping through our bl0cc
  231.  
  232.     // Since we'll add a new top-level block to unrealircd.conf, need to filter on CONFIG_MAIN lmao
  233.     if(type != CONFIG_MAIN)
  234.         return 0; // Returning 0 means idgaf bout dis
  235.  
  236.     // Check for valid config entries first
  237.     if(!ce || !ce->ce_varname)
  238.         return 0;
  239.  
  240.     // If it isn't our bl0cc, idc
  241.     if(strcmp(ce->ce_varname, MYCONF))
  242.         return 0;
  243.  
  244.     // Loop dat shyte fam
  245.     for(cep = ce->ce_entries; cep; cep = cep->ce_next) {
  246.         // Do we even have a valid name l0l?
  247.         if(!cep->ce_varname)
  248.             continue; // Next iteration imo tbh
  249.  
  250. #ifdef USE_MYSQL
  251.         if(cep->ce_vardata && !strcmp(cep->ce_varname, "mysql-user")) {
  252.             mysql_user = strdup(cep->ce_vardata);
  253.             continue;
  254.         }
  255.        
  256.         if(cep->ce_vardata && !strcmp(cep->ce_varname, "mysql-pass")) {
  257.             mysql_pass = strdup(cep->ce_vardata);
  258.             continue;
  259.         }
  260.        
  261.         if(cep->ce_vardata && !strcmp(cep->ce_varname, "mysql-db")) {
  262.             mysql_db = strdup(cep->ce_vardata);
  263.             continue;
  264.         }
  265.  
  266.         if(cep->ce_vardata && !strcmp(cep->ce_varname, "mysql-host")) {
  267.             mysql_host = strdup(cep->ce_vardata);
  268.             continue;
  269.         }
  270.        
  271.         if(!strcmp(cep->ce_varname, "mysql-interval")) {
  272.             mysql_interval = atoi(cep->ce_vardata);
  273.             continue;
  274.         }
  275.        
  276.         if(!strcmp(cep->ce_varname, "use-mysql")) {
  277.             use_mysql = 1;
  278.             continue;
  279.         }
  280. #endif
  281.        
  282.         if(cep->ce_vardata && !strcmp(cep->ce_varname, "socket-path")) {
  283.             socket_path = strdup(cep->ce_vardata);
  284.             continue;
  285.         }
  286.     }
  287. #ifdef USE_MYSQL
  288.     if(mysql_interval == 0) mysql_interval = DEFAULT_MYSQL_INTERVAL;
  289. #endif
  290.     return 1; // We good
  291. }
  292.  
  293. ModuleHeader MOD_HEADER(m_wwwstats)
  294.   = {
  295.     "m_wwwstats",     /* Name of module */
  296.     "$Id: v1.07 2018/12/28 rocket/k4be$", /* Version */
  297.     "Provides data for network stats", /* Short description of module */
  298.     "3.2-b8-1",
  299.     NULL
  300.     };
  301.  
  302. // Configuration testing-related hewks go in testing phase obv
  303. MOD_TEST(m_wwwstats) {
  304.     // We have our own config block so we need to checkem config obv m9
  305.     // Priorities don't really matter here
  306.     HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, wwwstats_configtest);
  307.     HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, wwwstats_configposttest);
  308.     return MOD_SUCCESS;
  309. }
  310.  
  311. /* This is called on module init, before Server Ready */
  312. MOD_INIT(m_wwwstats)
  313. {
  314.     /*
  315.      * We call our add_Command crap here
  316.     */
  317.     HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, wwwstats_configrun);
  318.     HookAddPChar(modinfo->handle, HOOKTYPE_PRE_CHANMSG, 0, wwwstats_msg);
  319.  
  320.     return MOD_SUCCESS;
  321. }
  322.  
  323. /* Is first run when server is 100% ready */
  324. MOD_LOAD(m_wwwstats)
  325. {
  326.     #ifdef USE_MYSQL
  327.     MYSQL_RES *res;
  328.     MYSQL_ROW row;
  329.     #endif
  330.    
  331.     if(socket_path){
  332.         stats_addr.sun_family = AF_UNIX;
  333.         strcpy(stats_addr.sun_path, socket_path);
  334.         unlink(stats_addr.sun_path);
  335.     }
  336.  
  337.     #ifdef USE_MYSQL
  338.     stats_db = mysql_init(NULL);
  339.     if(!stats_db) send_mysql_error();
  340.     #endif
  341.     IRCCreateMutex(chans_mutex);
  342.     chans_mutex_ai = 0;
  343.     counter = 0;
  344.  
  345.     chans = NULL;
  346.     chans_last = NULL;
  347.  
  348.     if(socket_path){
  349.         stats_socket = socket(PF_UNIX, SOCK_STREAM, 0);
  350.         bind(stats_socket, (struct sockaddr*) &stats_addr, SUN_LEN(&stats_addr));
  351.         chmod(socket_path, 0777);
  352.         listen(stats_socket, 5);
  353.     }
  354.  
  355.     #ifdef USE_MYSQL
  356.     if(use_mysql && mysql_host && mysql_user && mysql_pass && mysql_db){
  357.         mysql_real_connect(stats_db, mysql_host, mysql_user, mysql_pass, mysql_db, 0, NULL, 0);
  358.  
  359.         mysql_query(stats_db, "CREATE TABLE IF NOT EXISTS `chanlist` (`id` int(11) NOT NULL AUTO_INCREMENT, `date` int(11), `name` char(64), `topic` text, `users` int(11),  `messages` int(11), PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`,`users`,`messages`), KEY `name_3` (`name`), KEY `date` (`date`) )");
  360.         mysql_query(stats_db, "CREATE TABLE IF NOT EXISTS `stat` (`id` int(11) NOT NULL AUTO_INCREMENT, `date` int(11), `clients` int(11), `servers` int(11), `messages` int(11), `channels` int(11), PRIMARY KEY (`id`), UNIQUE KEY `changes` (`clients`,`servers`,`messages`,`channels`), KEY `date` (`date`) )");
  361.  
  362.         mysql_query(stats_db, "SELECT messages FROM stat ORDER BY id DESC LIMIT 1");
  363.         res = mysql_use_result(stats_db);
  364.         if(!res) send_mysql_error(); else {
  365.             if((row = mysql_fetch_row(res))) {
  366.                 counter = strtoul(row[0], NULL, 10);
  367.             }
  368.             mysql_free_result(res);
  369.         }
  370.  
  371.         loadChannels();
  372.     }
  373.  
  374.     #endif
  375.     IRCCreateThread(thr, wwwstats_thr, NULL);
  376.     #ifdef USE_MYSQL
  377.     if(stats_db) IRCCreateThread(mysql_thr, wwwstats_mysql_thr, NULL);
  378.     #endif
  379.  
  380.     return MOD_SUCCESS;
  381. }
  382.  
  383. /* Called when module is unloaded */
  384. MOD_UNLOAD(m_wwwstats)
  385. {
  386.     time_t act_time;
  387.     chanStats *next;
  388.  
  389.     pthread_cancel(thr);
  390.     pthread_join(thr, NULL);
  391.     #ifdef USE_MYSQL
  392.     if(stats_db){
  393.         pthread_cancel(mysql_thr);
  394.         pthread_join(mysql_thr, NULL);
  395.     }
  396.     #endif
  397.  
  398.     close(stats_socket);
  399.     unlink(stats_addr.sun_path);
  400.  
  401.     act_time = time(NULL);
  402.  
  403.     #ifdef USE_MYSQL
  404.     saveStats(act_time);
  405.     saveChannels(act_time);
  406.     #endif
  407.  
  408. //      for(;chans;chans=chans->next) free(chans);
  409.     for(;chans;chans=next) {
  410.         next=chans->next;
  411.         free(chans);
  412.     }
  413.     #ifdef USE_MYSQL
  414.     if(stats_db) mysql_close(stats_db);
  415.     if(mysql_user) free(mysql_user);
  416.     if(mysql_pass) free(mysql_pass);
  417.     if(mysql_db) free(mysql_db);
  418.     if(mysql_host) free(mysql_host);
  419.     #endif
  420.  
  421.     if(socket_path) free(socket_path);
  422.    
  423.     return MOD_SUCCESS;
  424. }
  425.  
  426. char* wwwstats_msg(aClient *sptr, aChannel *chptr, char *msg, int notice) {
  427.     chanStats *lp;
  428.     #ifdef USE_MYSQL
  429.     char name[2*CHANNELLEN+1];
  430.     char buf[2048];
  431.     MYSQL_RES *res;
  432.     MYSQL_ROW row;
  433.     #endif
  434.     int c_msg;
  435.     counter++;
  436.     for(lp=chans; lp; lp=lp->next) if(lp->chan==chptr) break;
  437.  
  438.     if(lp) lp->msg++;
  439.     else {
  440.         c_msg = 1;
  441.         #ifdef USE_MYSQL
  442.         if(use_mysql){
  443.             tmp_escape(name, chptr->chname);
  444.             mysql_query_sprintf(buf, "SELECT MAX(messages) FROM chanlist WHERE name='%s' GROUP BY name", name);
  445.             res = mysql_use_result(stats_db);
  446.             if(!res) send_mysql_error(); else {
  447.                 if((row = mysql_fetch_row(res)))
  448.                     if(row[0]) c_msg = strtoul(row[0], NULL, 10);
  449.                 mysql_free_result(res);
  450.             }
  451.         }
  452.         #endif
  453. //      sendto_realops("wwwstats: added channel %s, %d msgs", name, c_msg);
  454.         appendChannel(chptr, c_msg);
  455.     }
  456.     return msg;
  457. }
  458.  
  459. void wwwstats_thr(void *d) {
  460.     char buf[2000];
  461.     char topic[2*TOPICLEN+1];
  462.     char name[2*CHANNELLEN+1];
  463.     int i;
  464.     int sock;
  465.     channelInfo chinfo;
  466.     asendInfo asinfo;
  467.     struct sockaddr_un cli_addr;
  468.  
  469.     socklen_t slen = sizeof(cli_addr);
  470.  
  471.     asinfo.buf = send_buf;
  472.     asinfo.bufsize = sizeof(send_buf);
  473.     asinfo.tmpbuf = buf;
  474.  
  475.     aClient *acptr;
  476.  
  477.     while(1) {
  478.         sock = accept(stats_socket, (struct sockaddr*) &cli_addr, &slen);
  479.         if(sock<0) break;
  480.         asinfo.sock = sock;
  481.         send_buf[0] = 0;
  482.         append_int_param(&asinfo, "clients", IRCstats.clients);
  483.         append_int_param(&asinfo, "channels", IRCstats.channels);
  484.         append_int_param(&asinfo, "operators", IRCstats.operators);
  485.         append_int_param(&asinfo, "servers", IRCstats.servers);
  486.         append_int_param(&asinfo, "messages", counter);
  487.  
  488.         i=0;
  489.  
  490.         list_for_each_entry(acptr, &global_server_list, client_node){
  491.             if (IsULine(acptr) && HIDE_ULINES)
  492.                 continue;
  493.             asend_sprintf(&asinfo, "$stats['serv'][%d]['name'] = '%s';\n", i, acptr->name);
  494.             asend_sprintf(&asinfo, "$stats['serv'][%d]['users'] = %ld;\n", i, acptr->serv->users);
  495.             i++;
  496.         }
  497.  
  498.  
  499.         IRCMutexLock(chans_mutex);
  500.         if(!chans_mutex_ai) removeExpiredChannels();
  501.         chans_mutex_ai++;
  502.         IRCMutexUnlock(chans_mutex);
  503.         chinfo.chan = NULL;
  504.  
  505.         i=0;
  506.         while(getChannelInfo(&chinfo)) {
  507.             if(!PubChannel(chinfo.chan)) continue;
  508.             asend_sprintf(&asinfo, "$stats['chan'][%d]['name'] = '%s';\n", i, tmp_escape(name, chinfo.chan->chname));
  509.             asend_sprintf(&asinfo, "$stats['chan'][%d]['users'] = %d;\n", i, chinfo.chan->users);
  510.             asend_sprintf(&asinfo, "$stats['chan'][%d]['messages'] = %d;\n", i, chinfo.messages);
  511.             if(chinfo.chan->topic) asend_sprintf(&asinfo, "$stats['chan'][%d]['topic'] = '%s';\n", i, tmp_escape(topic, chinfo.chan->topic));
  512.             i++;
  513.         }
  514.  
  515.         IRCMutexLock(chans_mutex);
  516.         chans_mutex_ai--;
  517.         IRCMutexUnlock(chans_mutex);
  518.  
  519.         if(send_buf[0]) {
  520.             send(sock, send_buf, strlen(send_buf), 0);
  521.             send_buf[0] = 0;
  522.         }
  523.  
  524.         close(sock);
  525.     }
  526. }
  527.  
  528. #ifdef USE_MYSQL
  529.  
  530. void wwwstats_mysql_thr(void *d) {
  531.     time_t prev_time;
  532.     time_t act_time;
  533.     prev_time = 0;
  534.  
  535.     while(1) {
  536.         act_time = time(NULL);
  537.         if((act_time-prev_time)>=mysql_interval) {
  538.             saveStats(act_time);
  539.  
  540.             IRCMutexLock(chans_mutex);
  541.             if(!chans_mutex_ai) removeExpiredChannels();
  542.             chans_mutex_ai++;
  543.             IRCMutexUnlock(chans_mutex);
  544.  
  545.             saveChannels(act_time);
  546.  
  547.             IRCMutexLock(chans_mutex);
  548.             chans_mutex_ai--;
  549.             IRCMutexUnlock(chans_mutex);
  550.  
  551.             prev_time = act_time;
  552.         }
  553.         sleep(10);
  554.     }
  555. }
  556.  
  557. void saveChannels(time_t act_time) {
  558.     char buf[2*(TOPICLEN+CHANNELLEN)+256];
  559.     char name[2*CHANNELLEN+1];
  560.     char topic[2*TOPICLEN+1];
  561.     channelInfo chinfo;
  562.    
  563.     if(!use_mysql) return;
  564.  
  565.     chinfo.chan = NULL;
  566.     while(getChannelInfo(&chinfo)) {
  567.         tmp_escape(name, chinfo.chan->chname);
  568.         if(chinfo.chan->topic) tmp_escape(topic, chinfo.chan->topic);
  569.         else topic[0] = 0;
  570.         mysql_query_sprintf(buf, "INSERT IGNORE INTO chanlist VALUES (NULL, %d, '%s', '%s', %d, %d)", act_time, name, topic, chinfo.chan->users, chinfo.messages);
  571.     }
  572. }
  573.  
  574. void loadChannels(void){ // channel will be added automatically when a message comes
  575.     char buf[2*CHANNELLEN+20];
  576.     char name[2*CHANNELLEN+1];
  577.     aChannel *ch;
  578.     MYSQL_RES *res;
  579.     MYSQL_ROW row;
  580.    
  581.     channelInfo chinfo;
  582.     unsigned long cnt;
  583.    
  584.     if(!use_mysql) return;
  585.    
  586.     chinfo.chan = NULL;
  587.     while(getChannelInfo(&chinfo)) {
  588.         ch = chinfo.chan;
  589.         tmp_escape(name, chinfo.chan->chname);
  590.         mysql_query_sprintf(buf, "SELECT MAX(messages) FROM chanlist WHERE name = '%s'", name);
  591.         res = mysql_use_result(stats_db);
  592.         if(res && (row = mysql_fetch_row(res))){
  593.             cnt = 0;
  594.             if(row[0]) cnt = strtoul(row[0], NULL, 10);
  595.             if(cnt > 0){
  596.                 appendChannel(ch, cnt);
  597. //              sendto_realops("wwwstats: added from db: %s, %lu msgs", ch->chname, cnt);
  598.             }
  599.             mysql_free_result(res);
  600.         }
  601.     }
  602. }
  603.  
  604. void saveStats(time_t act_time) {
  605.     char buf[512];
  606.    
  607.     if(!use_mysql) return;
  608.    
  609.     mysql_query_sprintf(buf, "INSERT IGNORE INTO stat VALUES (NULL, %d, %d, %d, %d, %d)", act_time, IRCstats.clients, IRCstats.servers, counter, IRCstats.channels);
  610. }
  611.  
  612. void send_mysql_error(void){
  613.     sendto_realops("wwwstats: mysql error: %s",mysql_error(stats_db));
  614. }
  615. #endif
  616.  
  617.  
  618. void appendChannel(aChannel *ch, int messages) {
  619.     chanStats *lp;
  620.  
  621.     lp = malloc(sizeof(chanStats));
  622.     lp->chan = ch;
  623.     lp->msg = messages;
  624.     strcpy(lp->chname, ch->chname);
  625.     lp->next = NULL;
  626.     if(chans_last) chans_last->next = lp;
  627.     chans_last = lp;
  628.     if(!chans) chans = lp;
  629. }
  630.  
  631. void removeExpiredChannels() {
  632.     int hashnum;
  633.     aChannel *c;
  634.     chanStats *lp, *lpprev, *lpnext;
  635.    
  636.     for(lp=chans; lp; lp=lp->next) lp->exists = 0;
  637.  
  638.     for(hashnum=0; hashnum<CH_MAX; hashnum++) {
  639.         c = (aChannel*) hash_get_chan_bucket(hashnum);
  640.         while(c) {
  641.             for(lp=chans; lp; lp=lp->next) if(lp->chan==c) break;
  642.             if(lp) lp->exists = 1;
  643.             c = c->hnextch;
  644.         }
  645.     }
  646.  
  647.     lpprev = NULL;
  648.     lpnext = NULL;
  649.     for(lp=chans; lp; lp=lpnext) {
  650.         if(!lp->exists) {
  651. //          sendto_realops("wwwstats: deleted channel %s", lp->chname);
  652.             if(lpprev) lpprev->next = lp->next;
  653.                 else chans = lp->next;
  654.             if(!lp->next) chans_last = lpprev;
  655.             lpnext = lp->next;
  656.             free(lp);
  657.             continue;
  658.         }
  659.         lpnext = lp->next;
  660.         lpprev = lp;
  661.     }
  662. }
  663.  
  664. aChannel *getChanByName(char *name) {
  665.     channelInfo chinfo;
  666.  
  667.     chinfo.chan = NULL;
  668.     while(getChannelInfo(&chinfo)) {
  669.         if(strcmp(chinfo.chan->chname, name)==0) return chinfo.chan;
  670.     }
  671.     return NULL;
  672. }
  673.  
  674.  
  675.  
  676. int getChannelInfo(channelInfo *prev) {
  677.     int hashnum = 0;
  678.     int messages = 0;
  679.     aChannel *c = NULL;
  680.     chanStats *lp;
  681.  
  682.     if(prev->chan) {
  683.         hashnum = prev->hashnum;
  684.         c = prev->chan->hnextch;
  685.         if(!c) hashnum++;
  686.     }
  687.  
  688.     if(!c) for(; hashnum<CH_MAX; hashnum++) {
  689.         c = (aChannel*) hash_get_chan_bucket(hashnum);
  690.         if(c) break;
  691.     }
  692.     if(!c) return 0;
  693.  
  694.     for(lp=chans; lp; lp=lp->next) if(lp->chan==c) break;
  695.     if(lp) messages = lp->msg;
  696.  
  697.     prev->hashnum = hashnum;
  698.     prev->chan = c;
  699.     prev->messages = messages;
  700.     return 1;
  701. }
  702.  
  703.  
  704.  
  705. #ifdef USE_MYSQL
  706. int mysql_query_sprintf(char *buf, char *fmt, ...) {
  707.     int ret;
  708.     va_list list;
  709.     va_start(list, fmt);
  710.     vsprintf(buf, fmt, list);
  711.     va_end(list);
  712.     ret = mysql_query(stats_db, buf);
  713.     if(ret){
  714.           sendto_realops("wwwstats: mysql query error: %s",mysql_error(stats_db));
  715.     }
  716.     return ret;
  717. }
  718.  
  719. #endif
  720.  
  721. void asend_sprintf(asendInfo *info, char *fmt, ...) {
  722.     int bl, tl;
  723.     va_list list;
  724.     va_start(list, fmt);
  725.     vsprintf(info->tmpbuf, fmt, list);
  726.     bl = strlen(info->tmpbuf);
  727.     tl = strlen(info->buf);
  728.     if((bl+tl)>=info->bufsize) {
  729.         send(info->sock, info->buf, tl, 0);
  730.         info->buf[0] = 0;
  731.     }
  732.  
  733.     strcat(info->buf, info->tmpbuf);
  734.     va_end(list);
  735. }
  736.  
  737. void append_int_param(asendInfo *info, char *param, int value) {
  738.     asend_sprintf(info, "$stats['%s'] = %d;\n", param, value);
  739. }
  740.  
  741. char *tmp_escape(char *d, const char *a) {
  742.     int diff;
  743.     int i;
  744.     diff = 0;
  745.     for(i=0; a[i]; i++) {
  746.         if((a[i]=='\'') || (a[i]=='\\')) {
  747.             d[diff+i] = '\\';
  748.             diff++;
  749.         }
  750.         d[diff+i] = a[i];
  751.     }
  752.     d[diff+i] = 0;
  753.     return d;
  754. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement