-/* IRCParser.c - NeonServ v5.1
+/* IRCParser.c - NeonServ v5.2
* Copyright (C) 2011 Philipp Kreil (pk910)
*
* This program is free software: you can redistribute it and/or modify
#include "ModeNode.h"
struct irc_cmd *irc_commands = NULL;
+static struct UserNode *registering_users = NULL;
+int statistics_privmsg = 0;
+int statistics_network_users = 0;
+int statistics_network_channels = 0;
static void parse_line(struct ClientSocket *client, char *line);
static void register_irc_function(char *command, irc_cmd_t *func);
}
static IRC_CMD(raw_001) {
+ struct UserNode *user = getUserByNick(argv[0]);
+ if(!user)
+ user = addUser(argv[0]);
+ client->user = user;
+ client->user->flags |= USERFLAG_ISBOT;
client->flags |= SOCKET_FLAG_READY;
event_bot_ready(client);
return 1;
}
+static int is_firstBotSeeUser(struct ClientSocket *client, struct UserNode *user) {
+ struct ClientSocket *bot, *pref_bot = NULL, *unpref_bot = NULL;
+ struct ChanUser *chanuser;
+ int found;
+ for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+ found = 0;
+ for(chanuser = getUserChannels(bot->user, NULL); chanuser; chanuser = getUserChannels(bot->user, chanuser)) {
+ if(isUserOnChan(user, chanuser->chan)) {
+ found = 1;
+ break;
+ }
+ }
+ if(!found) continue;
+ if(bot->flags & SOCKET_FLAG_PREFERRED) {
+ pref_bot = bot;
+ break;
+ } else
+ unpref_bot = bot;
+ }
+ bot = (pref_bot ? pref_bot : unpref_bot);
+ if(client == bot)
+ return 1;
+ else
+ return 0;
+}
+
+static int is_onlyBotSeeUser(struct ClientSocket *client, struct UserNode *user) {
+ struct ClientSocket *bot;
+ struct ChanUser *chanuser;
+ for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+ if(bot == client) continue;
+ for(chanuser = getUserChannels(bot->user, NULL); chanuser; chanuser = getUserChannels(bot->user, chanuser)) {
+ if(isUserOnChan(user, chanuser->chan)) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
static IRC_CMD(raw_join) {
if(from == NULL || argc < 1) return 0;
struct UserNode *user = getUserByMask(from);
struct ChanNode *chan = getChanByName(argv[0]);
if(!chan && !(user->flags & USERFLAG_ISBOT)) return 0;
+ if(chan && chan->chanbot != client->user) return 1; //we ignore it - but it's not a parse error
if(user == NULL) {
user = addUserMask(from);
}
+ struct UserNode *registering, *last_registering = NULL, *next_registering;
+ int noEvent = 0, wasRegistering = 0;
+ for(registering = registering_users; registering; registering = next_registering) {
+ next_registering = registering->next;
+ if(!strcmp(registering->nick, user->nick)) {
+ noEvent = event_registered(registering, user);
+ wasRegistering = 1;
+ if(last_registering)
+ last_registering->next = registering->next;
+ else
+ registering_users = registering->next;
+ delUser(registering, 1);
+ } else if(time(0) - registering->created > 2) {
+ if(last_registering)
+ last_registering->next = registering->next;
+ else
+ registering_users = registering->next;
+ delUser(registering, 1);
+ } else
+ last_registering = registering;
+ }
if(chan == NULL) {
chan = addChannel(argv[0]);
//request member list
putsock(client, "MODE %s +b", chan->name);
} else if(!isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
struct ChanUser *chanuser = addChanUser(chan, user);
- event_join(chanuser);
+ if(!noEvent) {
+ if(wasRegistering)
+ user->flags |= USERFLAG_WAS_REGISTRING;
+ event_join(chanuser);
+ if(wasRegistering)
+ user->flags &= ~USERFLAG_WAS_REGISTRING;
+ }
}
return 1;
}
if(user == NULL) return 0;
struct ChanNode *chan = getChanByName(argv[0]);
if(chan == NULL) return 0;
+ if(chan->chanbot != client->user) return 1; //we ignore it - but it's not a parse error
if(isUserOnChan(user, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
struct ChanUser *chanuser = getChanUser(user, chan);
delChanUser(chanuser, 0); //we need to free the chanuser manually!
event_part(chanuser, (argc > 1 ? argv[1] : NULL));
- free(chanuser);
+ freeChanUser(chanuser);
if(chan->chanbot == user) {
//check if theres another bot in the channel - otherwise free it
checkChannelVisibility(chan);
if(from == NULL || argc < 1) return 0;
struct UserNode *user = getUserByMask(from);
if(user == NULL) return 0;
+ if(!is_firstBotSeeUser(client, user)) return 1; //we ignore it - but it's not a parse error
+ int registering = !stricmp(argv[0], "Registered");
+ if((registering && (user->flags & USERFLAG_ISBOT))) return 1; //bot is registering - just ignore it
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
event_quit(user, argv[0]);
if(user->flags & USERFLAG_ISBOT) {
struct ChanUser *chanuser, *next;
for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
next = getUserChannels(user, chanuser);
- checkChannelVisibility(chanuser->chan);
+ if(chanuser->chan->chanbot == user)
+ checkChannelVisibility(chanuser->chan);
+ }
+ //search the user representing the bot in the world of IRC
+ struct ClientSocket *bot;
+ for(bot = getBots(0, NULL); bot; bot = getBots(0, bot)) {
+ if(bot->user == user) {
+ bot->user = NULL;
+ break;
+ }
}
}
- delUser(user, 1); //now we fully free the user
+ if(registering && !(user->flags & USERFLAG_ISBOT)) {
+ user->next = registering_users;
+ user->created = time(0);
+ registering_users = user;
+ } else
+ delUser(user, 1); //now we fully free the user
return 1;
}
void bot_disconnect(struct ClientSocket *client) {
struct UserNode *user = client->user;
struct ChanUser *chanuser, *next;
- delUser(user, 0);
- event_quit(user, "disconnected");
- for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
- next = getUserChannels(user, chanuser);
- checkChannelVisibility(chanuser->chan);
- free(chanuser);
+ if(user) {
+ if(is_onlyBotSeeUser(client, user)) {
+ //ok the bot-user is not seen by any other bots so we can simply free it.
+ delUser(user, 0);
+ event_quit(user, "disconnected");
+ for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
+ next = getUserChannels(user, chanuser);
+ if(chanuser->chan->chanbot == user)
+ checkChannelVisibility(chanuser->chan);
+ freeChanUser(chanuser);
+ }
+ user->channel = NULL;
+ delUser(user, 1); //now we fully free the user
+ } else {
+ //we need to transform the bot-user back to a normal user (BNC FIX)
+ user->flags &= ~USERFLAG_ISBOT;
+ for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) {
+ next = getUserChannels(user, chanuser);
+ if(chanuser->chan->chanbot == user)
+ checkChannelVisibility(chanuser->chan);
+ }
+ }
+ client->user = NULL;
}
- user->channel = NULL;
}
static IRC_CMD(raw_kick) {
struct UserNode *target = getUserByNick(argv[1]);
struct ChanNode *chan = getChanByName(argv[0]);
if(chan == NULL || target == NULL) return 0;
+ if(chan->chanbot != client->user) return 1; //we ignore it - but it's not a parse error
if(isUserOnChan(target, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) {
if(user == NULL) {
user = createTempUser(from);
struct ChanUser *chanuser = getChanUser(target, chan);
delChanUser(chanuser, 0); //we need to free the chanuser manually!
event_kick(user, chanuser, argv[1]);
- free(chanuser);
- if(target->flags & USERFLAG_ISBOT) {
+ if(chanuser->chan->chanbot == user) {
//check if theres another bot in the channel - otherwise free it
checkChannelVisibility(chan);
}
+ freeChanUser(chanuser);
}
if(target->channel == NULL && !(target->flags & USERFLAG_ISBOT)) {
//remove the user
if(argv[0][0] == '#') { //Channel message
struct ChanNode *chan = getChanByName(argv[0]);
if(chan && chan->chanbot == client->user) {
+ if(statistics_enabled)
+ statistics_privmsg++;
if(argv[1][0] == '\001') {
char *cmd = &argv[1][1];
char *text = strstr(cmd, " ");
if(from == NULL || argc == 0) return 0;
struct UserNode *user = getUserByMask(from);
if(user == NULL) return 0;
+ if(!is_firstBotSeeUser(client, user)) return 1; //we ignore it - but it's not a parse error
event_nick(user, argv[0]);
renameUser(user, argv[0]);
return 1;
return 1;
}
+static IRC_CMD(raw_251) {
+ if(argc < 2) return 0;
+ char *total_user_str = argv[1];
+ char total_visible[20], total_invisible[20];
+ int i, total_visible_pos = 0, total_invisible_pos = 0;
+ while(*total_user_str) {
+ if(*total_user_str == ' ') {
+ i++;
+ } else if(i == 2) {
+ if(total_visible_pos < 20)
+ total_visible[total_visible_pos++] = *total_user_str;
+ } else if(i == 5) {
+ if(total_invisible_pos < 20)
+ total_invisible[total_invisible_pos++] = *total_user_str;
+ }
+ total_user_str++;
+ }
+ total_visible[total_visible_pos] = '\0';
+ total_invisible[total_invisible_pos] = '\0';
+ statistics_network_users = atoi(total_visible) + atoi(total_invisible);
+ return 1;
+}
+
+static IRC_CMD(raw_254) {
+ if(argc < 3) return 0;
+ statistics_network_channels = atoi(argv[1]);
+ statistics_update();
+ return 1;
+}
+
+static IRC_CMD(raw_332) {
+ //Skynet #neonserv :topic
+ struct ChanNode *chan = getChanByName(argv[1]);
+ if(!chan) return 0;
+ strcpy(chan->topic, argv[2]);
+ return 1;
+}
+
void init_parser() {
//all the raws we receive...
register_irc_function("001", raw_001);
+ register_irc_function("251", raw_251);
+ register_irc_function("254", raw_254);
register_irc_function("324", raw_324);
+ register_irc_function("332", raw_332);
register_irc_function("367", raw_367);
register_irc_function("INVITE", raw_invite);
register_irc_function("NOTICE", raw_notice);