Bez tytułu

z k4be, 6 lata temu, napisane w C, wyświetlone 482 razy.
URL https://pastebin.k4be.pl/view/4daecc9c Udostępnij
Pobierz wklejkę lub Pokaż surowy tekst
  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. }
  755.  

odpowiedź "Bez tytułu"

Tutaj możesz odpowiedzieć na wklejkę z góry

captcha