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