*** VERSION 5.1.0 ***
[NeonServV5.git] / src / IRCParser.c
1 /* IRCParser.c - NeonServ v5.1
2  * Copyright (C) 2011  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
18 #include "IRCParser.h"
19 #include "UserNode.h"
20 #include "ChanNode.h"
21 #include "ChanUser.h"
22 #include "IRCEvents.h"
23 #include "ClientSocket.h"
24 #include "WHOHandler.h"
25 #include "lang.h"
26 #include "DBHelper.h"
27 #include "BanNode.h"
28 #include "ModeNode.h"
29
30 struct irc_cmd *irc_commands = NULL;
31
32 static void parse_line(struct ClientSocket *client, char *line);
33 static void register_irc_function(char *command, irc_cmd_t *func);
34 static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc);
35
36 int parse_lines(struct ClientSocket *client, char *lines, int len) {
37     int i, used = 0;
38     char *line = lines;
39     for(i = 0; i < len; i++) {
40         if(lines[i] == '\r') //just zero it out :D
41             lines[i] = 0;
42         if(lines[i] == '\n') {
43             lines[i] = 0;
44             parse_line(client, line);
45             line = lines+(i+1);
46             used = i+1;
47         }
48     }
49     return used;
50 }
51
52 static void parse_line(struct ClientSocket *client, char *line) {
53     int argc = 0;
54     char *argv[MAXNUMPARAMS];
55     printf("[recv %lu] %s\n", (unsigned long) strlen(line), line);
56     if(line[0] == ':')
57         line++;
58     else
59         argv[argc++] = NULL;
60     while(*line) {
61         //skip leading spaces
62         while (*line == ' ')
63             *line++ = 0;
64         if (*line == ':') {
65            //the rest is a single parameter
66            argv[argc++] = line + 1;
67            break;
68         }
69         argv[argc++] = line;
70         if (argc >= MAXNUMPARAMS)
71             break;
72         while (*line != ' ' && *line)
73             line++;
74     }
75     if(argc >= 2) {
76         parse_raw(client, argv[0], argv[1], argv+2, argc-2);
77     }
78 }
79
80 static void register_irc_function(char *command, irc_cmd_t *func) {
81     struct irc_cmd *irc_cmd = malloc(sizeof(*irc_cmd));
82     if (!irc_cmd)
83     {
84         perror("malloc() failed");
85         return;
86     }
87     irc_cmd->cmd = command;
88     irc_cmd->func = func;
89     irc_cmd->next = irc_commands;
90     irc_commands = irc_cmd;
91 }
92
93 static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc) {
94     struct irc_cmd *irc_cmd;
95     int ret = 0;
96     for(irc_cmd = irc_commands; irc_cmd; irc_cmd = irc_cmd->next) {
97         if(!stricmp(irc_cmd->cmd, cmd)) {
98             ret = irc_cmd->func(client, from, argv, argc);
99             break;
100         }
101     }
102     if(!irc_cmd) {
103         event_raw(client, from, cmd, argv, argc);
104     } else if(!ret) {
105         fprintf(stderr,"PARSE ERROR: %s\n", cmd);
106     }
107 }
108
109 static USERLIST_CALLBACK(got_channel_userlist) {
110     struct ChanUser *chanuser = data;
111     event_join(chanuser);
112 }
113
114 static IRC_CMD(raw_001) {
115     client->flags |= SOCKET_FLAG_READY;
116     event_bot_ready(client);
117     return 1;
118 }
119
120 static IRC_CMD(raw_join) {
121     if(from == NULL || argc < 1) return 0;
122     struct UserNode *user = getUserByMask(from);
123     struct ChanNode *chan = getChanByName(argv[0]);
124     if(!chan && !(user->flags & USERFLAG_ISBOT)) return 0;
125     if(user == NULL) {
126         user = addUserMask(from);
127     }
128     if(chan == NULL) {
129         chan = addChannel(argv[0]);
130         //request member list
131         chan->chanbot = user;
132         struct ChanUser *chanuser = addChanUser(chan, user); //it must be a bot
133         get_userlist(chan, got_channel_userlist, chanuser);
134         putsock(client, "MODE %s", chan->name);
135         putsock(client, "MODE %s +b", chan->name);
136     } else if(!isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
137         struct ChanUser *chanuser = addChanUser(chan, user);
138         event_join(chanuser);
139     }
140     return 1;
141 }
142
143 static IRC_CMD(raw_part) {
144     if(from == NULL || argc < 1) return 0;
145     struct UserNode *user = getUserByMask(from);
146     if(user == NULL) return 0;
147     struct ChanNode *chan = getChanByName(argv[0]);
148     if(chan == NULL) return 0;
149     if(isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
150         struct ChanUser *chanuser = getChanUser(user, chan);
151         delChanUser(chanuser, 0); //we need to free the chanuser manually!
152         event_part(chanuser, (argc > 1 ? argv[1] : NULL));
153         free(chanuser);
154         if(chan->chanbot == user) {
155             //check if theres another bot in the channel - otherwise free it
156             checkChannelVisibility(chan);
157         }
158     }
159     if(user->channel == NULL && !(user->flags & USERFLAG_ISBOT)) {
160         //remove the user
161         delUser(user, 1);
162     }
163     return 1;
164 }
165
166 static IRC_CMD(raw_quit) {
167     if(from == NULL || argc < 1) return 0;
168     struct UserNode *user = getUserByMask(from);
169     if(user == NULL) return 0;
170     delUser(user, 0); //a little bit crazy, but we want to delete the user on the channel's userlists - but not the users channel list
171     event_quit(user, argv[0]);
172     if(user->flags & USERFLAG_ISBOT) {
173         //check if there are other bots in the users channel - otherwise free them
174         struct ChanUser *chanuser, *next;
175         for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
176             next = getUserChannels(user, chanuser);
177             checkChannelVisibility(chanuser->chan);
178         }
179     }
180     delUser(user, 1); //now we fully free the user
181     return 1;
182 }
183
184 void bot_disconnect(struct ClientSocket *client) {
185     struct UserNode *user = client->user;
186     struct ChanUser *chanuser, *next;
187     delUser(user, 0);
188     event_quit(user, "disconnected");
189     for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
190         next = getUserChannels(user, chanuser);
191         checkChannelVisibility(chanuser->chan);
192         free(chanuser);
193     }
194     user->channel = NULL;
195 }
196
197 static IRC_CMD(raw_kick) {
198     if(from == NULL || argc < 3) return 0;
199     struct UserNode *user = getUserByMask(from);
200     struct UserNode *target = getUserByNick(argv[1]);
201     struct ChanNode *chan = getChanByName(argv[0]);
202     if(chan == NULL || target == NULL) return 0;
203     if(isUserOnChan(target, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
204         if(user == NULL) {
205             user = createTempUser(from);
206             user->flags |= USERFLAG_ISTMPUSER;
207         }
208         struct ChanUser *chanuser = getChanUser(target, chan);
209         delChanUser(chanuser, 0); //we need to free the chanuser manually!
210         event_kick(user, chanuser, argv[1]);
211         free(chanuser);
212         if(target->flags & USERFLAG_ISBOT) {
213             //check if theres another bot in the channel - otherwise free it
214             checkChannelVisibility(chan);
215         }
216     }
217     if(target->channel == NULL && !(target->flags & USERFLAG_ISBOT)) {
218         //remove the user
219         delUser(target, 1);
220     }
221     return 1;
222 }
223
224 static IRC_CMD(raw_topic) {
225     if(from == NULL || argc < 2) return 0;
226     struct UserNode *user = getUserByMask(from);
227     struct ChanNode *chan = getChanByName(argv[0]);
228     if(chan == NULL) return 0;
229     if(chan->chanbot != client->user) return 1; //just ignore it to prevent event duplicates
230     if(user == NULL) {
231         user = createTempUser(from);
232         user->flags |= USERFLAG_ISTMPUSER;
233     }
234     event_topic(user, chan, argv[1]);
235     strcpy(chan->topic, argv[1]);
236     return 1;
237 }
238
239 static IRC_CMD(raw_privmsg) {
240     if(from == NULL || argc < 2) return 0;
241     struct UserNode *user = getUserByMask(from);
242     if(user == NULL) {
243         user = createTempUser(from);
244         user->flags |= USERFLAG_ISTMPUSER;
245     }
246     if(argv[0][0] == '#') { //Channel message
247         struct ChanNode *chan = getChanByName(argv[0]);
248         if(chan && chan->chanbot == client->user) {
249             if(argv[1][0] == '\001') {
250                 char *cmd = &argv[1][1];
251                 char *text = strstr(cmd, " ");
252                 if(text) {
253                     *text = '\0';
254                     text++;
255                     if(strlen(text) && text[strlen(text)-1] == '\001')
256                         text[strlen(text)-1] = '\0';
257                 } else if(strlen(cmd) && cmd[strlen(cmd)-1] == '\001')
258                     cmd[strlen(cmd)-1] = '\0';
259                 event_chanctcp(user, chan, cmd, text);
260             } else
261                 event_chanmsg(user, chan, argv[1]);
262         }
263     } else {
264         struct UserNode *target = getUserByNick(argv[0]);
265         if(target) {
266             if(argv[1][0] == '\001') {
267                 char *cmd = &argv[1][1];
268                 char *text = strstr(cmd, " ");
269                 if(text) {
270                     *text = '\0';
271                     text++;
272                     if(strlen(text) && text[strlen(text)-1] == '\001')
273                         text[strlen(text)-1] = '\0';
274                 } else if(strlen(cmd) && cmd[strlen(cmd)-1] == '\001')
275                     cmd[strlen(cmd)-1] = '\0';
276                 event_privctcp(user, target, cmd, text);
277             } else
278                 event_privmsg(user, target, argv[1]);
279         }
280     }
281     return 1;
282 }
283
284 static IRC_CMD(raw_notice) {
285     if(from == NULL || argc < 2) return 0;
286     struct UserNode *user = getUserByMask(from);
287     if(user == NULL) {
288         user = createTempUser(from);
289         user->flags |= USERFLAG_ISTMPUSER;
290     }
291     if(argv[0][0] == '#') { //Channel notice
292         struct ChanNode *chan = getChanByName(argv[0]);
293         if(chan && chan->chanbot == client->user)
294             event_channotice(user, chan, argv[1]);
295     } else {
296         struct UserNode *target = getUserByNick(argv[0]);
297         if(target)
298             event_privnotice(user, target, argv[1]);
299     }
300     return 1;
301 }
302
303 static IRC_CMD(raw_nick) {
304     if(from == NULL || argc == 0) return 0;
305     struct UserNode *user = getUserByMask(from);
306     if(user == NULL) return 0;
307     event_nick(user, argv[0]);
308     renameUser(user, argv[0]);
309     return 1;
310 }
311
312 static IRC_CMD(raw_ping) {
313     if(argc == 0) return 0;
314     putsock(client, "PONG :%s", argv[0]);
315     return 1;
316 }
317
318 static IRC_CMD(raw_354) {
319     recv_whohandler_354(client, argv, argc);
320     return 1;
321 }
322
323 static IRC_CMD(raw_315) {
324     recv_whohandler_315(client, argv, argc);
325     return 1;
326 }
327
328 static IRC_CMD(raw_324) { //MODE LIST
329     //Watchcat #pktest +stnzN
330     if(from == NULL || argc < 3) return 0;
331     struct ChanNode *chan = getChanByName(argv[1]);
332     if(chan == NULL) return 0;
333     parseModes(chan->modes, argv[2], argv+3, argc-3);
334     return 1;
335 }
336
337 static IRC_CMD(raw_invite) {
338     if(from == NULL || argc < 2) return 0;
339     struct UserNode *user = getUserByMask(from);
340     if(user == NULL) {
341         user = createTempUser(from);
342         user->flags |= USERFLAG_ISTMPUSER;
343     }
344     event_invite(client, user, argv[1]);
345     return 1;
346 }
347
348 static IRC_CMD(raw_mode) {
349     if(from == NULL || argc < 2) return 0;
350     struct UserNode *user = getUserByMask(from);
351     if(user == NULL) {
352         user = createTempUser(from);
353         user->flags |= USERFLAG_ISTMPUSER;
354     }
355     if(argv[0][0] == '#') {
356         //ChannelMode
357         struct ChanNode *chan = getChanByName(argv[0]);
358         if(!chan) return 0;
359         if(chan->chanbot != client->user) return 1;
360         event_mode(user, chan, argv[1], argv+2, argc-2);
361         parseModes(chan->modes, argv[1], argv+2, argc-2);
362     } else {
363         //UserMode
364     }
365     return 1;
366 }
367
368 static IRC_CMD(raw_367) {
369     //Watchcat #pktest pk911!*@* TestBot!~bot@pktest.user.WebGamesNet 1315863279
370     struct ChanNode *chan = getChanByName(argv[1]);
371     if(!chan) return 0;
372     struct BanNode *ban;
373     while((ban = getMatchingChannelBan(chan, argv[2]))) {
374         removeChannelBan(ban);
375     }
376     addChannelBan(chan, argv[2]);
377     return 1;
378 }
379
380 void init_parser() {
381     //all the raws we receive...
382     register_irc_function("001", raw_001);
383     register_irc_function("324", raw_324);
384     register_irc_function("367", raw_367);
385     register_irc_function("INVITE", raw_invite);
386     register_irc_function("NOTICE", raw_notice);
387     register_irc_function("TOPIC", raw_topic);
388     register_irc_function("KICK", raw_kick);
389     register_irc_function("PART", raw_part);
390     register_irc_function("QUIT", raw_quit);
391     register_irc_function("JOIN", raw_join);
392     register_irc_function("MODE", raw_mode);
393     register_irc_function("NICK", raw_nick);
394     register_irc_function("354", raw_354);
395     register_irc_function("315", raw_315);
396     register_irc_function("PING", raw_ping);
397     register_irc_function("PRIVMSG", raw_privmsg);
398 }
399
400 void free_parser() {
401     struct irc_cmd *cmd, *next;
402     for(cmd = irc_commands; cmd; cmd = next) {
403         next = cmd->next;
404         free(cmd);
405     }
406 }
407
408 void reply(struct ClientSocket *client, struct UserNode *user, const char *text, ...) {
409     const char *reply_format = get_language_string(user, text);
410     if(reply_format == NULL)
411         reply_format = text;
412     loadUserSettings(user);
413     char formatBuf[MAXLEN];
414     sprintf(formatBuf, "%s %s :%s", ((user->flags & USERFLAG_REPLY_PRIVMSG) ? "PRIVMSG" : "NOTICE"), user->nick, reply_format);
415     va_list arg_list;
416     char sendBuf[MAXLEN];
417     int pos;
418     if (!(client->flags & SOCKET_FLAG_CONNECTED)) return;
419     sendBuf[0] = '\0';
420     va_start(arg_list, text);
421     pos = vsnprintf(sendBuf, MAXLEN - 2, formatBuf, arg_list);
422     va_end(arg_list);
423     if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
424     sendBuf[pos] = '\n';
425     sendBuf[pos+1] = '\0';
426     write_socket(client, sendBuf, pos+1);
427 }
428
429 char* merge_argv(char **argv, int start, int end) {
430     return merge_argv_char(argv, start, end, ' ');
431 }
432
433 char* merge_argv_char(char **argv, int start, int end, char seperator) {
434     int i;
435     char *p = NULL;
436     for(i = start; i < end; i++) {
437         p = argv[i];
438         while(*p) p++;
439         *p = seperator;
440     }
441     if(p) *p = '\0';
442     return argv[start];
443 }