rearranged NeonServ code to be modular
[NeonServV5.git] / src / modules.c
1 /* modules.c - NeonServ v5.3
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 "modules.h"
18
19 /* 000-011 */ #include "main.h"
20 /* 012     */ #include "BanNode.h"
21 /* 013-019 */ #include "bots.h"
22 /* 020-025 */ #include "ChanNode.h"
23 /* 026-029 */ #include "ChanUser.h"
24 /* 030-036 */ #include "ClientSocket.h"
25 /* 037-038 */ #include "ConfigParser.h"
26 /* 039-048 */ #include "DBHelper.h"
27 /* 049     */ #include "EventLogger.h"
28 /* 050     */ #include "HandleInfoHandler.h"
29 /* 051-088 */ #include "IRCEvents.h"
30 /* 089-091 */ #include "IRCParser.h"
31 /* 092-098 */ #include "lang.h"
32 #ifdef ENABLE_MEMORY_DEBUG
33 /* 099-102 */ #include "memoryDebug.h"
34 #endif
35 /* 103-106 */ #include "memoryInfo.h"
36 /* 107-125 */ #include "modcmd.h"
37 /* 126-136 */ #include "ModeNode.h"
38 /* 137-142 */ #include "mysqlConn.h"
39 /* 143-149 */ #include "timeq.h"
40 /* 150-169 */ #include "tools.h"
41 /* 170-178 */ #include "UserNode.h"
42 /* 179     */ #include "version.h"
43 /* 180-182 */ #include "WHOHandler.h"
44
45 void **global_functions = {
46 /* 000 */ getStartTime,
47 /* 001 */ getRunningThreads,
48 /* 002 */ exit_daemon,
49 /* 003 */ stricmp,
50 /* 004 */ stricmplen,
51 /* 005 */ restart_process,
52 /* 006 */ cleanup,
53 /* 007 */ restart_bot,
54 /* 008 */ stop_bot,
55 /* 009 */ reload_config,
56 /* 010 */ putlog,
57 #ifdef HAVE_THREADS
58 /* 011 */ getCurrentThreadID,
59 #else
60 /* 011 */ NULL,
61 #endif
62 /* 012 */ getMatchingChannelBan,
63 /* 013 */ getChannelBot,
64 /* 014 */ requestOp,
65 /* 015 */ channel_ban_timeout,
66 /* 016 */ general_event_privctcp,
67 /* 017 */ set_bot_alias,
68 /* 018 */ resolve_botid,
69 /* 019 */ resolve_botalias,
70 /* 020 */ is_valid_chan,
71 /* 021 */ getAllChans,
72 /* 022 */ getChanByName,
73 /* 023 */ getChannelCount,
74 /* 024 */ getChanUserCount,
75 /* 025 */ getChanBanCount,
76 /* 026 */ isUserOnChan,
77 /* 027 */ getChanUser,
78 /* 028 */ getChannelUsers,
79 /* 029 */ getUserChannels,
80 /* 030 */ create_socket,
81 /* 031 */ connect_socket,
82 /* 032 */ close_socket,
83 /* 033 */ disconnect_socket,
84 /* 034 */ write_socket,
85 /* 035 */ putsock,
86 /* 036 */ getBots,
87 /* 037 */ get_int_field,
88 /* 038 */ get_string_field,
89 /* 039 */ _loadUserSettings,
90 /* 040 */ isGodMode,
91 /* 041 */ getChanDefault,
92 /* 042 */ getChannelAccess,
93 /* 043 */ checkChannelAccess,
94 /* 044 */ _loadChannelSettings,
95 /* 045 */ isUserProtected,
96 /* 046 */ getBanAffectingMask,
97 /* 047 */ renameAccount,
98 /* 048 */ deleteUser,
99 /* 049 */ logEvent,
100 /* 050 */ lookup_authname,
101 /* 051 */ bind_join,
102 /* 052 */ unbind_join,
103 /* 053 */ bind_nick,
104 /* 054 */ unbind_nick,
105 /* 055 */ bind_part,
106 /* 056 */ unbind_part,
107 /* 057 */ bind_quit,
108 /* 058 */ unbind_quit,
109 /* 059 */ bind_kick,
110 /* 060 */ unbind_kick,
111 /* 061 */ bind_topic,
112 /* 062 */ unbind_topic,
113 /* 063 */ bind_mode,
114 /* 064 */ unbind_mode,
115 /* 065 */ bind_chanmsg,
116 /* 066 */ unbind_chanmsg,
117 /* 067 */ bind_privmsg,
118 /* 068 */ unbind_privmsg,
119 /* 069 */ bind_channotice,
120 /* 070 */ unbind_channotice,
121 /* 071 */ bind_privnotice,
122 /* 072 */ unbind_privnotice,
123 /* 073 */ bind_chanctcp,
124 /* 074 */ unbind_chanctcp,
125 /* 075 */ bind_privctcp,
126 /* 076 */ unbind_privctcp,
127 /* 077 */ bind_invite,
128 /* 078 */ unbind_invite,
129 /* 079 */ bind_raw,
130 /* 080 */ unbind_raw,
131 /* 081 */ bind_bot_ready,
132 /* 082 */ unbind_bot_ready,
133 /* 083 */ bind_registered,
134 /* 084 */ unbind_registered,
135 /* 085 */ bind_freeuser,
136 /* 086 */ unbind_freeuser,
137 /* 087 */ bind_freechan,
138 /* 088 */ unbind_freechan,
139 /* 089 */ reply,
140 /* 090 */ merge_argv,
141 /* 091 */ merge_argv_char,
142 /* 092 */ get_language_by_tag,
143 /* 093 */ get_language_by_name,
144 /* 094 */ get_default_language,
145 /* 095 */ load_language,
146 /* 096 */ register_default_language_table,
147 /* 097 */ get_language_string,
148 /* 098 */ build_language_string,
149 #ifdef ENABLE_MEMORY_DEBUG
150 /* 099 */ xmalloc,
151 /* 100 */ xcalloc,
152 /* 101 */ xstrdup,
153 /* 102 */ xfree,
154 #else
155 /* 099 */ NULL,
156 /* 100 */ NULL,
157 /* 101 */ NULL,
158 /* 102 */ NULL,
159 #endif
160 /* 103 */ getMemoryInfoFiles,
161 /* 104 */ freeMemoryInfoFiles,
162 /* 105 */ getMemoryInfoLines,
163 /* 106 */ freeMemoryInfoLines,
164 /* 107 */ get_botwise_prefered_bot,
165 /* 108 */ register_command,
166 /* 109 */ set_trigger_callback,
167 /* 110 */ flush_trigger_cache,
168 /* 111 */ changeBotwiseChannelTrigger,
169 /* 112 */ bind_botwise_cmd_to_function,
170 /* 113 */ bind_botwise_cmd_to_command,
171 /* 114 */ unbind_botwise_cmd,
172 /* 115 */ unbind_botwise_allcmd,
173 /* 116 */ bind_botwise_set_parameters,
174 /* 117 */ bind_botwise_set_global_access,
175 /* 118 */ bind_botwise_set_channel_access,
176 /* 119 */ bind_botwise_set_bind_flags,
177 /* 120 */ find_botwise_cmd_binding,
178 /* 121 */ bind_botwise_unbound_required_functions,
179 /* 122 */ find_cmd_function,
180 /* 123 */ getTextBot,
181 /* 124 */ register_command_alias,
182 /* 125 */ getAllBinds,
183 /* 126 */ createModeNode,
184 /* 127 */ freeModeNode,
185 /* 128 */ isModeSet,
186 /* 129 */ isModeAffected,
187 /* 130 */ getModeValue,
188 /* 131 */ getModeType,
189 /* 132 */ parseModes,
190 /* 133 */ parseModeString,
191 /* 134 */ parseMode,
192 /* 135 */ getModeString,
193 /* 136 */ getFullModeString,
194 /* 137 */ mysql_use,
195 /* 138 */ mysql_free,
196 /* 139 */ printf_mysql_query,
197 /* 140 */ printf_long_mysql_query,
198 /* 141 */ escape_string,
199 /* 142 */ get_mysql_conn,
200 /* 143 */ timeq_add,
201 /* 144 */ timeq_uadd,
202 /* 145 */ timeq_add_name,
203 /* 146 */ timeq_uadd_name,
204 /* 147 */ timeq_del,
205 /* 148 */ timeq_del_name,
206 /* 149 */ timeq_name_exists,
207 /* 150 */ match,
208 /* 151 */ table_init,
209 /* 152 */ table_add,
210 /* 153 */ table_change,
211 /* 154 */ table_change_field,
212 /* 155 */ table_set_bold,
213 /* 156 */ table_end,
214 /* 157 */ table_free,
215 /* 158 */ timeToStr,
216 /* 159 */ strToTime,
217 /* 160 */ initModeBuffer,
218 /* 161 */ modeBufferSet,
219 /* 162 */ flushModeBuffer,
220 /* 163 */ freeModeBuffer,
221 /* 164 */ is_ircmask,
222 /* 165 */ generate_banmask,
223 /* 166 */ make_banmask,
224 /* 167 */ isFakeHost,
225 /* 168 */ mask_match,
226 /* 169 */ crc32,
227 /* 170 */ is_valid_nick,
228 /* 171 */ getUserByNick,
229 /* 172 */ getUserByMask,
230 /* 173 */ countUsersWithHost,
231 /* 174 */ getAuthFakehost,
232 /* 175 */ searchUserByNick,
233 /* 176 */ getAllUsers,
234 /* 177 */ getUsersWithAuth,
235 /* 178 */ getUserCount,
236 /* 179 */ get_userlist,
237 /* 180 */ _get_userlist_with_invisible,
238 /* 181 */ get_userauth,
239 /* 182 */ &compilation,
240 /* 183 */ &creation,
241 /* 184 */ &revision,
242 /* 185 */ &codelines,
243 /* 186 */ &patchlevel
244 };
245
246 #define MODINFO_STATE_STARTED 0x01
247
248 struct ModuleInfo {
249     char *name;
250     int module_id;
251     #ifndef WIN32
252     void *module;
253     #else
254     HMODULE module;
255     #endif
256     int state;
257     void *startfunc;
258     void *loopfunc;
259     void *stopfunc;
260     struct ModuleInfo *next;
261 }
262
263 static int module_id_counter = 1;
264 static struct ModuleInfo *modules = NULL;
265
266 static void unregister_module_hooks(int module_id);
267
268 int loadModule(char *name) {
269     char fname[256];
270     #ifndef WIN32
271     sprintf(fname, "%s.so", name);
272     void* module = dlopen(fname, RTLD_LAZY);
273     if(!module) {
274         putlog(LOGLEVEL_ERROR, "Error loading module '%s': %s not found.", name, fname);
275         return 0;
276     }
277     void* initfunc = dlsym(module, "init_module");
278     void* startfunc = dlsym(module, "start_module");
279     void* loopfunc = dlsym(module, "loop_module");
280     void* stopfunc = dlsym(module, "stop_module");
281     void* modversion = dlsym(module, "modversion");
282     #else
283     sprintf(fname, "%s.dll", name);
284     HMODULE module = LoadLibrary(fname);
285     if(!module) {
286         putlog(LOGLEVEL_ERROR, "Error loading module '%s': %s not found.", name, fname);
287         return 0;
288     }
289     FARPROC initfunc = GetProcAddress(module, "init_module");
290     FARPROC startfunc = GetProcAddress(module, "start_module");
291     FARPROC loopfunc = GetProcAddress(module, "loop_module");
292     FARPROC stopfunc = GetProcAddress(module, "stop_module");
293     FARPROC modversion = GetProcAddress(module, "modversion");
294     #endif
295     if(!startfunc || !loopfunc || !stopfunc || !modversion) {
296         putlog(LOGLEVEL_ERROR, "Error loading module '%s': required symbols not found.", name);
297         return 0;
298     }
299     int version = ((int (*)(void)) modversion)();
300     if(version != MODULE_VERSION) {
301         putlog(LOGLEVEL_ERROR, "Error loading module '%s': version mismatch ('%d' main code, '%d' module)", name, MODULE_VERSION, version);
302         return 0;
303     }
304     //start module
305     int errid;
306     int module_id = module_id_counter++;
307     if((errid = ((int (*)(void **, int)) initfunc)(global_functions, module_id))) {
308         putlog(LOGLEVEL_ERROR, "Error loading module '%s': module reported error (errid: %d)", name, errid);
309         return 0;
310     }
311     struct ModuleInfo *modinfo = malloc(sizeof(*modinfo));
312     if(!modinfo) {
313         unregister_module_hooks(module_id);
314         return 0;
315     }
316     modinfo->name = strdup(name);
317     modinfo->module_id = module_id;
318     modinfo->module = module;
319     modinfo->startfunc = startfunc;
320     modinfo->loopfunc = loopfunc;
321     modinfo->stopfunc = stopfunc;
322     modinfo->next = modules;
323     modules = modinfo;
324     return 1;
325 }
326
327 #ifndef WIN32
328 static void closemodule(void *module) {
329     dlclose(module);
330 }
331 #else
332 static void closemodule(HMODULE module) {
333     FreeLibrary(module);
334 }
335 #endif
336
337 int reload_module(char *name) {
338     struct ModuleInfo *old_modinfo, *old_prev = NULL;
339     for(old_modinfo = modules; old_modinfo; old_modinfo = old_modinfo->next) {
340         if(old_prev)
341             old_prev->next = old_modinfo->next;
342         else
343             modules = old_modinfo->next;
344         unregister_module_hooks(old_modinfo->module_id);
345         ((void (*)(void)) old_modinfo->stopfunc)(MODSTATE_RELOAD);
346         closemodule(old_modinfo->module);
347         free(old_modinfo->name);
348         free(old_modinfo);
349         break;
350     } else
351         old_prev = old_modinfo;
352     if(!loadModule(name)) return 0;
353     struct ModuleInfo *modinfo;
354     for(modinfo = modules; modinfo; modinfo = modinfo->next) {
355         if(!(modinfo->state & MODINFO_STATE_STARTED)) {
356             modinfo->state |= MODINFO_STATE_STARTED;
357             ((void (*)(void)) modinfo->startfunc)(MODSTATE_STARTSTOP);
358         } else
359             ((void (*)(void)) modinfo->startfunc)(MODSTATE_REBIND);
360     }
361 }
362
363 void start_modules() {
364     struct ModuleInfo *modinfo;
365     for(modinfo = modules; modinfo; modinfo = modinfo->next) {
366         if(!(modinfo->state & MODINFO_STATE_STARTED)) {
367             modinfo->state |= MODINFO_STATE_STARTED;
368             ((void (*)(void)) modinfo->startfunc)(MODSTATE_STARTSTOP);
369         }
370     }
371 }
372
373 void loop_modules() {
374     struct ModuleInfo *modinfo;
375     for(modinfo = modules; modinfo; modinfo = modinfo->next) {
376         ((void (*)(void)) modinfo->loopfunc)();
377     }
378 }
379
380 void stop_modules() {
381     struct ModuleInfo *modinfo, *next;
382     for(modinfo = modules; modinfo; modinfo = next) {
383         next = modinfo->next;
384         unregister_module_hooks(modinfo->module_id);
385         ((void (*)(int)) modinfo->stopfunc)(MODSTATE_STARTSTOP);
386         closemodule(modinfo->module);
387         free(modinfo->name);
388         free(modinfo);
389     }
390     modules = NULL;
391 }
392
393 static void unregister_module_hooks(int module_id) {
394     unregister_module_commands(module_id);
395     unregister_module_events(module_id);
396     unregister_module_timers(module_id);
397 }
398
399 int module_loaded(int module_id) {
400     if(!module_id) return 1;
401     struct ModuleInfo *modinfo;
402     for(modinfo = modules; modinfo; modinfo = modinfo->next) {
403         if(modinfo->module_id == module_id)
404             return 1;
405     }
406     return 0;
407 }