fixed statistics user counter
[NeonServV5.git] / src / IRCParser.c
1 /* IRCParser.c - NeonServ v5.3
2  * Copyright (C) 2011-2012  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 #include "tools.h"
30
31 struct irc_cmd *irc_commands = NULL;
32 static struct UserNode *registering_users = NULL;
33 int statistics_privmsg = 0;
34 int statistics_network_users = 0;
35 int statistics_network_channels = 0;
36
37 static void parse_line(struct ClientSocket *client, char *line);
38 static void register_irc_function(char *command, irc_cmd_t *func);
39 static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc);
40
41 int parse_lines(struct ClientSocket *client, char *lines, int len) {
42     int i, used = 0;
43     char *line = lines;
44     for(i = 0; i < len; i++) {
45         if(lines[i] == '\r') //just zero it out :D
46             lines[i] = 0;
47         if(lines[i] == '\n') {
48             lines[i] = 0;
49             parse_line(client, line);
50             line = lines+(i+1);
51             used = i+1;
52         }
53     }
54     return used;
55 }
56
57 static void parse_line(struct ClientSocket *client, char *line) {
58     int argc = 0;
59     char *argv[MAXNUMPARAMS];
60     #ifdef HAVE_THREADS
61     printf("[%lu recv %lu] %s\n", syscall(SYS_gettid), (unsigned long) strlen(line), line);
62     #else
63     printf("[recv %lu] %s\n", (unsigned long) strlen(line), line);
64     #endif
65     if(line[0] == ':')
66         line++;
67     else
68         argv[argc++] = NULL;
69     while(*line) {
70         //skip leading spaces
71         while (*line == ' ')
72             *line++ = 0;
73         if (*line == ':') {
74            //the rest is a single parameter
75            argv[argc++] = line + 1;
76            break;
77         }
78         argv[argc++] = line;
79         if (argc >= MAXNUMPARAMS)
80             break;
81         while (*line != ' ' && *line)
82             line++;
83     }
84     if(argc >= 2) {
85         parse_raw(client, argv[0], argv[1], argv+2, argc-2);
86     }
87 }
88
89 static void register_irc_function(char *command, irc_cmd_t *func) {
90     struct irc_cmd *irc_cmd = malloc(sizeof(*irc_cmd));
91     if (!irc_cmd)
92     {
93         perror("malloc() failed");
94         return;
95     }
96     irc_cmd->cmd = command;
97     irc_cmd->func = func;
98     irc_cmd->next = irc_commands;
99     irc_commands = irc_cmd;
100 }
101
102 static void parse_raw(struct ClientSocket *client, char *from, char *cmd, char **argv, int argc) {
103     struct irc_cmd *irc_cmd;
104     int ret = 0;
105     for(irc_cmd = irc_commands; irc_cmd; irc_cmd = irc_cmd->next) {
106         if(!stricmp(irc_cmd->cmd, cmd)) {
107             ret = irc_cmd->func(client, from, argv, argc);
108             break;
109         }
110     }
111     if(!irc_cmd) {
112         event_raw(client, from, cmd, argv, argc);
113     } else if(!ret) {
114         fprintf(stderr,"PARSE ERROR: %s\n", cmd);
115     }
116 }
117
118 static USERLIST_CALLBACK(got_channel_userlist) {
119     struct ChanUser *chanuser = data;
120     event_join(chanuser);
121 }
122
123 static IRC_CMD(raw_002) { //fixed: ZNC fakes a 001 raw even if we're not connected!
124     struct UserNode *user = getUserByNick(argv[0]);
125     if(!user)
126         user = addUser(argv[0]);
127     client->user = user;
128     client->user->flags |= USERFLAG_ISBOT;
129     client->flags |= SOCKET_FLAG_READY;
130     event_bot_ready(client);
131     return 1;
132 }
133
134 static int is_firstBotSeeUser(struct ClientSocket *client, struct UserNode *user) {
135     struct ClientSocket *bot, *pref_bot = NULL, *unpref_bot = NULL;
136     struct ChanUser *chanuser;
137     int found;
138     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
139         found = 0;
140         for(chanuser = getUserChannels(bot->user, NULL); chanuser; chanuser = getUserChannels(bot->user, chanuser)) {
141             if(isUserOnChan(user, chanuser->chan)) {
142                 found = 1;
143                 break;
144             }
145         }
146         if(!found) continue;
147         if(bot->flags & SOCKET_FLAG_PREFERRED) {
148             pref_bot = bot;
149             break;
150         } else
151             unpref_bot = bot;
152     }
153     bot = (pref_bot ? pref_bot : unpref_bot);
154     if(client == bot)
155         return 1;
156     else
157         return 0;
158 }
159
160 static int is_onlyBotSeeUser(struct ClientSocket *client, struct UserNode *user) {
161     struct ClientSocket *bot;
162     struct ChanUser *chanuser;
163     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
164         if(bot == client) continue;
165         for(chanuser = getUserChannels(bot->user, NULL); chanuser; chanuser = getUserChannels(bot->user, chanuser)) {
166             if(isUserOnChan(user, chanuser->chan)) {
167                 return 0;
168             }
169         }
170     }
171     return 1;
172 }
173
174 static IRC_CMD(raw_join) {
175     if(from == NULL || argc < 1) return 0;
176     struct UserNode *user = getUserByMask(from);
177     struct ChanNode *chan = getChanByName(argv[0]);
178     if(!chan && (!user || !(user->flags & USERFLAG_ISBOT))) return 0;
179     if(chan && (((!user || !isBot(user)) && chan->chanbot != client->user) || ((user && isBot(user)) && client->user != user))) return 1; //we ignore it - but it's not a parse error
180     //let Bots always add themselves! (maybe they join invisible)
181     if(user == NULL) {
182         user = addUserMask(from);
183     }
184     struct UserNode *registering, *last_registering = NULL, *next_registering;
185     int noEvent = 0, wasRegistering = 0;
186     for(registering = registering_users; registering; registering = next_registering) {
187         next_registering = registering->next;
188         if(!strcmp(registering->nick, user->nick)) {
189             noEvent = event_registered(registering, user);
190             wasRegistering = 1;
191             if(last_registering)
192                 last_registering->next = registering->next;
193             else
194                 registering_users = registering->next;
195             delUser(registering, 1);
196         } else if(time(0) - registering->created > 2) {
197             if(last_registering)
198                 last_registering->next = registering->next;
199             else
200                 registering_users = registering->next;
201             delUser(registering, 1);
202         } else
203             last_registering = registering;
204     }
205     if(chan == NULL) {
206         chan = addChannel(argv[0]);
207         //request member list
208         chan->chanbot = user;
209         struct ChanUser *chanuser = addChanUser(chan, user); //it must be a bot
210         get_userlist_with_invisible(chan, got_channel_userlist, chanuser);
211         putsock(client, "MODE %s", chan->name);
212         putsock(client, "MODE %s +b", chan->name);
213     } else if(!isUserOnChan(user, chan) && ((chan->flags & CHANFLAG_RECEIVED_USERLIST) || isBot(user))) {
214         struct ChanUser *chanuser = addChanUser(chan, user);
215         if(isModeSet(chan->modes, 'D'))
216             chanuser->flags |= CHANUSERFLAG_INVISIBLE;
217         if(!noEvent) {
218             if(wasRegistering)
219                 user->flags |= USERFLAG_WAS_REGISTRING;
220             event_join(chanuser);
221             if(wasRegistering)
222                 user->flags &= ~USERFLAG_WAS_REGISTRING;
223         }
224         if(!(user->flags & USERFLAG_ISBOT) && (chan->flags & CHANFLAG_REJOINING)) {
225             //ABORT REJOIN (security break)
226             struct ClientSocket **clients = chan->rejoin_array;
227             while(*clients) {
228                 putsock(*clients, "JOIN %s", chan->name);
229                 clients++;
230             }
231             free(chan->rejoin_array);
232             chan->flags &= ~CHANFLAG_REJOINING;
233         }
234     } else if(chan->usercount == 1 && isUserOnChan(user, chan)) {
235         //first bot rejoined
236         struct ChanUser *chanuser = getChanUser(user, chan);
237         chanuser->flags &= ~CHANUSERFLAG_VOICED;
238         chanuser->flags |= CHANUSERFLAG_OPPED;
239     }
240     return 1;
241 }
242
243 static void check_full_rejoin(struct ChanNode *chan) {
244     struct ChanUser *chanuser;
245     char do_rejoin = 1;
246     int botcount = 0;
247     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
248         if((chanuser->flags & CHANUSERFLAG_OPPED) || !(chanuser->user->flags & USERFLAG_ISBOT)) {
249             do_rejoin = 0;
250             break;
251         }
252         if((chanuser->user->flags & USERFLAG_ISBOT))
253             botcount++;
254     }
255     if(do_rejoin) {
256         struct ClientSocket **clients = calloc(botcount, sizeof(*clients));
257         struct ClientSocket *bot, *chanbot;
258         int i = 0;
259         for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
260             if(bot->user != chan->chanbot && isUserOnChan(bot->user, chan)) {
261                 clients[i++] = bot;
262                 putsock(bot, "PART %s :rejoining", chan->name);
263             } else if(bot->user == chan->chanbot)
264                 chanbot = bot;
265         }
266         chan->flags |= CHANFLAG_REJOINING;
267         chan->rejoin_array = clients;
268         if(botcount == 1) {
269             //we're alone
270             putsock(chanbot, "PART %s :magic hop", chan->name);
271             putsock(chanbot, "JOIN %s", chan->name);
272         }
273     }
274 }
275
276 static IRC_CMD(raw_part) {
277     if(from == NULL || argc < 1) return 0;
278     struct UserNode *user = getUserByMask(from);
279     if(user == NULL) return 0;
280     struct ChanNode *chan = getChanByName(argv[0]);
281     if(chan == NULL) return 0;
282     if((!isBot(user) && chan->chanbot != client->user) || (isBot(user) && client->user != user)) return 1; //we ignore it - but it's not a parse error
283     int keep_channel = 1;
284     if(chan->chanbot == user && (chan->flags & CHANFLAG_REJOINING)) {
285         struct ClientSocket **clients = chan->rejoin_array;
286         while(*clients) {
287             putsock(*clients, "JOIN %s", chan->name);
288             clients++;
289         }
290         free(chan->rejoin_array);
291         chan->flags &= ~CHANFLAG_REJOINING;
292         return 0;
293     } else if(isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
294         struct ChanUser *chanuser = getChanUser(user, chan);
295         delChanUser(chanuser, 0); //we need to free the chanuser manually!
296         event_part(chanuser, (argc > 1 ? argv[1] : NULL));
297         freeChanUser(chanuser);
298         if(chan->chanbot == user) {
299             //check if theres another bot in the channel - otherwise free it
300             keep_channel = checkChannelVisibility(chan);
301         }
302     }
303     if(user->channel == NULL && !(user->flags & USERFLAG_ISBOT)) {
304         //remove the user
305         delUser(user, 1);
306     }
307     if(keep_channel && (chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chan->flags & CHANFLAG_REJOINING)) {
308         check_full_rejoin(chan);
309     }
310     else if(keep_channel && (chan->flags & CHANFLAG_REJOINING) && chan->usercount == 1) {
311         //bot is alone... rejoin!
312         putsock(client, "PART %s :magic hop", chan->name);
313         putsock(client, "JOIN %s", chan->name);
314     }
315     return 1;
316 }
317
318 static IRC_CMD(raw_quit) {
319     if(from == NULL || argc < 1) return 0;
320     struct UserNode *user = getUserByMask(from);
321     if(user == NULL) return 0;
322     if(!is_firstBotSeeUser(client, user)) return 1; //we ignore it - but it's not a parse error
323     int registering = !stricmp(argv[0], "Registered");
324     if((registering && (user->flags & USERFLAG_ISBOT))) return 1; //bot is registering - just ignore it
325     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
326     event_quit(user, argv[0]);
327     if(user->flags & USERFLAG_ISBOT) {
328         //check if there are other bots in the users channel - otherwise free them
329         struct ChanUser *chanuser, *next;
330         for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
331             next = getUserChannels(user, chanuser);
332             if(chanuser->chan->chanbot == user)
333                 checkChannelVisibility(chanuser->chan);
334         }
335         //search the user representing the bot in the world of IRC
336         struct ClientSocket *bot;
337         for(bot = getBots(0, NULL); bot; bot = getBots(0, bot)) {
338             if(bot->user == user) {
339                 bot->flags &= ~SOCKET_FLAG_READY;
340                 bot->user = NULL;
341                 break;
342             }
343         }
344     } else if(!registering) {
345         struct ChanUser *chanuser;
346         struct ChanNode *chan;
347         for(chanuser = user->channel; chanuser; chanuser = chanuser->next_chan) {
348             chan = chanuser->chan;
349             if((chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chan->flags & CHANFLAG_REJOINING))
350                 check_full_rejoin(chan);
351         }
352     }
353     if(registering && !(user->flags & USERFLAG_ISBOT)) {
354         user->next = registering_users;
355         user->created = time(0);
356         registering_users = user;
357     } else
358         delUser(user, 1); //now we fully free the user
359     return 1;
360 }
361
362 void bot_disconnect(struct ClientSocket *client) {
363     struct UserNode *user = client->user;
364     struct ChanUser *chanuser, *next;
365     if(user) {
366         if(is_onlyBotSeeUser(client, user)) {
367             //ok  the bot-user is not seen by any other bots so we can simply free it.
368             delUser(user, 0);
369             event_quit(user, "disconnected");
370             for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
371                 next = getUserChannels(user, chanuser);
372                 if(chanuser->chan->chanbot == user)
373                     checkChannelVisibility(chanuser->chan);
374                 freeChanUser(chanuser);
375             }
376             user->channel = NULL;
377             delUser(user, 1); //now we fully free the user
378         } else {
379             //we need to transform the bot-user back to a normal user (BNC FIX)
380             user->flags &= ~USERFLAG_ISBOT;
381             for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
382                 next = getUserChannels(user, chanuser);
383                 if(chanuser->chan->chanbot == user)
384                     checkChannelVisibility(chanuser->chan);
385             }
386         }
387         client->user = NULL;
388         client->flags &= ~SOCKET_FLAG_READY;
389     }
390 }
391
392 static IRC_CMD(raw_kick) {
393     if(from == NULL || argc < 3) return 0;
394     struct UserNode *user = getUserByMask(from);
395     struct UserNode *target = getUserByNick(argv[1]);
396     struct ChanNode *chan = getChanByName(argv[0]);
397     if(chan == NULL || target == NULL) return 0;
398     if(((!isBot(target) && chan->chanbot != client->user) || (isBot(target) && client->user != target))) return 1; //we ignore it - but it's not a parse error
399     int keep_channel = 1;
400     if(isUserOnChan(target, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
401         if(user == NULL) {
402             user = createTempUserMask(from);
403                         if(!user) return 0;
404             user->flags |= USERFLAG_ISTMPUSER;
405         }
406         struct ChanUser *chanuser = getChanUser(target, chan);
407         delChanUser(chanuser, 0); //we need to free the chanuser manually!
408         event_kick(user, chanuser, argv[1]);
409         if(chanuser->chan->chanbot == user) {
410             //check if theres another bot in the channel - otherwise free it
411             keep_channel = checkChannelVisibility(chan);
412         }
413         freeChanUser(chanuser);
414     }
415     if(target->channel == NULL && !(target->flags & USERFLAG_ISBOT)) {
416         //remove the user
417         delUser(target, 1);
418     }
419     if(keep_channel && (chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chan->flags & CHANFLAG_REJOINING)) {
420         check_full_rejoin(chan);
421     }
422     return 1;
423 }
424
425 static IRC_CMD(raw_topic) {
426     if(from == NULL || argc < 2) return 0;
427     struct UserNode *user = getUserByMask(from);
428     struct ChanNode *chan = getChanByName(argv[0]);
429     if(chan == NULL) return 0;
430     if(chan->chanbot != client->user) return 1; //just ignore it to prevent event duplicates
431     if(user == NULL) {
432         user = createTempUserMask(from);
433                 if(!user) return 0;
434         user->flags |= USERFLAG_ISTMPUSER;
435     }
436     event_topic(user, chan, argv[1]);
437     strcpy(chan->topic, argv[1]);
438     return 1;
439 }
440
441 static IRC_CMD(raw_privmsg) {
442     if(from == NULL || argc < 2) return 0;
443     struct UserNode *user = getUserByMask(from);
444     if(user == NULL) {
445         user = createTempUserMask(from);
446                 if(!user) return 0;
447         user->flags |= USERFLAG_ISTMPUSER;
448     }
449     if(!stricmp(user->nick, "*status") && !match("Disconnected from IRC.*", argv[1])) {
450         //ZNC DISCONNECT
451         bot_disconnect(client);
452         return 1;
453     }
454     if(!stricmp(user->nick, "-sBNC") && !match("* disconnected from the server.", argv[1])) {
455         //sBNC DISCONNECT
456         bot_disconnect(client);
457         return 1;
458     }
459     if(argv[0][0] == '#') { //Channel message
460         struct ChanNode *chan = getChanByName(argv[0]);
461         if(chan && chan->chanbot == client->user) {
462             if(statistics_enabled)
463                 statistics_privmsg++;
464             if(argv[1][0] == '\001') {
465                 char *cmd = &argv[1][1];
466                 char *text = strstr(cmd, " ");
467                 if(text) {
468                     *text = '\0';
469                     text++;
470                     if(strlen(text) && text[strlen(text)-1] == '\001')
471                         text[strlen(text)-1] = '\0';
472                 } else if(strlen(cmd) && cmd[strlen(cmd)-1] == '\001')
473                     cmd[strlen(cmd)-1] = '\0';
474                 event_chanctcp(user, chan, cmd, text);
475             } else
476                 event_chanmsg(user, chan, argv[1]);
477         }
478     } else {
479         struct UserNode *target = getUserByNick(argv[0]);
480         if(target) {
481             if(argv[1][0] == '\001') {
482                 char *cmd = &argv[1][1];
483                 char *text = strstr(cmd, " ");
484                 if(text) {
485                     *text = '\0';
486                     text++;
487                     if(strlen(text) && text[strlen(text)-1] == '\001')
488                         text[strlen(text)-1] = '\0';
489                 } else if(strlen(cmd) && cmd[strlen(cmd)-1] == '\001')
490                     cmd[strlen(cmd)-1] = '\0';
491                 event_privctcp(user, target, cmd, text);
492             } else
493                 event_privmsg(user, target, argv[1]);
494         }
495     }
496     return 1;
497 }
498
499 static IRC_CMD(raw_notice) {
500     if(from == NULL || argc < 2) return 0;
501     struct UserNode *user = getUserByMask(from);
502     if(user == NULL) {
503         user = createTempUserMask(from);
504                 if(!user) return 0;
505         user->flags |= USERFLAG_ISTMPUSER;
506     }
507     if(argv[0][0] == '#') { //Channel notice
508         struct ChanNode *chan = getChanByName(argv[0]);
509         if(chan && chan->chanbot == client->user)
510             event_channotice(user, chan, argv[1]);
511     } else {
512         struct UserNode *target = getUserByNick(argv[0]);
513         if(target)
514             event_privnotice(user, target, argv[1]);
515     }
516     return 1;
517 }
518
519 static IRC_CMD(raw_nick) {
520     if(from == NULL || argc == 0) return 0;
521     struct UserNode *user = getUserByMask(from);
522     if(user == NULL) return 0;
523     if(!is_firstBotSeeUser(client, user)) return 1; //we ignore it - but it's not a parse error
524     event_nick(user, argv[0]);
525     renameUser(user, argv[0]);
526     return 1;
527 }
528
529 static IRC_CMD(raw_ping) {
530     if(argc == 0) return 0;
531     putsock(client, "PONG :%s", argv[0]);
532     return 1;
533 }
534
535 static IRC_CMD(raw_354) {
536     recv_whohandler_354(client, argv, argc);
537     return 1;
538 }
539
540 static IRC_CMD(raw_315) {
541     recv_whohandler_315(client, argv, argc);
542     return 1;
543 }
544
545 static IRC_CMD(raw_324) { //MODE LIST
546     //Watchcat #pktest +stnzN
547     if(from == NULL || argc < 3) return 0;
548     struct ChanNode *chan = getChanByName(argv[1]);
549     if(chan == NULL) return 0;
550     parseModes(chan->modes, argv[2], argv+3, argc-3);
551     return 1;
552 }
553
554 static IRC_CMD(raw_invite) {
555     if(from == NULL || argc < 2) return 0;
556     struct UserNode *user = getUserByMask(from);
557     if(user == NULL) {
558         user = createTempUserMask(from);
559                 if(!user) return 0;
560         user->flags |= USERFLAG_ISTMPUSER;
561     }
562     event_invite(client, user, argv[1]);
563     return 1;
564 }
565
566 static IRC_CMD(raw_mode) {
567     if(from == NULL || argc < 2) return 0;
568     struct UserNode *user = getUserByMask(from);
569     if(user == NULL) {
570         user = createTempUserMask(from);
571                 if(!user) return 0;
572         user->flags |= USERFLAG_ISTMPUSER;
573     }
574     if(argv[0][0] == '#') {
575         //ChannelMode
576         struct ChanNode *chan = getChanByName(argv[0]);
577         if(!chan) return 0;
578         if(chan->chanbot != client->user) return 1;
579         parseModes(chan->modes, argv[1], argv+2, argc-2);
580         event_mode(user, chan, argv[1], argv+2, argc-2);
581     } else {
582         //UserMode
583     }
584     return 1;
585 }
586
587 static IRC_CMD(raw_367) {
588     //Watchcat #pktest pk911!*@* TestBot!~bot@pktest.user.WebGamesNet 1315863279
589     struct ChanNode *chan = getChanByName(argv[1]);
590     if(!chan) return 0;
591     struct BanNode *ban;
592     while((ban = getMatchingChannelBan(chan, argv[2]))) {
593         removeChannelBan(ban);
594     }
595     addChannelBan(chan, argv[2]);
596     return 1;
597 }
598
599 static IRC_CMD(raw_251) {
600     if(argc < 2) return 0;
601     char *total_user_str = argv[1];
602     char total_visible[20], total_invisible[20];
603     int i = 0, total_visible_pos = 0, total_invisible_pos = 0;
604     while(*total_user_str) {
605         if(*total_user_str == ' ') {
606             i++;
607         } else if(i == 2) {
608             if(total_visible_pos < 20)
609                 total_visible[total_visible_pos++] = *total_user_str;
610         } else if(i == 5) {
611             if(total_invisible_pos < 20)
612                 total_invisible[total_invisible_pos++] = *total_user_str;
613         }
614         total_user_str++;
615     }
616     total_visible[total_visible_pos] = '\0';
617     total_invisible[total_invisible_pos] = '\0';
618     statistics_network_users = atoi(total_visible) + atoi(total_invisible);
619     return 1;
620 }
621
622 static IRC_CMD(raw_254) {
623     if(argc < 3) return 0;
624     statistics_network_channels = atoi(argv[1]);
625     statistics_update();
626     return 1;
627 }
628
629 static IRC_CMD(raw_332) {
630     //Skynet #neonserv :topic
631     struct ChanNode *chan = getChanByName(argv[1]);
632     if(!chan) return 0;
633     strcpy(chan->topic, argv[2]);
634     return 1;
635 }
636
637 void init_parser() {
638     //all the raws we receive...
639     register_irc_function("002", raw_002);
640     register_irc_function("251", raw_251);
641     register_irc_function("254", raw_254);
642     register_irc_function("324", raw_324);
643     register_irc_function("332", raw_332);
644     register_irc_function("367", raw_367);
645     register_irc_function("INVITE", raw_invite);
646     register_irc_function("NOTICE", raw_notice);
647     register_irc_function("TOPIC", raw_topic);
648     register_irc_function("KICK", raw_kick);
649     register_irc_function("PART", raw_part);
650     register_irc_function("QUIT", raw_quit);
651     register_irc_function("JOIN", raw_join);
652     register_irc_function("MODE", raw_mode);
653     register_irc_function("NICK", raw_nick);
654     register_irc_function("354", raw_354);
655     register_irc_function("315", raw_315);
656     register_irc_function("PING", raw_ping);
657     register_irc_function("PRIVMSG", raw_privmsg);
658 }
659
660 void free_parser() {
661     struct irc_cmd *cmd, *next;
662     for(cmd = irc_commands; cmd; cmd = next) {
663         next = cmd->next;
664         free(cmd);
665     }
666 }
667
668 void reply(struct ClientSocket *client, struct UserNode *user, const char *text, ...) {
669     const char *reply_format = get_language_string(user, text);
670     if(reply_format == NULL)
671         reply_format = text;
672     loadUserSettings(user);
673     char formatBuf[MAXLEN];
674     sprintf(formatBuf, "%s %s :%s", ((user->flags & USERFLAG_REPLY_PRIVMSG) ? "PRIVMSG" : "NOTICE"), user->nick, reply_format);
675     va_list arg_list;
676     char sendBuf[MAXLEN];
677     int pos;
678     if (!(client->flags & SOCKET_FLAG_CONNECTED)) return;
679     sendBuf[0] = '\0';
680     va_start(arg_list, text);
681     pos = vsnprintf(sendBuf, MAXLEN - 2, formatBuf, arg_list);
682     va_end(arg_list);
683     if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
684     sendBuf[pos] = '\n';
685     sendBuf[pos+1] = '\0';
686     write_socket(client, sendBuf, pos+1);
687 }
688
689 char* merge_argv(char **argv, int start, int end) {
690     return merge_argv_char(argv, start, end, ' ');
691 }
692
693 char* merge_argv_char(char **argv, int start, int end, char seperator) {
694     int i;
695     char *p = NULL;
696     for(i = start; i < end; i++) {
697         p = argv[i];
698         while(*p) p++;
699         if(i < end-1) {
700             while(p != argv[i+1]) {
701                 *p++ = seperator;
702             }
703         } else
704             *p = seperator;
705     }
706     if(p) *p = '\0';
707     return argv[start];
708 }