X-Git-Url: http://git.pk910.de/?p=NeonServV5.git;a=blobdiff_plain;f=src%2FIRCParser.c;h=3d410a471824b392016cbd8bb08b74b8208a8480;hp=2c30d6992dfe32f89abe3fd6b944d97b3e8652c4;hb=c8e7ce1c57afaebf3996a6712c45f4c89c34ba44;hpb=e77f75ad6cda0f1856710d685895284d694ef70d diff --git a/src/IRCParser.c b/src/IRCParser.c index 2c30d69..3d410a4 100644 --- a/src/IRCParser.c +++ b/src/IRCParser.c @@ -30,7 +30,7 @@ #include "bots.h" struct irc_cmd *irc_commands = NULL; -static struct UserNode *registering_users = NULL; +//static struct UserNode *registering_users = NULL; int statistics_privmsg = 0; int statistics_network_users = 0; int statistics_network_channels = 0; @@ -132,105 +132,46 @@ static IRC_CMD(raw_002) { //fixed: ZNC fakes a 001 raw even if we're not connect 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; SYNCHRONIZE(cache_sync); struct UserNode *user = getUserByMask(from); struct ChanNode *chan = getChanByName(argv[0]); + struct ChanUser *chanuser; if(!chan && (!user || !(user->flags & USERFLAG_ISBOT))) { + //parse error if the channel is not known, yet and it's not a bot joining DESYNCHRONIZE(cache_sync); return 0; } - if(chan && (((!user || !isBot(user)) && chan->chanbot != client->user) || ((user && isBot(user)) && client->user != user))) { - DESYNCHRONIZE(cache_sync); - return 1; //we ignore it - but it's not a parse error - } - //let Bots always add themselves! (maybe they join invisible) - if(user == NULL) { + 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) { + //new channel chan = addChannel(argv[0]); - //request member list - chan->chanbot = user; - struct ChanUser *chanuser = addChanUser(chan, user); //it must be a bot + chanuser = addChanUser(chan, user); + chanuser->visCount = 1; get_userlist_with_invisible(chan, 0, got_channel_userlist, chanuser); putsock(client, "MODE %s", chan->name); putsock(client, "MODE %s +b", chan->name); - } else if(!isUserOnChan(user, chan) && ((chan->flags & CHANFLAG_RECEIVED_USERLIST) || isBot(user))) { - struct ChanUser *chanuser = addChanUser(chan, user); + } else if((user->flags & USERFLAG_WAS_REGISTERING)) { + //user rejoined after registering (should still be present in the channel) + if(!(chanuser = getChanUser(user, chan))) + chanuser = addChanUser(chan, user); + chanuser->visCount++; + + event_registered(user, from); + user->flags &= ~USERFLAG_WAS_REGISTERING; + } else if(!isUserOnChan(user, chan)) { + //join user to an existing channel + chanuser = addChanUser(chan, user); + chanuser->visCount = 1; if(isBot(user) && isModeSet(chan->modes, 'D')) //if the bot joins a channel it could also be invisible chanuser->flags |= CHANUSERFLAG_INVISIBLE; - if(!noEvent) { - if(wasRegistering) - user->flags |= USERFLAG_WAS_REGISTRING; - event_join(chanuser); - if(wasRegistering) - user->flags &= ~USERFLAG_WAS_REGISTRING; - } + + event_join(chanuser); + if(!(user->flags & USERFLAG_ISBOT) && (chan->flags & CHANFLAG_REJOINING)) { - //ABORT REJOIN (security break) + //ABORT AUTOMATIC REJOIN (security break) struct ClientSocket **clients = chan->rejoin_array; while(*clients) { putsock(*clients, "JOIN %s", chan->name); @@ -239,11 +180,12 @@ static IRC_CMD(raw_join) { free(chan->rejoin_array); chan->flags &= ~CHANFLAG_REJOINING; } - } else if(isUserOnChan(user, chan)) { //user is already in the channel? ^^ - //first bot rejoined - chan->flags &= ~CHANFLAG_RECEIVED_USERLIST; - struct ChanUser *chanuser = getChanUser(user, chan); - get_userlist_with_invisible(chan, 0, got_channel_userlist, chanuser); + } else { + //user is already in the channel + chanuser = getChanUser(user, chan); + chanuser->visCount++; + //if multiple bots see the user, it can't be invisible + chanuser->flags &= ~CHANUSERFLAG_INVISIBLE; } DESYNCHRONIZE(cache_sync); return 1; @@ -263,21 +205,26 @@ static void check_full_rejoin(struct ChanNode *chan) { } if(do_rejoin) { struct ClientSocket **clients = calloc(botcount, sizeof(*clients)); - struct ClientSocket *bot, *chanbot; + struct ClientSocket *bot, *chanbot = NULL; int i = 0; for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { - if(bot->user != chan->chanbot && isUserOnChan(bot->user, chan)) { + if(!isUserOnChan(bot->user, chan)) + continue; + if(!chanbot && ((bot->flags & SOCKET_FLAG_PREFERRED) || !getBots(SOCKET_FLAG_READY, bot))) + chanbot = bot; + else { clients[i++] = bot; putsock(bot, "PART %s :rejoining", chan->name); - } else if(bot->user == chan->chanbot) - chanbot = bot; + } } - chan->flags |= CHANFLAG_REJOINING; - chan->rejoin_array = clients; if(botcount == 1) { //we're alone + free(clients); putsock(chanbot, "PART %s :magic hop", chan->name); putsock(chanbot, "JOIN %s", chan->name); + } else { + chan->flags |= CHANFLAG_REJOINING; + chan->rejoin_array = clients; } } } @@ -286,53 +233,104 @@ static IRC_CMD(raw_part) { if(from == NULL || argc < 1) return 0; SYNCHRONIZE(cache_sync); struct UserNode *user = getUserByMask(from); - if(user == NULL) { - DESYNCHRONIZE(cache_sync); - return 0; - } struct ChanNode *chan = getChanByName(argv[0]); - if(chan == NULL) { + struct ChanUser *chanuser; + if(user == NULL || chan == NULL || !(chanuser = getChanUser(user, chan))) { DESYNCHRONIZE(cache_sync); return 0; } - if((!isBot(user) && chan->chanbot != client->user) || (isBot(user) && client->user != user)) { - DESYNCHRONIZE(cache_sync); - return 1; //we ignore it - but it's not a parse error + chanuser->visCount--; + if(chanuser->visCount == 0) { + delChanUser(chanuser, 0); //not free, yet! + event_part(chanuser, 0, (argc > 1 ? argv[1] : NULL)); + freeChanUser(chanuser); } + + //check if channel is still present int keep_channel = 1; - if(chan->chanbot == user && (chan->flags & CHANFLAG_REJOINING)) { - struct ClientSocket **clients = chan->rejoin_array; - while(*clients) { - putsock(*clients, "JOIN %s", chan->name); - clients++; + if(chan->usercount == 0) { + if((chan->flags & CHANFLAG_REJOINING)) { + struct ClientSocket **clients = chan->rejoin_array; + while(*clients) { + putsock(*clients, "JOIN %s", chan->name); + clients++; + } + free(chan->rejoin_array); + chan->flags &= ~CHANFLAG_REJOINING; } - free(chan->rejoin_array); - chan->flags &= ~CHANFLAG_REJOINING; + delChannel(chan, 1); + keep_channel = 0; + } else if(isBot(user)) //bot parted - check if theres another bot in the channel + keep_channel = checkChannelVisibility(chan); + + // free user if he/she is in no other channel + if(user->channel == NULL && !(user->flags & USERFLAG_ISBOT)) + delUser(user, 1); + + if(keep_channel && (chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chan->flags & CHANFLAG_REJOINING)) + check_full_rejoin(chan); + else if(keep_channel && (chan->flags & CHANFLAG_REJOINING) && chan->usercount == 1) { + //bot is alone... rejoin! + struct ClientSocket *bot; + //find the last bot in the channel + for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { + if(isUserOnChan(bot->user, chan)) { + putsock(bot, "PART %s :magic hop", chan->name); + putsock(bot, "JOIN %s", chan->name); + } + } + } + DESYNCHRONIZE(cache_sync); + return 1; +} + +static IRC_CMD(raw_kick) { + if(from == NULL || argc < 3) return 0; + SYNCHRONIZE(cache_sync); + struct UserNode *user = getUserByMask(from); + struct UserNode *target = getUserByNick(argv[1]); + struct ChanNode *chan = getChanByName(argv[0]); + struct ChanUser *chanuser; + if(chan == NULL || target == NULL || !(chanuser = getChanUser(target, chan))) { DESYNCHRONIZE(cache_sync); return 0; - } else 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)); - freeChanUser(chanuser); - if(chan->chanbot == user) { - //check if theres another bot in the channel - otherwise free it - keep_channel = checkChannelVisibility(chan); - } } - if(user->channel == NULL && !(user->flags & USERFLAG_ISBOT)) { - //remove the user - delUser(user, 1); + chanuser->visCount--; + if(chanuser->visCount == 0) { + delChanUser(chanuser, 0); //not free, yet! + event_kick(user, chanuser, argv[2]); + freeChanUser(chanuser); } - if(keep_channel && (chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chan->flags & CHANFLAG_REJOINING)) { + + //check if channel is still present + int keep_channel = 1; + if(chan->usercount == 0) { + if((chan->flags & CHANFLAG_REJOINING)) { + struct ClientSocket **clients = chan->rejoin_array; + while(*clients) { + putsock(*clients, "JOIN %s", chan->name); + clients++; + } + free(chan->rejoin_array); + chan->flags &= ~CHANFLAG_REJOINING; + } + delChannel(chan, 1); + keep_channel = 0; + } else if(isBot(target)) //bot parted - check if theres another bot in the channel + keep_channel = checkChannelVisibility(chan); + + // free user if he/she is in no other channel + if(target->channel == NULL && !(target->flags & USERFLAG_ISBOT)) + delUser(target, 1); + + if(keep_channel && (chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chan->flags & CHANFLAG_REJOINING)) check_full_rejoin(chan); - } else if(keep_channel && (chan->flags & CHANFLAG_REJOINING) && chan->usercount == 1) { //bot is alone... rejoin! struct ClientSocket *bot; //find the last bot in the channel for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { - if(bot->user == chan->chanbot) { + if(isUserOnChan(bot->user, chan)) { putsock(bot, "PART %s :magic hop", chan->name); putsock(bot, "JOIN %s", chan->name); } @@ -350,125 +348,82 @@ static IRC_CMD(raw_quit) { DESYNCHRONIZE(cache_sync); return 0; } - if(!is_firstBotSeeUser(client, user)) { + + if(client->user == user) { DESYNCHRONIZE(cache_sync); - return 1; //we ignore it - but it's not a parse error + return 0; } - int registering = !stricmp(argv[0], "Registered"); - if((registering && (user->flags & USERFLAG_ISBOT))) { - DESYNCHRONIZE(cache_sync); - 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) { - //check if there are other bots in the users channel - otherwise free them - struct ChanUser *chanuser, *next; - for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next) { - next = getUserChannels(user, chanuser); - 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->flags &= ~SOCKET_FLAG_READY; - bot->user = NULL; - break; - } - } - } else if(!registering) { - struct ChanUser *chanuser; - struct ChanNode *chan; - for(chanuser = user->channel; chanuser; chanuser = chanuser->next_chan) { - chan = chanuser->chan; - if((chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chan->flags & CHANFLAG_REJOINING)) - check_full_rejoin(chan); + + //check if user is just registering + if(!stricmp(argv[0], "Registered")) + user->flags |= USERFLAG_WAS_REGISTERING; + + //decrease visCount counter + struct ChanUser *chanuser, *next_chanuser; + for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next_chanuser) { + next_chanuser = getUserChannels(user, chanuser); + chanuser->visCount--; + if(chanuser->visCount == 0) { + delChanUser(chanuser, 0); //not free, yet! + event_part(chanuser, 1, argv[0]); + if((chanuser->chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chanuser->chan->flags & CHANFLAG_REJOINING)) + check_full_rejoin(chanuser->chan); + freeChanUser(chanuser); + } + } + + if(user->channel == NULL) { + if(isBot(user)) { + //ASSERT + return 0; } + if((user->flags & USERFLAG_WAS_REGISTERING)) { + //TODO: set a timeout or sth like that? + } else + delUser(user, 1); } - 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 + DESYNCHRONIZE(cache_sync); return 1; } void bot_disconnect(struct ClientSocket *client) { struct UserNode *user = client->user; - struct ChanUser *chanuser, *next; 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); + //just remove the bot mark from the user and handle a normal quit :) + user->flags &= ~USERFLAG_ISBOT; + client->user = NULL; + client->flags &= ~SOCKET_FLAG_READY; + + //decrease visCount counter + struct ChanUser *chanuser, *next_chanuser; + for(chanuser = getUserChannels(user, NULL); chanuser; chanuser = next_chanuser) { + next_chanuser = getUserChannels(user, chanuser); + chanuser->visCount--; + if(chanuser->visCount == 0) { + delChanUser(chanuser, 0); //not free, yet! + event_part(chanuser, 1, "QUIT"); + if((chanuser->chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chanuser->chan->flags & CHANFLAG_REJOINING)) + check_full_rejoin(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; - client->flags &= ~SOCKET_FLAG_READY; + + if(user->channel == NULL) + delUser(user, 1); } } -static IRC_CMD(raw_kick) { - if(from == NULL || argc < 3) return 0; - SYNCHRONIZE(cache_sync); - struct UserNode *user = getUserByMask(from); - struct UserNode *target = getUserByNick(argv[1]); - struct ChanNode *chan = getChanByName(argv[0]); - if(chan == NULL || target == NULL) { - DESYNCHRONIZE(cache_sync); - return 0; - } - if(((!isBot(target) && chan->chanbot != client->user) || (isBot(target) && client->user != target))) { - DESYNCHRONIZE(cache_sync); - return 1; //we ignore it - but it's not a parse error - } - int keep_channel = 1; - if(isUserOnChan(target, chan) && (chan->flags & CHANFLAG_RECEIVED_USERLIST)) { - if(user == NULL) { - user = createTempUserMask(from); - if(!user) { - DESYNCHRONIZE(cache_sync); - return 0; - } - user->flags |= USERFLAG_ISTMPUSER; - } - struct ChanUser *chanuser = getChanUser(target, chan); - delChanUser(chanuser, 0); //we need to free the chanuser manually! - event_kick(user, chanuser, argv[1]); - if(chanuser->chan->chanbot == user) { - //check if theres another bot in the channel - otherwise free it - keep_channel = checkChannelVisibility(chan); - } - freeChanUser(chanuser); - } - if(target->channel == NULL && !(target->flags & USERFLAG_ISBOT)) { - //remove the user - delUser(target, 1); - } - if(keep_channel && (chan->flags & CHANFLAG_RECEIVED_USERLIST) && !(chan->flags & CHANFLAG_REJOINING)) { - check_full_rejoin(chan); +static struct ClientSocket *get_first_prefered_bot_in_channel(struct ChanNode *chan) { + struct ClientSocket *bot, *chanbot = NULL; + for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) { + if(!isUserOnChan(bot->user, chan)) + continue; + if(bot->flags & SOCKET_FLAG_PREFERRED) + return bot; + chanbot = bot; } - DESYNCHRONIZE(cache_sync); - return 1; + return chanbot; } static IRC_CMD(raw_topic) { @@ -480,7 +435,7 @@ static IRC_CMD(raw_topic) { DESYNCHRONIZE(cache_sync); return 0; } - if(chan->chanbot != client->user) { + if(client != get_first_prefered_bot_in_channel(chan)) { DESYNCHRONIZE(cache_sync); return 1; //just ignore it to prevent event duplicates } @@ -500,24 +455,6 @@ static IRC_CMD(raw_topic) { static IRC_CMD(raw_privmsg) { if(from == NULL || argc < 2) return 0; - if(!stricmplen(from, "*status", 7) || !stricmplen(from, "-sBNC", 5)) { - #ifdef HAVE_THREADS - unsigned int tid = (unsigned int) pthread_self_tid(); - while(!clientsocket_parseorder_top(tid)) { - usleep(1000); //1ms - } - #endif - if(!match("Disconnected from IRC.*", argv[1])) { - //ZNC DISCONNECT - bot_disconnect(client); - return 1; - } - if(!match("* disconnected from the server.", argv[1])) { - //sBNC DISCONNECT - bot_disconnect(client); - return 1; - } - } struct UserNode *user = getUserByMask(from); if(user == NULL) { user = createTempUserMask(from); @@ -526,7 +463,7 @@ static IRC_CMD(raw_privmsg) { } if(argv[0][0] == '#') { //Channel message struct ChanNode *chan = getChanByName(argv[0]); - if(chan && chan->chanbot == client->user) { + if(chan && client == get_first_prefered_bot_in_channel(chan)) { if(statistics_enabled) statistics_privmsg++; if(argv[1][0] == '\001') { @@ -574,7 +511,7 @@ static IRC_CMD(raw_notice) { } if(argv[0][0] == '#') { //Channel notice struct ChanNode *chan = getChanByName(argv[0]); - if(chan && chan->chanbot == client->user) + if(chan && client == get_first_prefered_bot_in_channel(chan)) event_channotice(user, chan, argv[1]); } else { struct UserNode *target = getUserByNick(argv[0]); @@ -592,7 +529,7 @@ static IRC_CMD(raw_nick) { struct UserNode *user = getUserByMask(from); if(user == NULL) { DESYNCHRONIZE(cache_sync); - return 0; + return 1; //maybe already renamed - no parse error } if(isBot(user)) { if(client->user != user) { @@ -601,9 +538,9 @@ static IRC_CMD(raw_nick) { } client_renamed(client); } - else if(!is_firstBotSeeUser(client, user)) { + else if(!strcmp(user->nick, argv[0])) { DESYNCHRONIZE(cache_sync); - return 1; //we ignore it - but it's not a parse error + return 1; //user has already this nick (case sensitive) } event_nick(user, argv[0]); renameUser(user, argv[0]); @@ -667,7 +604,7 @@ static IRC_CMD(raw_mode) { DESYNCHRONIZE(cache_sync); return 0; } - if(chan->chanbot != client->user) { + if(client != get_first_prefered_bot_in_channel(chan)) { DESYNCHRONIZE(cache_sync); return 1; }