Merge branch 'development'
[NeonServV5.git] / src / modules / stats.mod / module.c
1 /* module.c - NeonServ v5.6
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17 #include "../module.h"
18 #include "../../timeq.h"
19 #include "../../ConfigParser.h"
20 #include "../../mysqlConn.h"
21 #include "../../ClientSocket.h"
22 #include "../../UserNode.h"
23
24 #define STATS_UPDATE_SECONDS  1800
25 #define STATS_UPDATE_HOST     "neonserv.krypton-bouncer.de"
26 #define STATS_UPDATE_PORT     1675
27 #define STATS_IDENTIFIER_LEN  10
28 #define STATS_IDENTIFIER_POOL "abcdefghijklmnopqrstuvwxyz0123456789#*+-_.:;,!ยง$%&/()=?[]{}<>|@"
29 #define STATS_IDENTIFIER_POOL_SIZE 63
30
31 static TIMEQ_CALLBACK(stats_timer_callback);
32
33 static int module_initialize() {
34     return 0;
35 }
36
37 static void module_start(int type) {
38     if(!timeq_name_exists("stats"))
39         timeq_add_name("stats", 60, module_id, stats_timer_callback, NULL);
40 }
41
42 static void module_stop(int type) {
43     timeq_del_name("stats");
44 }
45
46 static char *get_identifier() {
47     MYSQL_RES *res;
48     MYSQL_ROW row;
49     printf_mysql_query("SELECT `value` FROM `settings` WHERE `name` = 'identifier'");
50     res = mysql_use();
51     if(!(row = mysql_fetch_row(res))) {
52         srand(time(NULL));
53         char identifier[STATS_IDENTIFIER_LEN+1];
54         int i;
55         char *pool = STATS_IDENTIFIER_POOL;
56         for(i = 0; i < STATS_IDENTIFIER_LEN; i++) {
57             identifier[i] = pool[(rand() % STATS_IDENTIFIER_POOL_SIZE)];
58         }
59         identifier[i] = 0;
60         printf_mysql_query("INSERT INTO `settings` (`name`, `value`) VALUES ('identifier', '%s')", escape_string(identifier));
61         printf_mysql_query("SELECT `value` FROM `settings` WHERE `name` = 'identifier'");
62         res = mysql_use();
63         row = mysql_fetch_row(res);
64         if(!row) return NULL;
65     }
66     if(strlen(row[0]) < 10) return NULL;
67     return row[0];
68 }
69
70 static TIMEQ_CALLBACK(stats_timer_callback) {
71     timeq_add_name("stats", STATS_UPDATE_SECONDS, module_id, stats_timer_callback, NULL);
72     char tmp[200];
73     char pkgbuf[1024];
74     int pkgpos = 0;
75     char *modname = get_module_name(module_id);
76     char *bot_identifier = get_identifier();
77     if(!bot_identifier) return;
78     //build update package
79     pkgpos += sprintf(pkgbuf + pkgpos, "nsupdate\n%s\n%s.%d %s\n", bot_identifier, NEONSERV_VERSION, get_patchlevel(), (strcmp(get_revision(), "") ? get_revision() : "-"));
80     sprintf(tmp, "modules/%s/hide_networkname", modname);
81     if(get_int_field(tmp))
82         pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
83     else {
84         struct ClientSocket *bot;
85         for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
86             if(bot->network_name) break;
87         }
88         if(bot)
89             pkgpos += sprintf(pkgbuf + pkgpos, "%s\n", bot->network_name);
90         else
91             pkgpos += sprintf(pkgbuf + pkgpos, "?\n");
92     }
93     sprintf(tmp, "modules/%s/hide_botnick", modname);
94     if(get_int_field(tmp))
95         pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
96     else {
97         sprintf(tmp, "modules/%s/use_bot", modname);
98         char *botname = get_string_field(tmp);
99         struct ClientSocket *bot, *bot1 = NULL, *bot2 = NULL, *bot3 = NULL, *bot4 = NULL;
100         for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
101             if(botname && !stricmp(bot->nick, botname))
102                 bot1 = bot;
103             else if(bot->botid == 1 && (bot->flags & SOCKET_FLAG_PREFERRED))
104                 bot2 = bot;
105             else if((bot->flags & SOCKET_FLAG_PREFERRED))
106                 bot3 = bot;
107             else
108                 bot4 = bot;
109         }
110         if(bot1)
111             bot = bot1;
112         else if(bot2)
113             bot = bot2;
114         else if(bot3)
115             bot = bot3;
116         else
117             bot = bot4;
118         if(bot) {
119             pkgpos += sprintf(pkgbuf + pkgpos, "%s!%s@%s %d\n", (bot->user ? bot->user->nick : "*"), (bot->user ? bot->user->ident : "*"), (bot->host ? bot->host : "*"), bot->port);
120         } else
121             pkgpos += sprintf(pkgbuf + pkgpos, "?\n");
122     }
123     sprintf(tmp, "modules/%s/hide_chancount", modname);
124     if(get_int_field(tmp))
125         pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
126     else {
127         int channel_count = getChannelCount();
128         pkgpos += sprintf(pkgbuf + pkgpos, "%d\n", channel_count);
129     }
130     sprintf(tmp, "modules/%s/hide_usercount", modname);
131     if(get_int_field(tmp))
132         pkgpos += sprintf(pkgbuf + pkgpos, "*\n");
133     else {
134         int user_count = getUserCount();
135         int chanuser_count = getChanUserCount();
136         pkgpos += sprintf(pkgbuf + pkgpos, "%d %d\n", user_count, chanuser_count);
137     }
138     pkgpos += sprintf(pkgbuf + pkgpos, "%lu\n", getStartTime());
139     pkgbuf[pkgpos] = 0;
140     //send package
141     #ifndef WIN32
142     struct sockaddr_in si_other;
143     int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
144     if (sock == -1) return;
145     memset((char *) &si_other, 0, sizeof(si_other));
146     si_other.sin_family = AF_INET;
147     si_other.sin_port = htons(STATS_UPDATE_PORT);
148     if (!inet_aton(STATS_UPDATE_HOST, &si_other.sin_addr)) {
149         struct hostent *host = gethostbyname(STATS_UPDATE_HOST);
150         if (!host) return;
151         si_other.sin_addr = *(struct in_addr*)host->h_addr;
152     }
153     sendto(sock, pkgbuf, pkgpos, 0, &si_other, sizeof(si_other));
154     #else
155     struct sockaddr_in si_other;
156     int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
157     if (sock == -1) return;
158     si_other.sin_family = AF_INET;
159     si_other.sin_port = htons(STATS_UPDATE_PORT);
160     si_other.sin_addr.s_addr = inet_addr(STATS_UPDATE_HOST);
161     if (si_other.sin_addr.s_addr == INADDR_NONE) {
162         struct hostent *host = gethostbyname(STATS_UPDATE_HOST);
163         if(!host) return;
164         memcpy(&(si_other.sin_addr), host->h_addr_list[0], 4);
165     }
166     sendto(sock, pkgbuf, pkgpos, 0, (struct sockaddr *) &si_other, sizeof(si_other));
167     #endif
168     close(sock);
169 }
170
171 MODULE_HEADER(module_initialize, module_start, module_stop);