added stats module for neonserv.krypton-bouncer.de stats
[NeonServV5.git] / src / modules / stats.mod / module.c
diff --git a/src/modules/stats.mod/module.c b/src/modules/stats.mod/module.c
new file mode 100644 (file)
index 0000000..ee8a20d
--- /dev/null
@@ -0,0 +1,167 @@
+/* module.c - NeonServ v5.4
+ * Copyright (C) 2011-2012  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#include "../module.h"
+#include "../../timeq.h"
+#include "../../ConfigParser.h"
+#include "../../mysqlConn.h"
+#include "../../ClientSocket.h"
+#include "../../UserNode.h"
+
+#define STATS_UPDATE_SECONDS  1800
+#define STATS_UPDATE_HOST     "neonserv.krypton-bouncer.de"
+#define STATS_UPDATE_PORT     1675
+#define STATS_IDENTIFIER_LEN  10
+#define STATS_IDENTIFIER_POOL "abcdefghijklmnopqrstuvwxyz0123456789#*+-_.:;,!ยง$%&/()=?[]{}<>|@"
+#define STATS_IDENTIFIER_POOL_SIZE 63
+
+static TIMEQ_CALLBACK(stats_timer_callback);
+
+static int module_initialize() {
+    return 0;
+}
+
+static void module_start(int type) {
+    if(!timeq_name_exists("stats"))
+        timeq_add_name("stats", 60, module_id, stats_timer_callback, NULL);
+}
+
+static void module_loop() {
+    
+}
+
+static void module_stop(int type) {
+    timeq_del_name("stats");
+}
+
+static char *get_identifier() {
+    MYSQL_RES *res;
+    MYSQL_ROW row;
+    printf_mysql_query("SELECT `value` FROM `settings` WHERE `name` = 'identifier'");
+    res = mysql_use();
+    if(!(row = mysql_fetch_row(res))) {
+        srand(time(NULL));
+        char identifier[STATS_IDENTIFIER_LEN+1];
+        int i;
+        char *pool = STATS_IDENTIFIER_POOL;
+        for(i = 0; i < STATS_IDENTIFIER_LEN; i++) {
+            identifier[i] = pool[(rand() % STATS_IDENTIFIER_POOL_SIZE)];
+        }
+        identifier[i] = 0;
+        printf_mysql_query("INSERT INTO `settings` (`name`, `value`) VALUES ('identifier', '%s')", escape_string(identifier));
+        printf_mysql_query("SELECT `value` FROM `settings` WHERE `name` = 'identifier'");
+        res = mysql_use();
+        row = mysql_fetch_row(res);
+        if(!row) return NULL;
+    }
+    if(strlen(row[0]) < 10) return NULL;
+    return row[0];
+}
+
+static TIMEQ_CALLBACK(stats_timer_callback) {
+    timeq_add_name("stats", STATS_UPDATE_SECONDS, module_id, stats_timer_callback, NULL);
+    char tmp[200];
+    char pkgbuf[1024];
+    int pkgpos = 0;
+    char *modname = get_module_name(module_id);
+    char *bot_identifier = get_identifier();
+    if(!bot_identifier) return;
+    //build update package
+    pkgpos += sprintf(pkgbuf + pkgpos, "nsupdate\n%s\n%s.%d %s\n", bot_identifier, NEONSERV_VERSION, get_patchlevel(), (strcmp(get_revision(), "") ? get_revision() : "-"));
+    sprintf(tmp, "modules/%s/hide_networkname", modname);
+    if(get_int_field(tmp))
+        pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
+    else {
+        struct ClientSocket *bot;
+        for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+            if(bot->network_name) break;
+        }
+        if(bot)
+            pkgpos += sprintf(pkgbuf + pkgpos, "%s\n", bot->network_name);
+        else
+            pkgpos += sprintf(pkgbuf + pkgpos, "?\n");
+    }
+    sprintf(tmp, "modules/%s/hide_botnick", modname);
+    if(get_int_field(tmp))
+        pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
+    else {
+        struct ClientSocket *bot, *bot1, *bot2, *bot3;
+        for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+            if(bot->botid == 1 && (bot->flags & SOCKET_FLAG_PREFERRED))
+                bot1 = bot;
+            else if((bot->flags & SOCKET_FLAG_PREFERRED))
+                bot2 = bot;
+            else
+                bot3 = bot;
+        }
+        if(bot1)
+            bot = bot1;
+        else if(bot2)
+            bot = bot2;
+        else
+            bot = bot3;
+        if(bot) {
+            pkgpos += sprintf(pkgbuf + pkgpos, "%s!%s@%s %d\n", bot->user->nick, bot->user->ident, bot->host, bot->port);
+        } else
+            pkgpos += sprintf(pkgbuf + pkgpos, "?\n");
+    }
+    sprintf(tmp, "modules/%s/hide_chancount", modname);
+    if(get_int_field(tmp))
+        pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
+    else {
+        int channel_count = getChannelCount();
+        pkgpos += sprintf(pkgbuf + pkgpos, "%d\n", channel_count);
+    }
+    sprintf(tmp, "modules/%s/hide_usercount", modname);
+    if(get_int_field(tmp))
+        pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
+    else {
+        int user_count = getUserCount();
+        int chanuser_count = getChanUserCount();
+        pkgpos += sprintf(pkgbuf + pkgpos, "%d %d\n", user_count, chanuser_count);
+    }
+    pkgbuf[pkgpos] = 0;
+    //send package
+    #ifndef WIN32
+    struct sockaddr_in si_other;
+    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if (sock == -1) return;
+    memset((char *) &si_other, 0, sizeof(si_other));
+    si_other.sin_family = AF_INET;
+    si_other.sin_port = htons(STATS_UPDATE_PORT);
+    if (!inet_aton(STATS_UPDATE_HOST, &si_other.sin_addr)) {
+        struct hostent *host = gethostbyname(STATS_UPDATE_HOST);
+        if (!host) return;
+        si_other.sin_addr = *(struct in_addr*)host->h_addr;
+    }
+    #else
+    struct sockaddr_in si_other;
+    int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if (sock == -1) return;
+    si_other.sin_family = AF_INET;
+    si_other.sin_port = htons(STATS_UPDATE_PORT);
+    si_other.sin_addr.s_addr = inet_addr(client->host);
+    if (si_other.sin_addr.s_addr == INADDR_NONE) {
+        struct hostent *host = gethostbyname(client->host);
+        if(!host) return;
+        memcpy(&(si_other.sin_addr), host->h_addr_list[0], 4);
+    }
+    #endif
+    sendto(sock, pkgbuf, pkgpos, 0, &si_other, sizeof(si_other));
+    close(sock);
+}
+
+MODULE_HEADER(module_initialize, module_start, module_loop, module_stop);