#include "DBHelper.h"
#include "BanNode.h"
#include "ModeNode.h"
+#include "tools.h"
struct irc_cmd *irc_commands = NULL;
static struct UserNode *registering_users = NULL;
event_join(chanuser);
}
-static IRC_CMD(raw_001) {
- client->user = addUser(argv[0]);
+static IRC_CMD(raw_002) { //fixed: ZNC fakes a 001 raw even if we're not connected!
+ 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 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(!chan && (!user || !(user->flags & USERFLAG_ISBOT))) return 0;
+ 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
+ //let Bots always add themselves! (maybe they join invisible)
if(user == NULL) {
user = addUserMask(from);
}
//request member list
chan->chanbot = user;
struct ChanUser *chanuser = addChanUser(chan, user); //it must be a bot
- get_userlist(chan, got_channel_userlist, chanuser);
+ get_userlist_with_invisible(chan, 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)) {
+ } else if(!isUserOnChan(user, chan) && ((chan->flags & CHANFLAG_RECEIVED_USERLIST) || isBot(user))) {
struct ChanUser *chanuser = addChanUser(chan, user);
+ if(isModeSet(chan->modes, 'D'))
+ chanuser->flags |= CHANUSERFLAG_INVISIBLE;
if(!noEvent) {
if(wasRegistering)
user->flags |= USERFLAG_WAS_REGISTRING;
if(wasRegistering)
user->flags &= ~USERFLAG_WAS_REGISTRING;
}
+ if(!(user->flags & USERFLAG_ISBOT) && (chan->flags & CHANFLAG_REJOINING)) {
+ //ABORT REJOIN (security break)
+ struct ClientSocket **clients = chan->rejoin_array;
+ while(*clients) {
+ putsock(*clients, "JOIN %s", chan->name);
+ clients++;
+ }
+ free(chan->rejoin_array);
+ chan->flags &= ~CHANFLAG_REJOINING;
+ }
+ } else if(chan->usercount == 1 && isUserOnChan(user, chan)) {
+ //first bot rejoined
+ struct ChanUser *chanuser = getChanUser(user, chan);
+ chanuser->flags &= ~CHANUSERFLAG_VOICED;
+ chanuser->flags |= CHANUSERFLAG_OPPED;
}
return 1;
}
+static void check_full_rejoin(struct ChanNode *chan) {
+ struct ChanUser *chanuser;
+ char do_rejoin = 1;
+ int botcount = 0;
+ for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+ if((chanuser->flags & CHANUSERFLAG_OPPED) || !(chanuser->user->flags & USERFLAG_ISBOT)) {
+ do_rejoin = 0;
+ break;
+ }
+ if((chanuser->user->flags & USERFLAG_ISBOT))
+ botcount++;
+ }
+ if(do_rejoin) {
+ struct ClientSocket **clients = calloc(botcount, sizeof(*clients));
+ struct ClientSocket *bot, *chanbot;
+ 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)) {
+ 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
+ putsock(chanbot, "PART %s :magic hop", chan->name);
+ putsock(chanbot, "JOIN %s", chan->name);
+ }
+ }
+}
+
static IRC_CMD(raw_part) {
if(from == NULL || argc < 1) return 0;
struct UserNode *user = getUserByMask(from);
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)) {
+ if((!isBot(user) && chan->chanbot != client->user) || (isBot(user) && client->user != user)) return 1; //we ignore it - but it's not a parse error
+ 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++;
+ }
+ free(chan->rejoin_array);
+ chan->flags &= ~CHANFLAG_REJOINING;
+ 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
- checkChannelVisibility(chan);
+ keep_channel = checkChannelVisibility(chan);
}
}
if(user->channel == NULL && !(user->flags & USERFLAG_ISBOT)) {
//remove the user
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!
+ putsock(client, "PART %s :magic hop", chan->name);
+ putsock(client, "JOIN %s", chan->name);
+ }
return 1;
}
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) {
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);
+ }
}
- if(!stricmp(argv[0], "Registered") && !(user->flags & USERFLAG_ISBOT)) {
+ if(registering && !(user->flags & USERFLAG_ISBOT)) {
user->next = registering_users;
user->created = time(0);
registering_users = user;
struct UserNode *user = client->user;
struct ChanUser *chanuser, *next;
if(user) {
- 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);
+ 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);
+ }
}
- user->channel = NULL;
- delUser(user, 1); //now we fully free the user
client->user = NULL;
}
}
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(((!isBot(target) && chan->chanbot != client->user) || (isBot(target) && client->user != target))) 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 = createTempUser(from);
struct ChanUser *chanuser = getChanUser(target, chan);
delChanUser(chanuser, 0); //we need to free the chanuser manually!
event_kick(user, chanuser, argv[1]);
- freeChanUser(chanuser);
if(chanuser->chan->chanbot == user) {
//check if theres another bot in the channel - otherwise free it
- checkChannelVisibility(chan);
+ 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);
+ }
return 1;
}
user = createTempUser(from);
user->flags |= USERFLAG_ISTMPUSER;
}
+ if(!stricmp(user->nick, "*status") && !match("Disconnected from IRC.*", argv[1])) {
+ //ZNC DISCONNECT
+ bot_disconnect(client);
+ return 1;
+ }
+ if(!stricmp(user->nick, "-sBNC") && !match("* disconnected from the server.", argv[1])) {
+ //sBNC DISCONNECT
+ bot_disconnect(client);
+ return 1;
+ }
if(argv[0][0] == '#') { //Channel message
struct ChanNode *chan = getChanByName(argv[0]);
if(chan && chan->chanbot == client->user) {
void init_parser() {
//all the raws we receive...
- register_irc_function("001", raw_001);
+ register_irc_function("002", raw_002);
register_irc_function("251", raw_251);
register_irc_function("254", raw_254);
register_irc_function("324", raw_324);