added chanlist to mod-watchdog.c
[srvx.git] / src / mod-watchdog.c
1 /* mod-watchdog.c - Watchdog module for srvx
2  * Copyright 2003-2004 Martijn Smit and srvx Development Team
3  *
4  * This file is part of srvx.
5  *
6  * srvx is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with srvx; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
19  */
20
21 /* Adds new section to srvx.conf:
22  * "modules" {
23  *     "watchdog" {
24  *         "nick" "Watchdog";
25  *         "modes" "+iok"
26  *     };
27  *  };
28  *
29  */
30
31 #include "chanserv.h"
32 #include "conf.h"
33 #include "modcmd.h"
34 #include "saxdb.h"
35 #include "timeq.h"
36
37 #define KEY_BADWORDS "badwords"
38 #define KEY_BADWORD_MASK "mask"
39 #define KEY_BADWORD_TRIGGERED "count"
40 #define KEY_BADWORD_ACTION "action"
41 #define KEY_CHANNELS "channel"
42
43 static const struct message_entry msgtab[] = {
44     { "WDMSG_NULL", "null." },
45     { NULL, NULL }
46 };
47
48 DECLARE_LIST(shitList, struct badword*);
49 DEFINE_LIST(shitList, struct badword*)
50
51 struct badword {
52     char *badword_mask;
53     unsigned int triggered : 29;
54     unsigned int action : 3;
55 };
56
57 struct watchdog_channel {
58     struct chanNode *channel;
59     //struct shitList *shitlist;
60 };
61
62 /* badword.action fields */
63 #define BADACTION_KICK   1
64 #define BADACTION_KILL   2
65 #define BADACTION_GLINE  3
66
67 static struct {
68     const char *nick;
69     const char *modes;
70 } watchdog_conf;
71
72 const char *watchdog_module_deps[] = { NULL };
73 struct userNode *watchdog;
74 static struct module *watchdog_module;
75 static struct service *watchdog_service;
76 static struct shitList shitlist;
77 static dict_t chanlist;
78 static struct log_type *MS_LOG;
79
80
81 static MODCMD_FUNC(cmd_addbad)
82 {
83     //to be continued...
84     return 1;
85 }
86
87 static MODCMD_FUNC(cmd_delbad)
88 {
89     //to be continued...
90     return 1;
91 }
92
93 static MODCMD_FUNC(cmd_editbad)
94 {
95     //to be continued...
96     return 1;
97 }
98
99 static MODCMD_FUNC(cmd_listbad)
100 {
101     //to be continued...
102     return 1;
103 }
104
105 static MODCMD_FUNC(cmd_register)
106 {
107     //to be continued...
108     return 1;
109 }
110
111 static MODCMD_FUNC(cmd_unregister)
112 {
113     //to be continued...
114     return 1;
115 }
116
117 static void
118 watchdog_channel_message(struct userNode *user, struct chanNode *chan, const char *text, struct userNode *bot, unsigned int is_notice)
119 {
120     //to be continued...
121 }
122
123 static struct badword*
124 add_badword(char *badword_mask, unsigned int triggered, unsigned int action)
125 {
126     struct badword *badword;
127
128     badword = calloc(1, sizeof(*badword));
129     if (!badword)
130         return NULL;
131
132     badword->badword_mask = strdup(badword_mask);
133     badword->triggered = triggered;
134     badword->action = action;
135     shitList_append(&shitlist, badword);
136     return badword;
137 }
138
139 static void
140 delete_badword(struct badword *badword)
141 {
142     shitList_remove(&shitlist, badword);
143     free(badword->badword_mask);
144     free(badword);
145 }
146
147 static struct watchdog_channel*
148 add_channel(const char *name)
149 {
150     struct watchdog_channel *wc;
151
152     wc = calloc(1, sizeof(*wc));
153     if (!wc)
154         return NULL;
155
156     wc->channel = AddChannel(name, now, NULL, NULL);
157     AddChannelUser(watchdog, wc->channel)->modes |= MODE_CHANOP;
158     dict_insert(chanlist, wc->channel->name, wc);
159     return wc;
160 }
161
162 static void
163 free_chanlist_entry(void *data)
164 {
165     struct watchdog_channel *wc = data;
166     
167     free(wc);
168 }
169
170 static void
171 watchdog_conf_read(void)
172 {
173     dict_t conf_node;
174     const char *str;
175
176     str = "modules/watchdog";
177     if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
178         log_module(MS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
179         return;
180     }
181
182     str = database_get_data(conf_node, "nick", RECDB_QSTRING);
183     if(watchdog_conf.nick && strcmp(watchdog_conf.nick, str)) {
184         //nick changed
185     }
186     watchdog_conf.nick = str;
187     
188     str = database_get_data(conf_node, "modes", RECDB_QSTRING);
189     watchdog_conf.modes = (str ? str : NULL);
190 }
191
192 static int
193 watchdog_saxdb_read_shitlist(const char *name, void *data, UNUSED_ARG(void *extra))
194 {
195     struct record_data *rd = data;
196     char *badword;
197     char *triggered, *action;
198
199      if (rd->type == RECDB_OBJECT) {
200         dict_t obj = GET_RECORD_OBJECT(rd);
201         /* new style structure */
202         badword = database_get_data(obj, KEY_BADWORD_MASK, RECDB_QSTRING);
203         triggered = database_get_data(obj, KEY_BADWORD_TRIGGERED, RECDB_QSTRING);
204         action = database_get_data(obj, KEY_BADWORD_ACTION, RECDB_QSTRING);
205
206         add_badword(badword, strtoul(triggered, NULL, 0), strtoul(action, NULL, 0));
207         return 1;
208     } else
209         return 0;
210 }
211
212 static int
213 watchdog_saxdb_read_chanlist(const char *name, void *data, UNUSED_ARG(void *extra))
214 {
215     struct record_data *rd = data;
216
217      if (rd->type == RECDB_OBJECT) {
218         dict_t obj = GET_RECORD_OBJECT(rd);
219         /* nothing in here, yet */
220
221         add_channel(name);
222         return 1;
223     } else
224         return 0;
225 }
226
227 static int
228 watchdog_saxdb_read(struct dict *db)
229 {
230     struct dict *object;
231     if ((object = database_get_data(db, KEY_BADWORDS, RECDB_OBJECT)))
232         dict_foreach(object, watchdog_saxdb_read_shitlist, NULL);
233     if ((object = database_get_data(db, KEY_CHANNELS, RECDB_OBJECT)))
234         dict_foreach(object, watchdog_saxdb_read_chanlist, NULL);
235     return 1;
236 }
237
238 static int
239 watchdog_saxdb_write(struct saxdb_context *ctx)
240 {
241     struct badword *badword;
242     char str[17];
243     unsigned int id = 0, ii;
244     dict_iterator_t it;
245
246     saxdb_start_record(ctx, KEY_BADWORDS, 1);
247     for (ii = 0; ii < shitlist.used; ++ii) {
248         badword = shitlist.list[ii];
249         snprintf(str, sizeof(str), "%x", id++);
250         saxdb_start_record(ctx, str, 0);
251         saxdb_write_string(ctx, KEY_BADWORD_MASK, badword->badword_mask);
252         saxdb_write_int(ctx, KEY_BADWORD_TRIGGERED, badword->triggered);
253         saxdb_write_int(ctx, KEY_BADWORD_ACTION, badword->action);
254         saxdb_end_record(ctx);
255     }
256     saxdb_end_record(ctx);
257
258     if (dict_size(chanlist)) {
259         saxdb_start_record(ctx, KEY_CHANNELS, 1);
260         for (it = dict_first(chanlist); it; it = iter_next(it)) {
261             struct watchdog_channel *wc = iter_data(it);
262             saxdb_start_record(ctx, wc->channel->name, 0);
263             //anything else?
264             saxdb_end_record(ctx);
265         }
266         saxdb_end_record(ctx);
267     }
268     
269     return 0;
270 }
271
272 static void
273 watchdog_cleanup(void)
274 {
275     while (shitlist.used)
276         delete_badword(shitlist.list[0]);
277     shitList_clean(&shitlist);
278     dict_delete(chanlist);
279 }
280
281 int
282 watchdog_init(void)
283 {
284     MS_LOG = log_register_type("Watchdog", "file:watchdog.log");
285     
286     shitList_init(&shitlist);
287     /* set up chanlist dict */
288     dict_delete(chanlist);
289     chanlist = dict_new();
290     dict_set_free_data(chanlist, free_chanlist_entry);
291     
292     conf_register_reload(watchdog_conf_read);
293     reg_exit_func(watchdog_cleanup);
294     saxdb_register("Watchdog", watchdog_saxdb_read, watchdog_saxdb_write);
295
296     const char *nick, *modes;
297     if((nick = conf_get_data("services/watchdog/nick", RECDB_QSTRING))) {
298         modes = conf_get_data("services/watchdog/modes", RECDB_QSTRING);
299         watchdog = AddLocalUser(nick, nick, NULL, "Watchdog Service", modes);
300         watchdog_service = service_register(watchdog);
301         reg_allchanmsg_func(watchdog, watchdog_channel_message);
302     }
303
304     watchdog_module = module_register("Watchdog", MS_LOG, "mod-watchdog.help", NULL);
305     modcmd_register(watchdog_module, "addbad", cmd_addbad, 1, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL);
306     modcmd_register(watchdog_module, "delbad", cmd_delbad, 1, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL);
307     modcmd_register(watchdog_module, "editbad", cmd_editbad, 1, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL);
308     modcmd_register(watchdog_module, "listbad", cmd_listbad, 1, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL);
309     modcmd_register(watchdog_module, "register", cmd_register, 1, MODCMD_REQUIRE_AUTHED, "flags", "+helping", NULL);
310     modcmd_register(watchdog_module, "unregister", cmd_unregister, 1, MODCMD_REQUIRE_AUTHED, "flags", "+helping", NULL);
311     message_register_table(msgtab);
312
313     return 1;
314 }
315
316 int
317 watchdog_finalize(void) {
318     dict_t conf_node;
319     const char *str;
320
321     str = "modules/watchdog";
322     if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
323         log_module(MS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
324         return 0;
325     }
326
327     str = database_get_data(conf_node, "nick", RECDB_QSTRING);
328     if (str) watchdog_conf.nick = str;
329     
330     str = database_get_data(conf_node, "modes", RECDB_QSTRING);
331     if (str) watchdog_conf.modes = str;
332     return 1;
333 }