added "channel master bot" system to prevent event duplicates
[NeonServV5.git] / IRCParser.c
1
2 #include "IRCParser.h"
3 #include "UserNode.h"
4 #include "ChanNode.h"
5 #include "ChanUser.h"
6 #include "IRCEvents.h"
7 #include "ClientSocket.h"
8 #include "WHOHandler.h"
9
10 struct irc_cmd *irc_commands = NULL;
11
12 static void parse_line(struct ClientSocket *client, char *line);
13 static void register_irc_function(char *command, irc_cmd_t *func);
14 static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc);
15
16 int parse_lines(struct ClientSocket *client, char *lines, int len) {
17     int i, used = 0;
18     char *line = lines;
19     for(i = 0; i < len; i++) {
20         if(lines[i] == '\r') //just zero it out :D
21             lines[i] = 0;
22         if(lines[i] == '\n') {
23             lines[i] = 0;
24             parse_line(client, line);
25             line = lines+(i+1);
26             used = i+1;
27         }
28     }
29     return used;
30 }
31
32 static void parse_line(struct ClientSocket *client, char *line) {
33     int argc = 0;
34     char *argv[MAXNUMPARAMS];
35     printf("[recv %lu] %s\n", (unsigned long) strlen(line), line);
36     if(line[0] == ':')
37         line++;
38     else
39         argv[argc++] = NULL;
40     while(*line) {
41         //skip leading spaces
42         while (*line == ' ')
43             *line++ = 0;
44         if (*line == ':') {
45            //the rest is a single parameter
46            argv[argc++] = line + 1;
47         }
48         argv[argc++] = line;
49         if (argc >= MAXNUMPARAMS)
50             break;
51         while (*line != ' ' && *line)
52             line++;
53     }
54     if(argc >= 2) {
55         parse_raw(client, argv[0], argv[1], argv+2, argc-2);
56     }
57 }
58
59 static void register_irc_function(char *command, irc_cmd_t *func) {
60     struct irc_cmd *irc_cmd = malloc(sizeof(*irc_cmd));
61     if (!irc_cmd)
62     {
63         perror("malloc() failed");
64         return;
65     }
66     irc_cmd->cmd = command;
67     irc_cmd->func = func;
68     irc_cmd->next = irc_commands;
69     irc_commands = irc_cmd;
70 }
71
72 static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc) {
73     struct irc_cmd *irc_cmd;
74     int ret = 0;
75     for(irc_cmd = irc_commands; irc_cmd; irc_cmd = irc_cmd->next) {
76         if(!stricmp(irc_cmd->cmd, cmd)) {
77             ret = irc_cmd->func(client, from, argv, argc);
78             break;
79         }
80     }
81     if(!ret) {
82         //fprintf(stderr,"PARSE ERROR: %s", cmd); commented out right now - we're still developing and this is very spammy
83     }
84 }
85
86 static USERLIST_CALLBACK(got_channel_userlist) {
87     struct ChanUser *chanuser = data;
88     event_join(chanuser);
89     putsock(client, "PRIVMSG %s :[BOT JOIN] Users on this Channel:", chan->name);
90     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
91         putsock(client, "PRIVMSG %s :  %s!%s@%s [%s]  rights: %d", chan->name, chanuser->user->nick, chanuser->user->ident, chanuser->user->host, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "*"), chanuser->flags);
92     }
93 }
94
95 static IRC_CMD(raw_001) {
96     client->flags |= SOCKET_FLAG_READY;
97     putsock(client, "JOIN #pktest");
98     return 1;
99 }
100
101 static IRC_CMD(raw_join) {
102     if(from == NULL || argc < 1) return 0;
103     struct UserNode *user = getUserByMask(from);
104     struct ChanNode *chan = getChanByName(argv[0]);
105     if(!chan && !(user->flags & USERFLAG_ISBOT)) return 0;
106     if(user == NULL) {
107         user = addUserMask(from);
108     }
109     if(chan == NULL) {
110         chan = addChannel(argv[0]);
111         //request member list
112         chan->chanbot = user;
113         struct ChanUser *chanuser = addChanUser(chan, user); //it must be a bot
114         get_userlist(chan, got_channel_userlist, chanuser);
115     } else if(!isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
116         struct ChanUser *chanuser = addChanUser(chan, user);
117         event_join(chanuser);
118     }
119     return 1;
120 }
121
122 static IRC_CMD(raw_part) {
123     if(from == NULL || argc < 2) return 0;
124     struct UserNode *user = getUserByMask(from);
125     if(user == NULL) return 0;
126     struct ChanNode *chan = getChanByName(argv[0]);
127     if(chan == NULL) return 0;
128     if(isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
129         struct ChanUser *chanuser = getChanUser(user, chan);
130         delChanUser(chanuser, 0); //we need to free the chanuser manually!
131         event_part(chanuser, argv[1]);
132         free(chanuser);
133         if(chan->chanbot == user) {
134             //check if theres another bot in the channel - otherwise free it
135             checkChannelVisibility(chan);
136         }
137     }
138     if(user->channel == NULL && !(user->flags & USERFLAG_ISBOT)) {
139         //remove the user
140         delUser(user, 1);
141     }
142     return 1;
143 }
144
145 static IRC_CMD(raw_quit) {
146     if(from == NULL || argc < 2) return 0;
147     struct UserNode *user = getUserByMask(from);
148     if(user == NULL) return 0;
149     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
150     event_quit(user, argv[1]);
151     if(user->flags & USERFLAG_ISBOT) {
152         //check if there are other bots in the users channel - otherwise free them
153         struct ChanUser *chanuser, *next;
154         for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
155             next = getUserChannels(user, chanuser);
156             checkChannelVisibility(chanuser->chan);
157         }
158     }
159     delUser(user, 1); //now we fully free the user
160     return 1;
161 }
162
163 void bot_disconnect(struct ClientSocket *client) {
164     struct UserNode *user = client->user;
165     struct ChanUser *chanuser, *next;
166     delUser(user, 0);
167     event_quit(user, "disconnected");
168     for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
169         next = getUserChannels(user, chanuser);
170         checkChannelVisibility(chanuser->chan);
171         free(chanuser);
172     }
173     user->channel = NULL;
174 }
175
176 static IRC_CMD(raw_kick) {
177     if(from == NULL || argc < 3) return 0;
178     struct UserNode *user = getUserByMask(from);
179     struct UserNode *target = getUserByNick(argv[1]);
180     struct ChanNode *chan = getChanByName(argv[0]);
181     if(chan == NULL || target == NULL) return 0;
182     if(isUserOnChan(target, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
183         if(user == NULL) {
184             user = createTempUser(from);
185             user->flags |= USERFLAG_ISTMPUSER;
186         }
187         struct ChanUser *chanuser = getChanUser(target, chan);
188         delChanUser(chanuser, 0); //we need to free the chanuser manually!
189         event_kick(user, chanuser, argv[1]);
190         free(chanuser);
191         if(user->flags & USERFLAG_ISTMPUSER) {
192             free(user);
193         }
194         if(target->flags & USERFLAG_ISBOT) {
195             //check if theres another bot in the channel - otherwise free it
196             checkChannelVisibility(chan);
197         }
198     }
199     if(target->channel == NULL && !(target->flags & USERFLAG_ISBOT)) {
200         //remove the user
201         delUser(user, 1);
202     }
203     return 1;
204 }
205
206 static IRC_CMD(raw_topic) {
207     if(from == NULL || argc < 2) return 0;
208     struct UserNode *user = getUserByMask(from);
209     struct ChanNode *chan = getChanByName(argv[0]);
210     if(chan == NULL) return 0;
211     if(chan->chanbot != client->user) return 1; //just ignore it to prevent event duplicates
212     if(user == NULL) {
213         user = createTempUser(from);
214         user->flags |= USERFLAG_ISTMPUSER;
215     }
216     event_topic(user, chan, argv[1]);
217     strcpy(chan->topic, argv[1]);
218     if(user->flags & USERFLAG_ISTMPUSER) {
219         free(user);
220     }
221     return 1;
222 }
223
224 static IRC_CMD(raw_privmsg) {
225     if(from == NULL || argc < 2) return 0;
226     struct UserNode *user = getUserByMask(from);
227     if(user == NULL) {
228         user = createTempUser(from);
229         user->flags |= USERFLAG_ISTMPUSER;
230     }
231     if(argv[0][0] == '#') { //Channel message
232         struct ChanNode *chan = getChanByName(argv[0]);
233         if(chan && chan->chanbot == client->user)
234             event_chanmsg(user, chan, argv[1]);
235     } else {
236         struct UserNode *target = getUserByNick(argv[0]);
237         if(target)
238             event_privmsg(user, target, argv[1]);
239     }
240     if(user->flags & USERFLAG_ISTMPUSER) {
241         free(user);
242     }
243     return 1;
244 }
245
246 static IRC_CMD(raw_ping) {
247     if(argc == 0) return 0;
248     putsock(client, "PONG :%s", argv[0]);
249     return 1;
250 }
251
252 static IRC_CMD(raw_354) {
253     recv_whohandler_354(client, argv, argc);
254     return 1;
255 }
256
257 static IRC_CMD(raw_315) {
258     recv_whohandler_315(client, argv, argc);
259     return 1;
260 }
261
262 void parser_init() {
263     //all the raws we receive...
264     register_irc_function("001", raw_001);
265     register_irc_function("TOPIC", raw_topic);
266     register_irc_function("KICK", raw_kick);
267     register_irc_function("JOIN", raw_join);
268     register_irc_function("PART", raw_part);
269     register_irc_function("QUIT", raw_quit);
270     register_irc_function("354", raw_354);
271     register_irc_function("315", raw_315);
272     register_irc_function("PING", raw_ping);
273     register_irc_function("PRIVMSG", raw_privmsg);
274 }