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