changed access variable name
[NeonServV5.git] / modcmd.c
1
2 #include "modcmd.h"
3 #include "IRCEvents.h"
4 #include "IRCParser.h"
5 #include "ClientSocket.h"
6 #include "UserNode.h"
7 #include "ChanNode.h"
8 #include "ChanUser.h"
9 #include "WHOHandler.h"
10 #include "lang.h"
11
12 struct trigger_callback {
13     int botid;
14     trigger_callback_t *func;
15     
16     struct trigger_callback *next;
17 };
18
19 struct command_check_user_cache {
20     struct ClientSocket *client, *textclient;
21     struct UserNode *user;
22     struct ChanNode *chan;
23     char **argv;
24     int argc;
25     char *message;
26     struct cmd_binding *cbind;
27 };
28
29 static struct cmd_binding **cmd_binds;
30 static struct cmd_function *cmd_functions = NULL;
31 static struct trigger_callback *trigger_callbacks = NULL;
32 static struct ClientSocket *tmp_text_client;
33
34 static const struct default_language_entry msgtab[] = {
35     {"MODCMD_LESS_PARAM_COUNT", "This command requires more parameters."},
36     {"MODCMD_CHAN_REQUIRED",    "You must provide the name of a channel that exists."},
37     {"MODCMD_AUTH_REQUIRED",    "You need to be authenticated with AuthServ to use this command."},
38     {"MODCMD_PRIVILEGED",       "§b%s§b is a privileged command."},
39     
40     
41     {NULL, NULL}
42 };
43
44 static int get_binds_index(char first_char) {
45     if(tolower(first_char) >= 'a' && tolower(first_char) <= 'z') {
46         return tolower(first_char - 'a');
47     }
48     return 26;
49 }
50
51 struct ClientSocket* get_prefered_bot(int botid) {
52     struct ClientSocket *client;
53     for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
54         if(client->botid == botid && (client->flags & SOCKET_FLAG_PREFERRED))
55             return client;
56     }
57     return NULL;
58 }
59
60 static char* get_channel_trigger(int botid, struct ChanNode *chan) {
61     struct trigger_cache *trigger;
62     for(trigger = chan->trigger; trigger; trigger = trigger->next) {
63         if(trigger->botid == botid)
64             return trigger->trigger;
65     }
66     struct trigger_callback *cb;
67     for(cb = trigger_callbacks; cb; cb = cb->next) {
68         if(cb->botid == botid)
69             break;
70     }
71     char triggerStr[TRIGGERLEN];
72     if(cb)
73         cb->func(chan, triggerStr);
74     else
75         strcpy(triggerStr, "+");
76     trigger = malloc(sizeof(*trigger));
77     if (!trigger) {
78         perror("malloc() failed");
79         return 0;
80     }
81     trigger->botid = botid;
82     trigger->trigger = strdup(triggerStr);
83     trigger->next = chan->trigger;
84     chan->trigger = trigger;
85     return trigger->trigger;
86 }
87
88 static USERAUTH_CALLBACK(command_checked_auth) {
89     struct command_check_user_cache *cache = data;
90     int execute_cmd = 1;
91     tmp_text_client = cache->textclient;
92     if((cache->cbind->func->flags & CMDFLAG_REQUIRE_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) {
93         reply(tmp_text_client, user, "MODCMD_AUTH_REQUIRED");
94         execute_cmd = 0;
95     }
96     else if((cache->cbind->func->flags & CMDFLAG_REQUIRE_GOD) && !isGodMode(user)) {
97         reply(tmp_text_client, user, "MODCMD_PRIVILEGED", cache->cbind->cmd);
98         execute_cmd = 0;
99     }
100     if(execute_cmd) {
101         cache->cbind->func->func(cache->client, user, cache->chan, cache->argv, cache->argc);
102     }
103     free(cache->message);
104     free(cache);
105 }
106
107 static void handle_command(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, char *message) {
108     if(message[0] == '#') {
109         char *chanName = message;
110         message = strstr(message, " ");
111         if(!message) return;
112         *message = '\0';
113         message++;
114         struct ChanNode *chan2 = getChanByName(chanName);
115         if(chan2)
116             chan = chan2;
117     }
118     message = strdup(message);
119     int bind_index = get_binds_index(message[0]);
120     char *args = strstr(message, " ");
121     if(args) {
122         *args = '\0';
123         args++;
124     }
125     struct cmd_binding *cbind;
126     for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
127         if(cbind->botid == client->botid && strcmp(cbind->cmd, message) == 0) {
128             //get a text bot
129             tmp_text_client = get_prefered_bot(client->botid);
130             //parse the arguments...
131             char *arga[MAXNUMPARAMS];
132             char **argv;
133             int argc = 0;
134             if(args) {
135                 while(*args) {
136                     //skip leading spaces
137                     while (*args == ' ')
138                         *args++ = 0;
139                     arga[argc++] = args;
140                     if (argc >= MAXNUMPARAMS)
141                         break;
142                     while (*args != ' ' && *args)
143                         args++;
144                 }
145             }
146             argv = arga;
147             if(argc != 0 && argv[0][0] == '#') {
148                 struct ChanNode *chan2 = getChanByName(argv[0]);
149                 if(chan2) {
150                     argv += 1;
151                     argc -= 1;
152                     chan = chan2;
153                 }
154             }
155             if(cbind->parameters) {
156                 //userdefined parameters...
157                 char *uarga[MAXNUMPARAMS];
158                 char params[strlen(cbind->parameters)+1];
159                 strcpy(params, cbind->parameters);
160                 int uargpos = 0, argi, allargs = 0;
161                 char *ppos = params;
162                 char *prev_ppos = params;
163                 while((ppos = strstr(ppos, " "))) {
164                     *ppos = '\0';
165                     if(prev_ppos[0] == '%') {
166                         prev_ppos++;
167                         if(prev_ppos[strlen(prev_ppos)-1] == '-') {
168                             allargs = 1;
169                             prev_ppos[strlen(prev_ppos)-1] = '\0';
170                         } else
171                             allargs = 0;
172                         argi = atoi(prev_ppos);
173                         if(argi > 0) {
174                             if(argi <= argc) continue;
175                             uarga[uargpos++] = argv[argi-1];
176                             if(allargs) {
177                                 for(;argi < argc; argi++)
178                                     uarga[uargpos++] = argv[argi-1];
179                             }
180                         } else if(!strcmp(prev_ppos, "c"))
181                             uarga[uargpos++] = (chan ? chan->name : NULL);
182                         else if(!strcmp(prev_ppos, "n")) 
183                             uarga[uargpos++] = user->nick;
184                     } else {
185                         uarga[uargpos++] = prev_ppos;
186                     }
187                     ppos++;
188                     prev_ppos = ppos;
189                 }
190                 argv = uarga;
191                 argc = uargpos;
192             }
193             if(argc < cbind->func->paramcount) {
194                 reply(tmp_text_client, user, "MODCMD_LESS_PARAM_COUNT");
195                 break;
196             }
197             if((cbind->func->flags & CMDFLAG_REQUIRE_CHAN) && !chan) {
198                 reply(tmp_text_client, user, "MODCMD_CHAN_REQUIRED");
199                 break;
200             }
201             if((cbind->func->flags & CMDFLAG_CHECK_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) {
202                 //check auth...
203                 struct command_check_user_cache *data = malloc(sizeof(*data));
204                 char **temp_argv = malloc(argc*sizeof(*temp_argv));
205                 if (!data || !temp_argv) {
206                     perror("malloc() failed");
207                     break;
208                 }
209                 memcpy(temp_argv, argv, argc*sizeof(*temp_argv));
210                 data->argv = temp_argv;
211                 data->argc = argc;
212                 data->client = client;
213                 data->user = user;
214                 data->chan = chan;
215                 data->message = message;
216                 data->cbind = cbind;
217                 data->textclient = tmp_text_client;
218                 get_userauth(user, command_checked_auth, data);
219                 return;
220             }
221             if((cbind->func->flags & CMDFLAG_REQUIRE_AUTH) && !(user->flags & USERFLAG_ISAUTHED)) {
222                 reply(tmp_text_client, user, "MODCMD_AUTH_REQUIRED");
223                 break;
224             }
225             if((cbind->func->flags & CMDFLAG_REQUIRE_GOD) && !isGodMode(user)) {
226                 reply(tmp_text_client, user, "MODCMD_PRIVILEGED", cbind->cmd);
227                 break;
228             }
229             cbind->func->func(client, user, chan, argv, argc);
230             break;
231         }
232     }
233     free(message);
234 }
235
236 static void got_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message) {
237     fd_set fds;
238     char *trigger;
239     struct ClientSocket *client;
240     FD_ZERO(&fds);
241     for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
242         if(isUserOnChan(client->user, chan) && (client->flags & SOCKET_FLAG_PREFERRED) && !FD_ISSET(client->botid, &fds)) {
243             FD_SET(client->botid, &fds);
244             trigger = get_channel_trigger(client->botid, chan);
245             if(stricmplen(message, trigger, strlen(trigger)) == 0) {
246                 handle_command(client, user, chan, message + strlen(trigger));
247             }
248         }
249     }
250     for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
251         if(isUserOnChan(client->user, chan) && !FD_ISSET(client->botid, &fds)) {
252             FD_SET(client->botid, &fds);
253             trigger = get_channel_trigger(client->botid, chan);
254             if(stricmplen(message, trigger, strlen(trigger)) == 0) {
255                 handle_command(client, user, chan, message + strlen(trigger));
256             }
257         }
258     }
259 }
260
261 static void got_privmsg(struct UserNode *user, struct UserNode *target, char *message) {
262     struct ClientSocket *client;
263     for(client = getBots(SOCKET_FLAG_READY, NULL); client; client = getBots(SOCKET_FLAG_READY, client)) {
264         if(client->user == target) {
265             handle_command(client, user, NULL, message);
266         }
267     }
268 }
269
270 int register_command(int botid, char *name, cmd_bind_t *func, int paramcount, unsigned int flags) {
271     struct cmd_function *cmdfunc;
272     for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) {
273         if(cmdfunc->botid == botid && strcmp(cmdfunc->name, name) == 0)
274             return 0;
275     }
276     cmdfunc = malloc(sizeof(*cmdfunc));
277     if (!cmdfunc) {
278         perror("malloc() failed");
279         return 0;
280     }
281     cmdfunc->botid = botid;
282     cmdfunc->name = strdup(name);
283     cmdfunc->func = func;
284     cmdfunc->flags = 0;
285     cmdfunc->paramcount = paramcount;
286     cmdfunc->next = cmd_functions;
287     cmd_functions = cmdfunc;
288     return 1;
289 }
290
291 int set_trigger_callback(int botid, trigger_callback_t *func) {
292     static struct trigger_callback *cb = NULL;
293     for(cb = trigger_callbacks; cb; cb = cb->next) {
294         if(cb->botid == botid)
295             break;
296     }
297     if(!cb) {
298         cb = malloc(sizeof(*cb));
299         if (!cb) {
300             perror("malloc() failed");
301             return 0;
302         }
303         cb->botid = botid;
304         cb->next = trigger_callbacks;
305         trigger_callbacks = cb;
306     }
307     cb->func = func;
308     return 1;
309 }
310
311 int changeChannelTrigger(int botid, struct ChanNode *chan, char *new_trigger) {
312     struct trigger_cache *trigger;
313     for(trigger = chan->trigger; trigger; trigger = trigger->next) {
314         if(trigger->botid == botid) {
315             free(trigger->trigger);
316             trigger->trigger = strdup(new_trigger);
317             return 1;
318         }
319     }
320     return 0;
321 }
322
323 int bind_cmd_to_function(int botid, char *cmd, struct cmd_function *func) {
324     int bind_index = get_binds_index(cmd[0]);
325     struct cmd_binding *cbind;
326     for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
327         if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0)
328             return 0;
329     }
330     cbind = malloc(sizeof(*cbind));
331     if (!cbind) {
332         perror("malloc() failed");
333         return 0;
334     }
335     cbind->botid = botid;
336     cbind->cmd = strdup(cmd);
337     cbind->func = func;
338     cbind->parameters = NULL;
339     cbind->gaccess = 0;
340     cbind->flags = 0;
341     cbind->next = cmd_binds[bind_index];
342     cmd_binds[bind_index] = cbind;
343     return 1;
344 }
345
346 int bind_cmd_to_command(int botid, char *cmd, char *func) {
347     struct cmd_function *cmdfunc;
348     for(cmdfunc = cmd_functions; cmdfunc; cmdfunc = cmdfunc->next) {
349         if(cmdfunc->botid == botid && strcmp(cmdfunc->name, func) == 0)
350             break;
351     }
352     if(!cmdfunc) return 0;
353     int bind_index = get_binds_index(cmd[0]);
354     struct cmd_binding *cbind;
355     for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
356         if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0)
357             return 0;
358     }
359     cbind = malloc(sizeof(*cbind));
360     if (!cbind) {
361         perror("malloc() failed");
362         return 0;
363     }
364     cbind->botid = botid;
365     cbind->cmd = strdup(cmd);
366     cbind->func = cmdfunc;
367     cbind->next = cmd_binds[bind_index];
368     cbind->parameters = NULL;
369     cbind->gaccess = 0;
370     cbind->flags = 0;
371     cmd_binds[bind_index] = cbind;
372     return 1;
373 }
374
375 int unbind_cmd(int botid, char *cmd) {
376     int bind_index = get_binds_index(cmd[0]);
377     struct cmd_binding *cbind, *last = NULL;
378     for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
379         if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
380             if(last)
381                 last->next = cbind->next;
382             else
383                 cmd_binds[bind_index] = cbind->next;
384             free(cbind->cmd);
385             if(cbind->parameters)
386                 free(cbind->parameters);
387             free(cbind);
388             return 1;
389         } else
390             last = cbind;
391     }
392     return 0;
393 }
394
395 struct ClientSocket *getTextBot() {
396     return tmp_text_client;
397 }
398
399 void init_modcmd() {
400     cmd_binds = calloc(27, sizeof(*cmd_binds));
401     bind_chanmsg(got_chanmsg);
402     bind_privmsg(got_privmsg);
403     register_default_language_table(msgtab);
404 }
405
406 void free_modcmd() {
407     int i;
408     for(i = 0; i < 27; i++) {
409         struct cmd_binding *cbind, *next;
410         for(cbind = cmd_binds[i]; cbind; cbind = next) {
411             next = cbind->next;
412             free(cbind->cmd);
413             if(cbind->parameters)
414                 free(cbind->parameters);
415             free(cbind);
416         }
417     }
418     free(cmd_binds);
419     struct cmd_function *cmdfunct, *next;
420     for(cmdfunct = cmd_functions; cmdfunct; cmdfunct = next) {
421         next = cmdfunct->next;
422         free(cmdfunct->name);
423         free(cmdfunct);
424     }
425     struct trigger_callback *cb, *next_cb;
426     for(cb = trigger_callbacks; cb; cb = next_cb) {
427         next_cb = cb->next;
428         free(next_cb);
429     }
430     cmd_functions = NULL;
431     trigger_callbacks = NULL;
432 }
433
434 void bind_set_parameters(int botid, char *cmd, char *parameters) {
435     
436 }
437
438 void bind_set_gaccess(int botid, char *cmd, int gaccess) {
439     
440 }
441